autoboxing and unboxing
java自动装箱与拆箱(auto boxing and unboxing)是指java编译器能够在原始类型(primitive type)以及它们的包装类之间进行自动转换。
autoboxing
自动装箱(autoboxing)发生于:
- 原始类型作为参数传入一个需要相关包装类做参数的函数。
Passed as a parameter to a method that expects an object of the corresponding wrapper class.
- 原始类型赋值给对应的包装类时
对于1情况,例子:
List<Integer> list = new ArrayList<Integer>();
list.add(1);
这是我们平常经常用到的语句,向一个List容器中添加数。其中,查看文档可以发现:
boolean add(E e)
Appends the specified element to the end of this list (optional operation).
add函数的参数是泛型E
,这里我们声明的list使用了Integer
。所以调用list.add(1)
时,1作为参数,被自动装箱,成为了Integer
。
对于2情况,例子:
Integer i = 1;
这也是我们平常常用的java语句,这里1作为primitive type被赋值给Integer,在此过程中,自动装箱为Integer。
unboxing
反过来,从包装类到原始类型就是自动拆箱(unboxing)。
与boxing相似,unboxing 发生于:
- 包装类作为参数传入一个需要相关原始类型做参数的函数。
Passed as a parameter to a method that expects a value of the corresponding primitive type.
- 原始类型赋值给对应的包装类时
Assigned to a variable of the corresponding primitive type
对于情况1,例子:
Integer a1 = 1;
Integer a2 = 2;
int sum = a1 + a2;
这里Intege类并没有定义+
的操作,所以a1 + a2
会拆箱成int
进行相加。
对于情况2,例子:
Integer i1 = 1;
int i2 = i1;
i1在赋值给i2时,自动拆箱成为int
。
autoboxing and equality
经验中,我们知道
int x = 1;
int y = 1;
x==y
结果为true
Integer x = 1;
Integer y = 1;
x.equals(y)
结果为true
。但是x==y
结果为false
。
这是因为integer类型重写了equals
方法。
Compares this object to the specified object. The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
比较两个Integer实例的实际int值。而==
会基于引用进行判断(referential equality),由于x, y 不是指向同一个Integer对象,所以二者==
便会返回false
。
由于java的自动装箱、拆箱机制,程序在相等性判断上,可能会有令人意想不到的结果。
我们观察几个例子。
https://learning.edx.org/course/course-v1:MITx+6.005.1x+3T2016/block-v1:MITx+6.005.1x+3T2016+type@sequential+block@12-Equality/block-v1:MITx+6.005.1x+3T2016+type@vertical+block@vertical_Questions_4386c462c7bd
Map<String, Integer> a = new HashMap<>(), b = new HashMap<>();
a.put("c", 130);
b.put("c", 130);
在这个例子中,数值130
在编译时的类型为int
,而在运行时,130
被放入Map
中,此时它必须被自动装箱成为Integer
类型。
a.get("c").equals(b.get("c"))
会返回true
,注意到a.get("c")
以及b.get("c")
返回的是Integer
类型,但是使用equals
方法比较二者仍返回true
。
a.get("c") == b.get("c")
此时使用==
进行引用比较,返回为false
int i = a.get("c");
int j = b.get("c");
此时i==j
结果为true
。这里a.get("c")
和b.get("c")
返回的Integer
类型被自动拆箱成为int
类型,再使用==
比较显然会返回true
。
参考
[1] https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html
[2] http://web.mit.edu/6.031/www/sp21/classes/15-equality/#implementing_equals