关于Integer的自动装箱与自动拆箱

关于Integer的自动装箱与自动拆箱

自动装箱

Integer x1 = 36和Integer n1 = new Integer(36)有什么区别?我们尝试运行下面代码看看会是什么结果:

public class Int {
    public static void main(String[] args) {
        Integer x1 = 36;
        Integer x2 = 36;
        boolean r1 = x1==x2;
        System.out.println("x1==x2:" + r1);

        Integer y1 = 360;
        Integer y2 = 360;
        boolean r2 = y1==y2;
        System.out.println("y1==y2:" + r2);

        Integer n1 = new Integer(36);
        Integer n2 = new Integer(36);
        boolean r3 = n1==n2;
        System.out.println("n1==n2:" + r3);

        Integer m1 = new Integer(360);
        Integer m2 = new Integer(360);
        boolean r4 = m1==m2;
        System.out.println("m1==m2:" + r4);
    }
}

运行结果:

x1==x2:true
y1==y2:false
n1==n2:false
m1==m2:false

看到运行结果是不是感觉有些奇怪,y1 == y2、n1 == n2、m1 == m2为什么结果是false?我们对代码进行反编译,反编译后代码如下:

public class Int {
    public static void main(String[] args) {
        Integer x1 = Integer.valueOf(36);
        Integer x2 = Integer.valueOf(36);
        boolean r1 = (x1 == x2);
        System.out.println("x1==x2:" + r1);
        
        Integer y1 = Integer.valueOf(360);
        Integer y2 = Integer.valueOf(360);
        boolean r2 = (y1 == y2);
        System.out.println("y1==y2:" + r2);
        
        Integer n1 = new Integer(36);
        Integer n2 = new Integer(36);
        boolean r3 = (n1 == n2);
        System.out.println("n1==n2:" + r3);
        
        Integer m1 = new Integer(360);
        Integer m2 = new Integer(360);
        boolean r4 = (m1 == m2);
        System.out.println("m1==m2:" + r4);
    }
}

从反编译结果来看,Integer x1 = 36和Integer n1 = new Integer(36)分别调用了Integer.valueOf(int i)和Integer(int value)方法。Integer.valueOf(int i)和Integer(int value)源码如下:

public Integer(int value) {
    this.value = value;
}

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

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() {}
}

Integer是int类型的包装类,当int值赋值给Integer时会使用valueOf(int i)方法自动装箱。从源码可以看出,默认情况下cache[]缓存范围是[-128,127]。对于valueOf(int i),当i在[-128,127]内,则直接返回catch中缓存的Integer对象,所以,x1,x2其实指向了同一个Integer对象。当i在[-128,127]外,则会重新new一个Integer对象并且返回,所以y1,y2其实是指向了不同的Integer对象。new Integer(36)和new Integer(360)调用Integer构造函数,得到的是不同的Integer对象。由此可见它们的不同之处是:x1、x2指向了同一个Integer对象,y1、y2、n1、n2、m1、m2各指向不同的Integer对象。对于对象引用类型:“ == ”比较的是对象的内存地址,对于基本数据类型比较的是数值。所以x1 == x2结果为true,y1 == y2、n1 == n2、m1 == m2结果为false。

在这里插入图片描述

自动拆箱

我们在运行一下下面代码:

Unpacking.java

public class Unpacking {
    public static void main(String[] args) {
        int a = 10;
        Integer b = 10;
        boolean result = a == b;
        System.out.println(result);
    }
}

运行结果:

true

我们对代码进行反编译,反编译后代码如下:

public class Unpacking {
    public static void main(String[] args) {
        int a = 10;
        Integer b = Integer.valueOf(10);
        boolean result = (a == b.intValue());
        System.out.println(result);
    }
}


/**
 * Returns the value of this {@code Integer} as an
 * {@code int}.
 */
public int intValue() {
    return value;
}

我们看到a、b在比较的时候,b调用了intValue()方法,获取了对象b的value值。这里b调用了intValue()方法进行自动拆箱,将自己的value值与a作比较,结果为true。到这里我们就应该知道,Integer的自动装箱是使用valueOf(int i)方法,自动拆箱是使用intValue()方法。

“==”比较的到底是什么?

前面提到:对于对象引用类型:“==”比较的是对象的内存地址,对于基本数据类型比较的是数值。我们可以通过字节码来证明这一点:

Int.class

//Integer x1 = 36;
//Integer x2 = 36;
//boolean r1 = x1==x2;
//System.out.println("x1==x2:" + r1);

0: bipush        36
2: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush        36
8: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: astore_2
12: aload_1
13: aload_2
14: if_acmpne     21
17: iconst_1
18: goto          22
21: iconst_0
22: istore_3

在Int类中x1、x2为引用类型。x1==x2比较使用到的是if_acmpne指令,其中a代表 reference的地址(address),是两个引用的比较,点击查看完整字节码。

Test.java

public class Test {
    public static void main(String[] args) {
        int a = 3;
        int b = 4;
        boolean result = a == b;
        System.out.println(result);
    }
}

Test.class

//int a = 3;
//int b = 4;
//boolean result = a == b;

0: iconst_3
1: istore_1
2: iconst_4
3: istore_2
4: iload_1
5: iload_2
6: if_icmpne     13
9: iconst_1
10: goto          14
13: iconst_0
14: istore_3

在Test类中x1、x2为基本数据类型。x1 == x2比较使用到的是if_icmpne指令,其中i 代表对 int,是两个数值的比较。所以,对于对象引用类型:“==”比较的是对象的内存地址,对于基本数据类型比较的是数值的结论是对的。

Integer.eqauls()方法

当我们比较两个Integer,想让它们的value相等就返回true时,我们可以使用Integer的equals方法,方法源码如下:

/**
 * Compares this object to the specified object.  The result is
 * {@code true} if and only if the argument is not
 * {@code null} and is an {@code Integer} object that
 * contains the same {@code int} value as this object.
 *
 * @param   obj   the object to compare with.
 * @return  {@code true} if the objects are the same;
 *          {@code false} otherwise.
 */
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

public int intValue() {
    return value;
}

基本数据类型缓冲池

基本数据类型缓冲池范围
boolean[true, false]
byte[-128, 127]
short[-128, 127]
int[-128, 127]
char[\u0000, \u007F]

Java虚拟机指令集《Java Virtual Machine Specification》Chapter 6. The Java Virtual Machine Instruction Set

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值