首页 > 技术文章 > Java 的自动装箱拆箱

kingfy 2016-08-02 13:18 原文

    Java 是面向对象的语言,其基本数据类型也就有了相对应的类,称为包装类。以下是基本数据类型对应的包装类:

基本数据类型

包装类

byte(1字节)

Byte

short(2字节)

Short

int(4字节)

Integer

long(8字节)

Long

float(4字节)

Float

double(8字节)

Double

char(2字节)

Character

boolean(1/8字节)

Boolean

自动装箱、拆箱:

    在 jdk1.5 以前,创建 Integer 对象需要调用其构造方法:

Integer i = new Integer(5);

    jdk1.5 具有自动装箱拆箱功能:

Integer i = 5;  //装箱
int j = i;   //拆箱

    其原理是调用了 Integer 的 valueOf(int) 和 Integer 对象的 intValue() 方法:

public static void intTest() {
        Integer integer = 2;
        int i = integer;
        System.out.println(i);
}
//反编译后
public static void intTest() {
        Integer integer = Integer.valueOf(2);
        int i = integer.intValue();
        System.out.println(i);
}

 

IntegerCache 类:

    IntegerCache 是 Integer 类中一个私有的静态类,用于整型对象的缓存。

Integer i1 = 2;
Integer i2 = 2;

System.out.println(i1 == i2); //true

    该缓存策略仅在自动装箱时适用,也就是使用 new Integer() 的方式构建的 Integer 对象!=:

Integer i1 = new Integer(2);
Integer i2 = new Integer(2);

System.out.println(i1 == i2); //false

    并且只适用于整数区间 -128 到 +127:

Integer i1 = 300;
Integer i2 = 300;

System.out.println(i1 == i2); //false

    源码里 Integer 的 valueOf(int) 方法:

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

    源码里规定了缓存的范围最小为:-128 到 +127 ,最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数 -XX:AutoBoxCacheMax=size 设置最大值。

 

其他包装类:

    Byte,Short,Long,Character 也有相应的缓存类;

    Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127;

    另外,只有 Integer 可以通过参数改变范围。

    boolean:

        Boolean b1 = false;
        Boolean b2 = false;
        Boolean b3 = true;
        Boolean b4 = true;
 
        System.out.println(b1==b2); //true
        System.out.println(b3==b4); //true

    Integer 与 Long:

        Integer a = 1;
        Integer b = 2;
        Long g = 3L;
        Long h = 2L;
 
        System.out.println(g==(a+b)); //true
        System.out.println(g.equals(a+b)); //false
        System.out.println(g.equals(a+h)); //ture

    "==" 与 equals :

        1,”==“可以用于原始值进行比较,也可以用于对象进行比较,当用于对象与对象之间比较时,比较的不是对象代表的值,而是检查两个对象是否是同一对象,这个比较过程中没有自动装箱发生。

        2,进行对象值比较不应该使用”==“,而应该使用对象对应的 equals 方法。

        3,equals 方法是 Object 类的一个方法:

     public boolean equals(Object obj) {
        return (this == obj);
     }

             许多类会重写这个方法:

             ① Integer 类重载了该方法:

     public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
     }
     Integer i1 = 300;
     Integer i2 = 300;

     System.out.println(i1 == i2); //false 两个不同的地址引用
     System.out.println(i1.equals(i2)); //true 两个相同的值(变为两个 int 之间的比较,所以比较值)

             ② String 重载了该方法:当两值不 == 时,比较他们的值

     public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

             所以,当对象没有重写 equals 时,== 与 equals 是等价的。

 

另外:

        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        
        int[] id = new int[9];

//数组下就不能这么装了... //
int[] ints = set.toArray(new Integer[0]);
Integer[] integers
= set.toArray(new Integer[0]); for(int i=0;i<=set.size()-1;i++){ id[i] = set.toArray(new Integer[0])[i]; }

 

   

推荐阅读