关闭数组类型

时间:2018-01-20 17:11:07

标签: java

请考虑以下代码:

Integer[] arr = new Integer[] {1,2};
Consumer<Integer> lm1 = a -> {
    arr[1] = a; // accepted without any problem
    System.out.println(arr[1]);
};

lm1.accept(100);

但是编译器有这个问题:

Integer b = 10;
Consumer<Integer> lm2 = a -> {
    b = a; // compiler complains
    System.out.println(b);
};

lm2.accept(20);

我了解如果我在代码段1中使用arr重新初始化new Integer[]{1}会导致错误,但我更有兴趣理解为什么代码段1不会导致任何错误?

3 个答案:

答案 0 :(得分:3)

不同之处在于间接等级的数量:

  • 第一个示例关闭一个数组,当您分配时,该数组保持不变:arr已修复,arr[1]不是
  • 第二个示例关闭Integer对象,您尝试在作业b=a中进行更改。这是不允许的。

请注意,此行为不是特定于数组的:任何可变对象都可用于实现间接。例如,您可以使用AtomicInteger,这是可设置的:

AtomicInteger b = new AtomicInteger(10);
Consumer<Integer> lm2 = a -> {
    b.set(a); // compiler complains
    System.out.println(b);
};
lm2.accept(20);

答案 1 :(得分:1)

Java lambdas要求你在lambda中引用的任何变量必须有效最终 - 也就是说,你不能修改变量所持有的值。

当你只创建一个普通的Integer时,它是一个常规值类型(自动装箱) - 分配给它会更改该值并且不允许。

但是,当你将Integer包装在一个数组中时,你并没有修改变量本身的内容,因为它是对数组的引用 - 你要修改它对它进行引用。

答案 2 :(得分:1)

嗯,问题是Integer是一个Object引用,它的引用可以改变。

另一方面,当你有一个数组时,它是内存中一组固定的地址,无法更改(这就是为什么数组是固定长度的)。因此,您只能更改数组中的值而不是其引用。

lambda将在稍后调用,因此编译器希望您将其设置为final,以确保您不会更改对它的引用。