简体   繁体   English

在java中,为什么需要将闭包变量声明为final?

[英]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.

相关问题 Java为什么在没有设置方法的情况下我们需要将实例变量声明为final - Java why do we need an instance variable declared as final if there are no set methods 为什么传递给runnable的变量需要是最终的? - Why do variables passed to runnable need to be final? 为什么大多数开源java项目中的局部变量都没有被声明为final? - Why are local variables not declared final in most open source java projects? 为什么在 try-with-resources 语句之外声明的资源需要在 java 中是 final 或有效 final? - why resources declared outside the try-with-resources statement need to be final or effectively final in java? 我是否需要为 Java 中的所有不可变变量指定 «final» 修饰符? - Do I need to specify «final» modifier for ALL immutable variables in Java? 为什么Java的BigDecimal类没有被声明为final? - Why is Java's BigDecimal class not declared as final? 为什么String类在Java中声明为final? - Why is the String class declared final in Java? java @SafeVarargs 为什么私有方法需要是 final - java @SafeVarargs why do private methods need to be final 为什么java接口变量是final的? - Why the java interface variables are final? 为什么不能将方法局部变量声明为final? - Why can't variables local to a method be declared final?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM