3

I'm new to java and trying to understand how anonymous inner classes work.

Object a = new Object(){
    Object b = new Object(){
        String c = "Hi!";
    };
};

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

When I try to run the code above, I get a 'cannot find symbol' error. Can somebody explain me why am I getting this error and how can I reference the String c.

(The reason why I am trying 'a possibly weird' thing is I wanted to organize widget handles in a hierarchical way like 'ui.menu.file.open'.)

JavaNovice
  • 33
  • 2
  • The type of `a` is `Object`, and `b` is not part of its interface. You need a non-anonymous class for this. – NickL Apr 11 '18 at 20:12
  • If you want hierarchical constants, try nested classes, e.g., `class Ui { class Menu { class File { static final String OPEN = "foo"; }}}` – shmosel Apr 11 '18 at 20:24

2 Answers2

2

While the dynamic type of variable a is an anonymous type that has field c, its static type is Object, which does not have field c.

You would be able to solve this problem once Java introduces var declarations, which derive the type implicitly. Unfortunately, this wouldn't be available until Java 10:

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

Until then you would have to declare a common type for your anonymous objects, and have it expose the properties that you need:

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() );
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • @cppbeginner Right, I didn't see the second level there. I removed it now, and added a more down-to-earth example for the current versions of Java. – Sergey Kalinichenko Apr 11 '18 at 20:22
0

Here b and c are fields of the anonymous classes but you cannot refer to them outside the anonymous classes as the type of the class is Object and the Object class doesn't have these fields.
While it would be legal to refer these fields inside the anonymous class itself such as :

Object a = new Object(){

    Object b = new Object(){

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

To solve your requirement (access to custom fields) you should not use anonymous classes but your own classes that present the expected structure such as :

public class A{
   public B b = new B();
}
public class B{
   public String c = "Hi";
}

So you could write (while public instance fields are not at all recommended) :

String c = new A().b.c;
davidxxx
  • 125,838
  • 23
  • 214
  • 215