在 java 中通过内联创建的对象访问私有元素

Accessing a private element through an inline created object in java

我是 java 的新手,在尝试一些访问方法时遇到了一些我不理解的问题。下面的代码工作正常,打印 9 并且没有给出任何编译错误。 我认为这段代码应该给出一个编译错误并且数字应该无法从测试方法访问,因为 new Human() 是一个完全不同的 class 的实例。谁能给我解释一下这里发生了什么?

public class Test{      
    public static void main(String[] args) {
        int number = 9;

        test("holla",new Human(){   
            @Override
            void test() {
                // TODO Auto-generated method stub
                System.out.println(number); // I think this line should not compile
            }               
        });    
    }

    private static void test(String a ,Human h){            
        h.test();           
    }    
} 

人类Class

public abstract class Human {       
    abstract void test();    
}

你在java 8之前是正确的。

In addition, a local class has access to local variables. However, a local class can only access local variables that are declared final. When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter.

局部变量应该是 final 以便在匿名内部访问 类。

从Java8开始,有效final变量也允许在里面访问。

However, starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.

尝试

int number = 9;
number=10;

现在 number 根本不是 有效最终,你会得到一个编译器错误 "Local variable number defined in an enclosing scope must be final or effectively final"

您可能想阅读 Difference between final and effectively final

这是完全有效的(对于 java8 - 在此之前,您在声明 number 时需要 final 关键字:

  • 你创建了一个匿名内部 class,扩展了人类并提供了test()所需的实现方法。
  • 该方法正在使用其封闭 "scope" 中的变量 - 编译器足够聪明,可以检测到该变量实际上是一个常量 - 因为没有其他后续赋值给它。

为了 "invalidate" 你的例子:只需添加一个赋值

number = 42; 

在 main 方法中 - 在定义匿名内部 class 之后。或者使用早于 java8.

的 java 版本

请记住,匿名内部 classes 是 closures,并且 JVM copying从外面需要 "inside"。但是当外部值发生变化时——应该复制哪个值。请参阅 here 以进一步阅读。