As any Java programmer knows, you can’t put an
int
(or other primitive value) into a collection. Collections can only hold object references, so you have to box primitive values into the appropriate wrapper class (which is Integer in the case of
int
). When you take the object out of the collection, you get the
Integer
that you put in; if you need an
int
, you must unbox the
Integer
using the
intValue
method. All of this boxing and unboxing is a pain, and clutters up your code. The autoboxing and unboxing feature automates the process, eliminating the pain and the clutter.
每个
Java
程序员都知道,不可能把一个
int(
或其它基本类型的值
)
放入一个
collection
中去。集合只能存放对象的引用,所以您必须把基本类型值装箱成适合的包装类
(int
对应的包装类是
integer)
。当您想从集合中取出对象时,您获取的是您放入的
Integer
;如果您需要的是一个
int
,您就必须用
intValue
方法。装箱出箱是一件很痛苦的事情,也把代码弄得乱糟糟的。自动装箱出箱特性使这一过程变得自动化,消除这种痛苦,并可以保持代码整洁。
The following example illustrates autoboxing and unboxing, along with generics and the for-each loop. In a mere ten lines of code, it computes and prints an alphabetized frequency table of the words appearing on the command line.
下面的例子演示了自动装箱和出箱,同时也用到了范型和
for-each
循环。在仅有的十行代码中,计算并按字母顺序打印出命令行中每个单词的出现频率。
import java.util.*;
// Prints a frequency table of the words on the command line
public class Frequency {
public static void main(String[] args) {
Map<String, Integer> m = new TreeMap<String, Integer>();
for (String word : args) {
Integer freq = m.get(word);
m.put(word, (freq == null ? 1 : freq + 1));
}
System.out.println(m);
}
}
java Frequency if it is to be it is up to me to do the watusi
{be=1, do=1, if=1, is=2, it=2, me=1, the=1, to=3, up=1, watusi=1}
The program first declares a map from
String
to
Integer
, associating the number of times a word occurs on the command line with the word. Then it iterates over each word on the command line. For each word, it looks up the word in the map. Then it puts a revised entry for the word into the map. The line that does this (highlighted in green) contains both autoboxing and unboxing. To compute the new value to associate with the word, first it looks at the current value (
freq
). If it is null, this is the first occurrence of the word, so it puts 1 into the map. Otherwise, it adds 1 to the number of prior occurrences and puts that value into the map. But of course you cannot put an
int
into a map, nor can you add one to an
Integer
. What is really happening is this: In order to add 1 to
freq
, it is automatically unboxed, resulting in an expression of type
int
. Since both of the alternative expressions in the conditional expression are of type
int
, so too is the conditional expression itself. In order to put this
int
value into the map, it is automatically boxed into an
Integer
.
程序首先声明一个
String
到
Integer
的
map
来关联命令行中每个单词出现在次数。然后遍历每个单词。程序在
map
中查找每个单词,然后把修改过的
entry
放入
map
中。绿色高亮显示的代码既包含自动装箱又包含自动出箱。为了计算与每个单词相关联的新值,首先程序查看当前值,如果它是
null
的话,此时是该单词第一次出现的情况,在
map
中放入
1
。否则就在前次出现的次数基础上加
1
,然后再放到
map
中去。当然,您既可能把
int
放入
map
中,也不可能把
1
加到
Integer
上去。到底发生了什么呢?为了使
freq
加
1
,程序自动进行出箱,产生一个
int
类型的表达式。因为在条件表达式两边都是
int
类型,条件表达式自身也当然是。为了能把
int
类型值放入
map
,程序自动地把它装箱成
Integer
。
The result of all this magic is that you can largely ignore the distinction between
int
and
Integer
, with a few caveats. An
Integer
expression can have a
null
value. If your program tries to autounbox null, it will throw a
NullPointerException
. The
==
operator performs reference identity comparisons on
Integer
expressions and value equality comparisons on
int
expressions. Finally, there are performance costs associated with boxing and unboxing, even if it is done automatically.
这样您就可以忽略
int
与
Integer
间的区分,只是会有一些警告。整型可包含
null
值。如果您的程序试图把一个
null
值出箱,就会抛出一个
NullPointerException
异常。对于
Integer
类型
==
操作符进行引用的比较,而对于
int
类型,进行值的比较。最后要提一下,即使装箱出箱是自动完成的,也是有很大的性能损耗的。
Here is another sample program featuring autoboxing and unboxing. It is a static factory that takes an
int
array and returns a List of
Integer
backed by the array. In a mere ten lines of code this method provides the full richness of the
List
interface atop an
int
array. All changes to the list write through to the array and vice-versa. The lines that use autoboxing or unboxing are highlighted in green:
这里还有一个用到装箱出箱的程序。接收一个
int
类型数组并返回
Integer
类型链表。在十几行代码中,这个方法提供从数组到链表的丰富内容。绿色高亮部分是装箱出箱:
// List adapter for primitive int array
public static List<Integer> asList(final int[] a) {
return new AbstractList<Integer>() {
public Integer get(int i) { return a[i]; }
// Throws NullPointerException if val == null
public Integer set(int i, Integer val) {
Integer oldVal = a[i];
a[i] = val;
return oldVal;
}
public int size() { return a.length; }
};
}
The performance of the resulting list is likely to be poor, as it boxes or unboxes on every
get
or
set
operation. It is plenty fast enough for occasional use, but it would be folly to use it in a performance critical inner loop.
结果链表的性能可能是很差的,因为每一个
get
或
set
操作都执行了出箱或装箱。对于间歇性的使用它是足够快的,但在内循环中会严重影响性能。
So when should you use autoboxing and unboxing? Use them only when there is an “impedance mismatch” between reference types and primitives, for example, when you have to put numerical values into a collection. It is not appropriate to use autoboxing and unboxing for scientific computing, or other performance-sensitive numerical code. An
Integer
is not a substitute for an
int
; autoboxing and unboxing blur the distinction between primitive types and reference types, but they do not eliminate it.
那什么时候该使用自动装箱和出箱呢?仅在引用类型和基本型间出现了“类型不匹配”错误时才用,例如,当您必须把一个数值型放入一个集合中去时。在使用科学计数法或其它敏感性数字代码中不宜使用自动装箱和出箱。
Integer
并不是
int
的替代品;自动装箱和出箱使基本型和引用类型间的区别变得模糊起来,但并没有消除。