【问题标题】:Effectively final - Inner classes access有效地最终 - 内部类访问
【发布时间】:2016-10-06 06:30:14
【问题描述】:

内部类只能访问最终或有效的最终变量。虽然我不明白,为什么实例变量无论如何都可以访问,但局部变量和方法参数至少需要有效地最终?

考虑以下代码:

public class BookStore {   

    private static final int taxId = 300000;   
    public String name;   

    public String searchBook(final String criteria) {      
        int count = 0;      
        int sum = 0;      
//      name = "";      I can uncomment this -> no compile error
        class Enumerator {         
            String interate(int k) {    
                System.out.println(name);
                System.out.println(sum);
                return "";         
            }             
        }            
//      sum++;      If I uncomment this, a compile error will be thrown.
        return "";
    }

}

为什么局部变量+方法参数必须是有效的final?

【问题讨论】:

    标签: java java-8


    【解决方案1】:

    这都是关于在创建实例时捕获的值。实例上下文中的内部类始终捕获不可变的外部 this 引用¹,通过它可以访问实例字段,无论是否可变。相比之下,局部变量只能通过其值来捕获,因此,变量不能改变,才能与捕获的值保持一致。

    这是一个设计决定。从技术上讲,a) 允许内部类的状态未反映的后续突变或 b) 将每个共享局部变量包装到一个对象中以允许突变,如外部类的实例字段,但两者都不允许语言设计者认为不一致或局部变量实际上不是本地的。

    ¹这与 lambda 表达式不同,后者仅在实际访问实例变量时捕获 this

    【讨论】:

      【解决方案2】:

      这是因为局部变量的作用域。它们的作用域是声明它们的方法。一旦执行离开方法,它们就不再有效。但是,诸如 Enumerator 类之类的内部类可以在方法执行之后继续存在,例如通过返回对类实例的引用。

      因此,可以在声明它的方法之外访问 Enumerator 类及其方法。此时,它需要假设它引用的局部变量具有与执行实例化类时相同的值。

      对于实例变量,它们和内部类的范围是相同的——只要父类实例存在,它们就都可用。

      【讨论】:

      • “枚举器类可以在外面访问”是什么意思?
      • 不可能与您编写的确切代码一致,但编译器考虑了理论上的可能性。你可以有类似的东西 return new Enumerator();这会将对 Enumerator 对象的引用传递给外部范围。
      • 如果我没记错的话,那是行不通的。我无法使用该方法返回类型“Enumerator”,因为如果您在方法中指定它,编译器不知道该类型。
      • 是的,你是对的,不是在这个特定的例子中。但是 Enumerator 可能是全球已知类的子类。它归结为编译器在检查本地范围的引用是否可能泄漏到外部时走了多远。它不会进行一些人类相对容易发现的检查。
      猜你喜欢
      • 1970-01-01
      • 2023-03-13
      • 2015-02-24
      • 1970-01-01
      • 2017-11-01
      • 1970-01-01
      • 2013-01-03
      • 2011-06-13
      • 2021-02-24
      相关资源
      最近更新 更多