Как получить доступ к полям, объявленным внутри анонимного объекта?

Java позволяет вам объявлять новые поля внутри анонимных классов, но я не могу понять, как получить к ним доступ извне, даже установка их как общедоступных не позволяет мне.

class A {
   public static void main(String[] args) {
       Object o = new Object() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }
       };
       System.out.println(o.x);
   }
}

Я получаю эту ошибку компилятора:

$ javac A.java && java A
A.java:10: cannot find symbol
symbol  : variable x
location: class java.lang.Object
       System.out.println(o.x);
                           ^
1 error

Почему?


person Dog    schedule 10.05.2013    source источник
comment
Это не человек JavaScript: D   -  person Lukas Knuth    schedule 11.05.2013


Ответы (6)


Почему?

Это потому, что Object является статическим типом переменной o, а Object не имеет свойства x. Следующее не скомпилируется по той же причине:

public class X {
  public int x;

  public static void main(String[] args) {
    Object o = new X();
    o.x = 3;
  }
}

Будем надеяться, что ваша интуиция в отношении Java верна в этом примере, и вы ожидаете, что это не удастся. Так что просто перенесите эту интуицию на свой пример.

Как получить доступ к полям, объявленным внутри анонимного объекта?

Так же, как вы получили бы доступ к x в моем примере: отражение.

Object o = new X();
o.getClass().getField("x").setInt(o, 3);

Почему он позволяет мне создавать общедоступные поля, если я не могу их использовать?

Если бы это не позволяло вам делать публичные поля, у вас бы не работало даже отражение, по крайней мере, не так просто, как выше.

person Marko Topolnik    schedule 10.05.2013
comment
во втором примере можно с X o = new X(); или с приведением ((X) o) .getClass() ... также нужно отловить некоторые проверенные исключения для отражения - person zemiak; 13.12.2020
comment
Возможно, но не имеет значения, потому что это не применимо для ОП. - person Marko Topolnik; 14.12.2020

Вы могли бы сделать это только путем отражения. У класса нет имени, поэтому вам пришлось объявить переменную o как Object, а Object не имеет этого члена. Другими словами, не делайте этого.

person Eric Jablow    schedule 10.05.2013
comment
Тогда почему неиспользуемые переменные являются ошибкой компиляции? Это проще не запрещать, но Java это делает. - person Dog; 11.05.2013
comment
Неиспользуемые переменные не являются ошибкой компиляции согласно Спецификации языка Java. То, что среда IDE сообщает об ошибке, не имеет ничего общего с языком Java. - person Marko Topolnik; 11.05.2013
comment
@MarkoTopolnik, упс. Я имел в виду, что недоступные строки кода вызывают ошибки компиляции. Кроме того, легче не иметь типов, поэтому я бы не стал утверждать, что Java занимается созданием чего-либо только потому, что его проще реализовать. - person Dog; 11.05.2013
comment
Я удалил свой комментарий, потому что он стал бессмысленным, когда другой комментарий был удален. - person Eric Jablow; 11.05.2013

Вы можете получить доступ к полю путем отражения:

    Object o = new Object() {
       public int x = 0;
       {
           System.out.println("x: " + x++);
           System.out.println("x: " + x++);
       }
   };
   System.out.println(o.getClass().getField("x").get(o));

Лучшим стилем было бы назвать класс и использовать его как тип переменной, если вы хотите получить доступ к полю:

    class MyObject {
       public int x = 0;
       {
           System.out.println("x: " + x++);
           System.out.println("x: " + x++);
       }
   }
   MyObject o = new MyObject();
   System.out.println(o.x);
person tkr    schedule 10.05.2013

Вы можете получить к нему доступ непосредственно в выражении создания анонимного класса:

class A {
   public static void main(String[] args) {
       System.out.println(new Object() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }
       }.x);
   }
}

Но тогда вы больше не можете использовать созданный объект, так что это бесполезно.

person newacct    schedule 10.05.2013

Определите внутренний класс, который расширяет Object (в вашем конкретном случае вы не должны писать extends Object, как это делается в любом случае. В своем классе определите свои поля, а затем получите к ним доступ по ссылке вашего типа.

Пример:

void func() {
     class MyInt extends Integer {
         boolean isSane = true;
     }
     MyInt intInstance = new MyInt();
     if (intInstance .isSane) {
         System.out.println("sane integer");
     }
}
person SomethingSomething    schedule 04.03.2014

также после Java 10 вы можете использовать магию 'var' (вывод типа локальной переменной)

class A {
   public static void main(String[] args) {
       // Object o = new Object() {
       var o = new Object() {
           public int x = 0;
           {
               System.out.println("x: " + x++);
               System.out.println("x: " + x++);
           }
       };
       System.out.println(o.x);
   }
}
person zemiak    schedule 13.12.2020