[英]Why a non-final “local” variable cannot be used inside an inner class, and instead a non-final field of the enclosing class can?
[英]Why the non-final instance variable of the outer class can be accessed and updated in the anonymous inner class?
在所有的文章中,都说java是按值复制的,内部类无法访问和修改外部类的实例变量。 但是现在可以做,为什么呢? 我的 jdk 是 1.8。
public class InnerClass {
private int counts = 0;
public void test(int src) {
int in = 100;
new Thread(new Runnable() {
private int a() {
counts++;
counts = src;
counts = in;
System.out.println("in a..." + counts);
return counts;
}
@Override
public void run() {
int s = a();
counts = s;
System.out.println("in run, " + counts);
}
}).start();
}
public int getCounts() {
return this.counts;
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
innerClass.test(99);
try {
Thread.sleep(1000);
} catch (java.lang.InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
System.out.println("in main," + innerClass.getCounts());
}
}
你的误解:这样的匿名内部类不能接受封闭范围的局部变量。 但是他们可以毫无问题地访问封闭类的字段。
你读过的文章是关于方法或构造函数中的参数和局部变量的; 不是其他类型的变量,例如示例中的实例变量。 内部类禁止修改属于封闭方法的参数或局部变量,但不能修改任何其他类型的变量。
这样做的原因是,为了使对象保持可访问和可修改的变量,该变量的内存必须在该对象的生命周期内保持分配状态。
内部类的封闭实例将在内部类实例的生命周期中保留在内存中,因为内部类的实例维护对其封闭实例的引用,这意味着封闭实例不能在实例之前被垃圾收集内部类。 因此,内部类可以安全地读取和写入该变量。
但是,参数或局部变量是在栈上分配的,而不是在堆上; 一旦方法返回,它就会被释放,这可能是在内部类实例的生命周期内。 因此,在其内存被释放并可能分配给不同的变量后,内部类读取或写入该变量是不安全的。
这确实提出了为什么允许内部类读取(但不能写入)最终或有效最终参数或局部变量的问题。 对此的答案是将其值复制到属于内部类的自动生成的字段中,内部类读取该字段的值。 该字段在对象的生命周期内存在,当然,因为它是对象的一部分。
但这引发了另一个问题:为什么只有 final 或有效最终变量被复制到实例的字段中? 为什么不允许可变的自动生成字段? 答案是,一个内部类的多个实例(可能多个内部类)可能会尝试访问同一个变量,并且为每个实例制作副本会产生意想不到的行为,因为一个实例所做的更改不会对另一个人可见。
这可以通过支持适当的闭包来解决,就像 Javascript 这样的语言所做的那样,但它需要 Java 编译器合成一个类来表示方法的闭包,这会给语言规范和编译器增加很多复杂性。 这种复杂性是不必要的,因为您始终可以只使用实例变量来实现相同的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.