繁体   English   中英

为什么匿名内部类可以访问和更新外部类的非final实例变量?

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM