关于java:引用内部类的字段

Referencing fields of an Inner Class

本问题已经有最佳答案,请猛点这里访问。

我是java的新手,并试图了解匿名内部类的工作原理。

1
2
3
4
5
6
7
Object a = new Object(){
    Object b = new Object(){
        String c ="Hi!";
    };
};

System.out.println( a.b.c );

当我尝试运行上面的代码时,我得到一个'找不到符号'的错误。 有人可以解释一下为什么我会收到此错误,如何引用String c。

(我之所以尝试'可能很奇怪'的原因是我想以像'ui.menu.file.open'这样的分层方式组织窗口小部件句柄。)


虽然动态类型的变量a是具有字段c的匿名类型,但其静态类型是Object,其没有字段c

一旦Java引入了var声明,你就可以解决这个问题,这些声明隐式地派生了这个类型。不幸的是,直到Java 10才能使用它:

1
2
3
4
5
// ** WARNING ** This would not compile until Java 10
var a = new Object() {
    String c ="Hi!";
};
System.out.println( a.c );

在此之前,您必须为匿名对象声明一个公共类型,并让它公开您需要的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface HasMyProperty {
    String getC();
}
interface HasMyObject {
    HasMyProperty getB();
}
...
HasMyObject a = new HasMyObject() {
    HasMyProperty b = new HasMyProperty() {
        private final String c ="Hi!";
        @Override
        public string getC() { return c; }
    };
    @Override
    public HasMyProperty getB() { return b; }
};
System.out.println( a.getB().getC() );


这里bc是匿名类的字段,但是你不能在匿名类之外引用它们,因为类的类型是ObjectObject类没有这些字段。
虽然在匿名类本身中引用这些字段是合法的,例如:

1
2
3
4
5
6
7
8
9
10
11
Object a = new Object(){

    Object b = new Object(){

        String c ="Hi!";
        @Override
        public String toString(){
            return c;
        }
    };
};

要解决您的需求(访问自定义字段),您不应使用匿名类,而应使用自己的类来呈现预期的结构,例如:

1
2
3
4
5
6
public class A{
   public B b = new B();
}
public class B{
   public String c ="Hi";
}

所以你可以写(虽然不建议使用公共实例字段):

1
String c = new A().b.c;