[英]in java, why do closured variables need to be declared final?
final Object o;
List l = new ArrayList(){{
// closure over o, in lexical scope
this.add(o);
}};
why must o
be declared final?为什么o
必须被宣布为 final? why don't other JVM languages with mutable vars have this requirement?为什么其他具有可变变量的 JVM 语言没有这个要求?
This is not JVM-deep, it all happens at syntactic-sugar level.这不是 JVM 深度的,这一切都发生在语法糖级别。 The reason is that exporting a non-final var via a closure makes it vulnerable to datarace issues and, since Java was designed to be a "blue-collar" language, such a surprising change in the behavior of an otherwise tame and safe local var was deemed way too "advanced".原因是通过闭包导出非最终变量使其容易受到数据竞争问题的影响,并且由于 Java 被设计为“蓝领”语言,因此在其他温和且安全的本地变量的行为上发生了如此惊人的变化被认为太“先进”了。
It's not hard to deduce logically why it has to be final
.不难从逻辑上推断出为什么它必须是final
。
In Java, when a local variable is captured into an anonymous class, it is copied by value.在Java中,当一个局部变量被捕获到一个匿名类中时,它是按值复制的。 The reason for this is that the object may live longer than the current function call (eg it may be returned, etc.), but local variables only live as long as the current function call.这样做的原因是该对象可能比当前函数调用存活的时间更长(例如它可能被返回等),但局部变量的存活时间仅与当前函数调用一样长。 So it is not possible to simply "reference" the variable because it may not exist by then.所以不可能简单地“引用”变量,因为到那时它可能不存在。 Some languages like Python, Ruby, JavaScript, do allow you to reference variables after the scope is gone, by keeping a reference to the environment in the heap or something.某些语言(如 Python、Ruby、JavaScript)确实允许您在范围消失后引用变量,方法是在堆中保留对环境的引用或其他东西。 But this is hard to do with the JVM because local variables are allocated on the function's stack frame, which is destroyed when the function call is done.但这在 JVM 中很难做到,因为局部变量是在函数的堆栈帧上分配的,当函数调用完成时,堆栈帧就会被销毁。
Now, since it is copied, there are two copies of the variable (and more, if there are more closures capturing this variable).现在,因为它被复制了,所以变量有两个副本(如果有更多的闭包捕获这个变量,则更多)。 If they were assignable, then you can change one of them without changing the other.如果它们是可分配的,那么您可以更改其中一个而不更改另一个。 For example, hypothetically:例如,假设:
Object o;
Object x = new Object(){
public String toString() {
return o.toString();
}
};
o = somethingElse;
System.out.println(x.toString()); // prints the original object, not the re-assigned one
// even though "o" now refers to the re-assigned one
Since there is only one o
variable in the scope, you would expect them to to refer to the same thing.由于作用域中只有一个o
变量,您会期望它们指代相同的事物。 In the example above, after you assign to o
, you would expect a later access of o
from the object to refer to the new value;在上面的示例中,在分配给o
,您会期望稍后从对象访问o
以引用新值; but it doesn't.但事实并非如此。 This would be surprising and unexpected to the programmer, and violates the principle that uses of the same variable refer to the same thing.这对程序员来说是令人惊讶和意外的,并且违反了相同变量的使用指向相同事物的原则。
So to avoid this surprise, they mandate that you cannot assign to it anywhere;所以为了避免这种意外,他们要求你不能在任何地方分配它; ie it has to be final
.即它必须是final
。
Now, of course, you can still initialize the final
variable from a non- final
variable.现在,当然,你仍然可以初始化final
从非可变final
变量。 And inside the closure, you can still assign the final
variable to something else non- final
.在闭包内部,您仍然可以将final
变量分配给其他非final
变量。
Object a; // non-final
final Object o = a;
Object x = new Object(){
Object m = o; // non-final
public String toString() {
return ,.toString();
}
};
But then this is all good since you are explicitly using different variables, so there is no surprise about what it does.但是这一切都很好,因为您明确地使用了不同的变量,所以它的作用也就不足为奇了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.