Java, отражающий вложенные анонимные классы - PullRequest
3 голосов
/ 27 февраля 2011

Почему этот код возвращает «класс java.lang.Object»?

Object a = new Object() {
  public Object b = new Object(){
    public int c;
  };
};

System.out.println(a.getClass().getField("b").getType());

Почему внутренний-внутренний тип теряется?Как я могу отразить поле c?

Редактировать:

Это работает (как указано в некоторых ответах):

a.getClass().getField("b").get(a) ...

Но тогда я должен вызватьgetter, есть ли способ отразить c только с метаданными отражения?

Ответы [ 3 ]

5 голосов
/ 27 февраля 2011

Поскольку b объявлено как Object:

public Object b = ...;

Существует различие между типом переменной (статический тип) и типом объекта, на который ссылается эта переменная (тип времени выполнения).

Field.getType() возвращает статический тип поля.

Если вы хотите получить тип времени выполнения объекта, на который ссылается поле, вам нужно получить к нему доступ и вызвать на нем getClass() (поскольку a объявлен как Object и, следовательно, b не виден как его член вы должны использовать отражение для доступа к нему):

System.out.println(
     a.getClass().getField("b").get(a).getClass());

ОБНОВЛЕНИЕ: Вы не можете отразить c без доступа к экземпляру объекта, его содержащего. Вот почему эти типы называются анонимными - тип, содержащий c, не имеет имени, поэтому вы не можете объявить поле b как поле этого типа.

3 голосов
/ 27 февраля 2011

Давайте внимательно посмотрим на эту строку:

System.out.println(a.getClass().getField("b").getType());

Сначала возьмем переменную a.Это некоторый анонимный подкласс объекта.Давайте назовем этот класс MyClass$1.Хорошо, пока все хорошо.

Далее вы вызываете метод getClass ().Он возвращает класс a, то есть описание класса MyClass$1.Это описание не привязано к какому-либо конкретному экземпляру этого класса.Класс одинаков для всех экземпляров, будь то a или что-то еще (если не используются разные загрузчики классов).В этом конкретном случае, однако, может быть только один экземпляр, поскольку класс является анонимным, но механизм все тот же.

Теперь из класса вы получаете поле b.Поскольку класс не связан напрямую ни с одним из этих экземпляров, поле также не имеет ничего общего с a.Это просто описание того, что представляет собой поле a класса MyClass$1.

Теперь вы получите его тип.Но поскольку он не привязан ни к какому экземпляру, он не может знать тип среды выполнения.На самом деле, если класс не был анонимным, у вас может быть множество экземпляров MyClass$1, каждый из которых имеет различное значение в a.Или у вас не может быть никаких экземпляров вообще.Таким образом, единственная вещь, которую getType () может вам сказать, это объявленный тип b, что именно и делает.Поле b на самом деле может быть null в этот момент, и вы все равно получите Object в качестве результата.

Класс Field предоставляет метод get () для фактического доступа к этому конкретному полюнекоторого объекта, такого как:

System.out.println(a.getClass().getField("b").get(a).getClass());

Теперь вы получаете что-то вроде MyClass$1$1, который является именем анонимного класса объекта, на который ссылается поле b, в a экземпляр .

1 голос
/ 27 февраля 2011

Почему внутренне-внутренний тип теряется?

Поскольку вы получаете тип type поля "b" (Object), а не тип анонимного внутреннего класса, которому вы присвоили экземпляр "b".

Как мне отразить поле c?

Вы можете использовать это

System.out.println(a.getClass().getField("b").get(a).getClass().getField("c"));

вместо этого. Это получает значение поля "b" и его класса, но это работает, только если гарантировано, что "b" не равно нулю.

Это, похоже, указывает на плохой дизайн, могут быть другие способы архивировать то, что вы хотите с этим сделать. Но не зная цели, это все, что я могу ответить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...