Skip to content

Latest commit

 

History

History
98 lines (74 loc) · 4.54 KB

02_Boxing_and_Unboxing.md

File metadata and controls

98 lines (74 loc) · 4.54 KB

《《《 返回首页
《《《 上一节

装箱与拆箱

回想一下,Java 中的每种类型都是引用类型或基本类型。 引用类型是任何类,接口或数组类型。 所有引用类型都是 Object 类的子类型,任何引用类型的变量都 可以设置为 null。 如下表所示,有八种基本类型,每种都有相应的类库的引用类型。 类库位于 java.lang 包:

原始类型 引用类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character

将原始类型转换为相应的引用类型称为装箱,并将引用类型转换为相应的原始类型称为拆箱

带泛型的 Java 在适当的地方自动装箱和拆箱。 如果 int 类型的表达式 E 出现在需要 Integer 类型值的地方,那么装箱会将其转换为新的 Integer(e)(但是,它可能会缓存经常出现的值)。 如果 Integer 类型的表达式 E 出现在期望 int 类型的值处,则拆箱将其转换为表达 式 e.intValue()。例如,集合

  List<Integer> ints = new ArrayList<Integer>();
  ints.add(1);
  int n = ints.get(0);

相当于集合:

  List<Integer> ints = new ArrayList<Integer>();
  ints.add(Integer.valueOf(1));
  int n = ints.get(0).intValue();

调用 Integer.valueOf(1) 与新的 Integer(1) 表达式类似,但是可能会缓存一些值以提高性能,正如我们稍后解释的那样。

在这里,再次,是代码来找到一个整数集合的和,方便打包为一个静态的方法:

  public static int sum (List<Integer> ints) {
  int s = 0;
  for (int n : ints) { s += n; }
  return s;
  }

为什么参数的类型是 List<Integer> 而不是 List<int>? 因为类型参数必须始终绑定到引用类型,而不是基本类型。

为什么结果有类型 int 和不是 Integer? 因为结果类型可能是原始类型或引用类型,使用前者比后者更有效。

拆箱在列表中的每个整数都绑定到 int 类型的变量 n 时发生。

我们可以重写这个方法,用Integer来替换每个 int 的出现:

  public static Integer sumInteger(List<Integer> ints) {
    Integer s = 0;
    for (Integer n : ints) { s += n; }
    return s;
  }

此代码编译,但执行了很多不必要的工作。 循环的每个迭代将 sn 中的值拆箱,执行加法操作,然后再次结束结果。使用 Sun 当前的编译器,测量结果显示 该版本大约为比原来慢60%。

注意这个! 装箱和拆箱的一个微妙之处在于 == 在原语和参考类型上的定义是不同的。 在 int 类型上,它是由值相等来定义的,而Integer类型则由对象标识 来定义。 所以下面的两个断言使用 SunJVM 是成功的:

  List<Integer> bigs = Arrays.asList(100,200,300);
  assert sumInteger(bigs) == sum(bigs);
  assert sumInteger(bigs) != sumInteger(bigs); // 不推荐

在第一个断言中,拆箱会导致值进行比较,所以结果是相同的。在第二个断言中,没有拆箱,两个方法调用返回不同整数对象,所以即使两个整数对象都表示结果也是不 相等的相同的值,600。我们建议您不要使用 == 来比较类型的值 Integer。 要么首先取消装箱,所以 == 比较 int 类型的值,否则使用 equals 比较 Integer类型的值。

更精妙的是装箱值可以被缓存。 装箱时需要缓存一个介于 -128127 之间的 intshort 值,一个介于'\ u0000'和之间的char值'\ u007f',一个字 节或一个布尔值; 并在装箱时允许进行缓存。因此,与我们之前的例子相比,我们有以下几点:

  List<Integer> smalls = Arrays.asList(1,2,3);
  assert sumInteger(smalls) == sum(smalls);
  assert sumInteger(smalls) == sumInteger(smalls); // 不推荐

这是因为 6 小于 128,所以装箱数值 6 总是返回正确的同一个对象。 一般来说,没有规定两次是否装箱相同的值返回相同或不同的对象,所以前面显示的不等 式断言也可以取决于实施失败或成功。 即使是小的值,为什么 == 将正确比较 Integer 类型的值,我们建议不要使用它。 它更清晰和更清洁使用 equals 而不 是 == 来比较引用类型的值,例如 IntegerString

《《《 下一节
《《《 返回首页