Могу ли я использовать поле класса в экземпляре ArrayList <T>в Java? - PullRequest
7 голосов
/ 22 сентября 2011

У меня есть этот код, который компилируется:

new TypeToken<ArrayList<ServerTask>>() {}.getType()

Затем я попытался

ArrayList<ServerTask>.class

, который не компилируется.

Я новичок в программировании на Java(пришло из C #), и я подумал, что T.class является точным эквивалентом typeof(T) в C #.Очевидно, что-то действительно базовое, чего я не понимаю, поэтому мой вопрос в том, что не так с ArrayList<ServerTask>.class, и у меня нет выбора, но вместо этого использовать new TypeToken<ArrayList<ServerTask>>() {}.getType()?Есть ли более короткая (более хорошая, разумная) форма?

Спасибо.

Ответы [ 4 ]

11 голосов
/ 22 сентября 2011

К сожалению (?) Java реализует обобщенные типы, используя Тип Erasure .

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

Точнее говоря, Generics в Java является конструкцией только во время компиляции.Они гарантируют безопасность типов только во время компиляции.

РЕДАКТИРОВАТЬ: Я только что заметил этот бит кода -

new TypeToken<ArrayList<ServerTask>>() {}.getType()

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

public interface List<T> {
}

public class StringList implements List<String> {
  // The bytecode of this class contains type information.
}

В вашем примере вы тривиально расширяете класс TypeToken, заставляя компилятор генерировать анонимный внутренний класс , который содержит информацию о типе.Реализация TypeToken.getType() будет использовать отражение, чтобы предоставить вам информацию этого типа.

EDIT2: Для более подробного объяснения взгляните на Reflecting Generics .

1 голос
/ 22 сентября 2011

Что касается конструкции ".class", то она не является ни оператором, ни членом экземпляра, это фактически способ сказать языку "иди и найди объект Class для этого имени класса перед точкой".Способ построения литералов класса .

Как указано в разделе 15.8.2 JLE , компилятор будет жаловаться, если вы попытаетесь использовать его с параметризованнымтип (среди прочих).

1 голос
/ 22 сентября 2011

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

(new TypeToken<ArrayList<ServerTask>>() {}.getType()).getClass(TypeToken.class)

вернет false!

Во втором примере кода вы пытаетесь сделать что-то, что Java не поддерживает из-за того, как обобщенные типы реализованы с типомстирание.Не существует класса, представляющего ArrayList, общий параметр которого связан ... с точки зрения компилятора ArrayList является ArrayList независимо от универсального типа, поэтому выражение не компилируется.

Вполне возможно, что ни одна из частей кода не будет работать правильно.Если вам нужно поиграть с классами с общими параметрами, вы, возможно, захотите взглянуть на gentyref , который, как я обнаружил, очень помогает упростить API, чтобы задавать вопросы, которые вы пытаетесь задать.получить ответы на вопрос.

0 голосов
/ 22 сентября 2011

Пример, приведенный Bringer128 , считается анти-паттерном, называемым pseudo-typedef antipattern . Вот альтернатива:

class TokenUtil{
   public static <T> TypeToken<T> newTypeToken(){
   return new TypeToken<T>();
   }
  public static void main(String[] args) {
    TypeToken<ArrayList<ServerTask>> typeTok = TokenUtil.newTypeToken();
    Type type = typeTok.getType();
   }

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