Как указать информацию о классе универсального типа во время компиляции?

#java #generics

#java #общие сведения

Вопрос:

У меня есть класс, определенный следующим образом:

 public class GenericClass<T> {

 private final Class<T> type;

 public GenericClass(Class<T> type) {
      this.type = type;
 }

 public Class<T> getMyType() {
     return this.type;
 }
}
  

С помощью этого кода класса легко создать новый экземпляр класса с не-универсальным типом. Например:

 GenericClass<String> c = new GenericClass<String>(String.class)
  

Мой вопрос заключается в следующем. Как я могу создать новый экземпляр класса с универсальным типом? Пример:

 GenericClass<List<String>> c = new GenericClass<List<String>>(...)
  

Если я помещаю List<String>.class , компилятор выдает мне ошибку. Какой синтаксис я должен использовать во время компиляции, чтобы указать конструктору правильный класс универсального типа?

Комментарии:

1. вам нужно сделать List.class,

2. Из-за стирания типа общая часть все равно теряется во время выполнения. Таким образом, во время выполнения невозможно различить List и List<String> . Поэтому вы должны просто использовать List.class .

3. Как упоминали другие, будет сложно получить больше информации, чем вы могли бы получить с помощью List.class . Информация о параметре типа будет потеряна. Однако TypeToken класс Guava предлагает сложную инфраструктуру для такого рода задач, и вы, возможно, захотите взглянуть: code.google.com/p/guava-libraries/wiki/ReflectionExplained

Ответ №1:

Универсальный не знает и не заботится о том, чтобы был указан общий класс, и, как таковой, нет List<String>.class , только List.class . Вы рассматривали подстановочные знаки? Что должно List<?>.class вернуться? И List<? extends AnotherClass>.class ? Итак, нет, вы не можете знать, какой конкретный класс содержит универсальный класс во время компиляции, в основном потому, что он может содержать разные классы, которые полностью указаны только во время выполнения.

Ответ №2:

Единственный способ записать обобщения для типа класса (и, следовательно, сделать их доступными во время выполнения с отражением) — это создать ваш подкласс GenericClass . Даже анонимный внутренний класс выполняет эту работу:

 GenericClass<List<String>> c = new GenericClass<List<String>>(...){};
  

(обратите внимание на завершение). {}

Комментарии:

1. Обратите внимание, что OP указывает «во время компиляции» .

2. Точно. Во время компиляции. Все анонимные внутренние классы создаются во время компиляции.

3. Во время компиляции средства .class должны работать. GenericClass<List<String>>.class по-прежнему недопустимый синтаксис. То, что вы предлагаете, делает GenericClass абстрактным, извините, я не понимаю, как это решает проблему.

4. Очевидно, я не могу изменить синтаксис java. Я только что объяснил, как записать общий параметр в байтовый код.

Ответ №3:

Как насчет:

 public class GenericClass<T> {
    Class<T> type;

    @SuppressWarnings("unchecked")
    public GenericClass() {
        Type type = ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
        if (type instanceof Class<?>)
            this.type = (Class<T>)type;
        else if (type instanceof ParameterizedType)
            this.type = (Class<T>) ((ParameterizedType)type).getRawType();
        else
            this.type = null;
    }

    public Class<T> getType() {
        return type;
    }
}
  

Использование:

 public static void main(String[] args) {
    GenericClass<Integer> g = new GenericClass<Integer>() {};
    System.out.println(g.getType());

    GenericClass<List<String>> g2 = new GenericClass<List<String>>() {};
    System.out.println(g2.getType());
}
  

Комментарии:

1. Обратите внимание на вопрос: «во время компиляции» .

2. Я думаю, что в названии вопроса упоминается время компиляции, потому что ошибка является ошибкой времени компиляции… Этот ответ предоставляет решение общей проблемы, которую пытаются решить, нет?

3. Я думаю, нет, потому что вопрос заключается в том, чтобы получить тип во время компиляции. Вы также можете свободно интерпретировать вопрос так, как вы это делали, все в порядке, я просто задаю правильный вопрос: D

4. «Мой вопрос заключается в следующем. Как я могу создать новый экземпляр класса с универсальным типом?» : p

5. В заголовке большими черными жирными буквами: «во время компиляции» : P

Ответ №4:

Ваша проблема в том, что существует только один List объект класса, который вы можете получить List.class . Но это Class<List> , Class<List<Object>> , Class<List<String>> , или Class<List<?>> и т.д.? Он может иметь только один тип, и разработчики Java выбрали Class<List> (это единственный безопасный выбор). Если вы действительно хотите a Class<List<String>> , вам придется выполнить несколько непроверенных приведений:

 GenericClass<List<String>> c =
    new GenericClass<List<String>>((Class<List<String>>)(Class<?>)List.class);