基本数据类型及其包装类

主要内容:分析数值型自动拆装箱过程中的常量池问题。

1. 基本数据类型及包装类型
基本数据类型长度(单位:字节)取值范围包装类型
byte1-2^7 – 2^7-1Byte
short2-2^15 – 2^15-1Short
int4-2^31 – 2^31-1Integer
long8-2^63 – 2^63-1Long
float43.402823e+38 ~ 1.401298e-45Float
double81.797693e+308~ 4.9000000e-324Double
boolean1true/falseBoolean
char20-2^16-1Character
2.自动拆装箱

拆箱(unboxing):将包装类转换成基本数据类型的过程。
装箱(boxing):将基本数据类型装换从包装类型的过程。

//自动装箱
Integer a = 100;
//自动拆箱
int b = a;
2.1 自动拆装箱中常量池的问题

eg1(面试题):

public static void main(String[] args) {
        Integer a = 30;
        int b = a;
        Integer c = Integer.valueOf(30);
        Integer d = new Integer(30);

        System.out.println(a == b);//true
        System.out.println(a == c);//true
        System.out.println(a == d);//false
        System.out.println(b == c);//true
        System.out.println(b == d);//true

    }

对代码进行反编译(取赋值部分):

  public static void main(java.lang.String[]);
    Code:
       0: bipush        30
       2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       5: astore_1
       6: aload_1
       7: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
      10: istore_2
      11: bipush        30
      13: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      16: astore_3
      17: new           #4                  // class java/lang/Integer
      20: dup
      21: bipush        30
      23: invokespecial #5                  // Method java/lang/Integer."<init>":(I)V

小结:
装箱的过程:使用Integer.valueOf(int i)方法。
拆箱的过程:使用Integer.intValue()方法。

eg2:

Integer a = 128;
Integer b = 128;

Integer c = 127;
Integer d = 127;

System.out.println(a == b);//false
System.out.println(c == d);//true

现象:范围在[-128,127]之间的Integer对象,只要值相等,那么指向的就是同一个对象。
原因:当int类型在某一个范围([-128,127])内,就直接从常量池中取对象。

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

那么在Byte\Short\Long类型中是否同样的有常量池存在?
答案是肯定的,并且常量池的范围都一样[-128,127],详情看源码。
为什么Float和Double没有常量池?
因为即便在[-128,127]之间,取值的个数也是无限个。

3.基本数据类型和包装类之间的比较

原则1:基本数据类型和包装类型使用==比较,先对包装类型进行拆箱,再比较值。所以只要值相同,一定是true。
原则2:包装类使用equals和基本数据类型进行比较,先将基本类型,转换成包装类型,再比较。

-------------------------------------2021-12-29更新----------------------------------------

1. 为什么需要包装类?

因为基本数据类型只能用来存储值,它没有方法。比如String类型和基本数据类型之间的转换,没有包装类型就无法完成。

2. java编译器的常量优化机制
byte b1 = 3;
byte b2 = 4;
byte b3 = 3+4;//编译通过
byte b4 = 120+8;//编译失败
byte b5 = b1+2;//编译失败
byte b6 =(byte) (b1+2);//编译通过

为什么第三行通过?第四行失败?
编译器的常量优化机制:当赋值表达式的等号右边全部都是常量时,编译器会先计算右边的内容,并判断结果是否在左侧数据的取值范围内,如果在,就赋值成功,否则赋值失败,编译报错。
为什么第五行不通过?
当等号右侧包含变量时,常量优化机制不起作用。这个时候,等号右侧的结果是int类型,不能直接赋值给byte类型。加个强转就可以。

3. byte、short、char类型在运算时自动转换为int
byte b1 = 3;
byte b2 = 4;
byte b7 = b1+b2;//编译失败

为什么编译失败?
有一种说法是:因为两个byte类型相加,结果可能超出byte类型的取值范围,所以编译器就报错了。这种说法是不对的,按照这种理论,两个int类型相加就必须要Long类型接收。两个Long类型相加要用什么数据类型接收呢?
按理说,等号右边的数据类型都是byte,应该不需要转成int计算,但结果却是int类型。原因是:JVM不支持直接对byte、short、char类型的算术运算,但是支持对int类型的计算,所以这三种数据在运算之前都会先转换成int类型,再进行运算。具体内容,可以查询JVM指令集,附上JVM中实际类型与运算类型的对应关系如下表:
在这里插入图片描述

4. 包装类型和基本数据类型的比较问题

记住下面这些规则就行:
4.1 使用==比较:
左右两边表达式只要有一边是基本数据类型,全部转换成基本数据类型比较值。
如果左右两边都是包装类,比较地址。如果是new出来的,肯定保存在堆中,如果是通过Integer.valueOf()方法赋值的(注意:通过字面量赋值实际上也是使用Integer.valueOf方法,比如:Integer a = 10),就考虑常量池。
4.2 使用equals方法,肯定是比较值了,因为包装类都重写了equals方法。

5. 包装类常量池和String类型常量池的区别

包装类:常量池是固定范围的,使用之前就有内容的。Integer为例,看源码:
静态代码块中就为常连池赋值了。所以可以直接取。

private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            int h = 127;
            String integerCacheHighPropValue =
                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
            if (integerCacheHighPropValue != null) {
                try {
                    int i = parseInt(integerCacheHighPropValue);
                    i = Math.max(i, 127);
                    // Maximum array size is Integer.MAX_VALUE
                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                } catch( NumberFormatException nfe) {
                    // If the property cannot be parsed into an int, ignore it.
                }
            }
            high = h;

            cache = new Integer[(high - low) + 1];
            int j = low;
            for(int k = 0; k < cache.length; k++)
                cache[k] = new Integer(j++);

            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }

        private IntegerCache() {}
    }

String类型:常连池一开始是空的,在赋值的时候才会添加到常量池中,或者使用intern方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值