Подтвердить что ты не робот

Java Generic Class - определение типа

Если я создаю класс java для общего типа, например:

public class Foo<T>

Как можно внутренне определить этот класс, что такое "Т"?

public ???? Bar()
{
    //if its type 1
    //    do this
    //if its type 2
    //    do this
    //if its type 3
    //    do this
    //if its type 4
    //    do this
}

Я ткнул API Java и играл с материалом Reflection, instanceof, getClass,.class и т.д., но я не могу сделать из них головы или хвосты. Я чувствую, что я рядом, и мне просто нужно объединить несколько звонков, но продолжайте быстро.

Чтобы быть более конкретным, я пытаюсь определить, был ли экземпляр класса одним из трех возможных типов.

4b9b3361

Ответ 1

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

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

Суть его заключается в следующем:

 public Class returnedClass() {
     ParameterizedType parameterizedType = (ParameterizedType)getClass()
                                                 .getGenericSuperclass();
     return (Class) parameterizedType.getActualTypeArguments()[0];
}

Ответ 2

В отличие от .NET Java дженерики реализуются методом, называемым стиранием типа.

Это означает, что компилятор будет использовать информацию о типе при создании файлов классов, но не передавать эту информацию в байтовый код. Если вы посмотрите на скомпилированные классы с помощью javap или аналогичных инструментов, вы обнаружите, что List<String> является простым List (из Object) в файле класса, как это было в коде pre-Java-5.

Кодирование, получающее общий список, будет "перезаписано" компилятором, чтобы включить в него броски, которые вам придется писать в более ранних версиях. По сути, следующие два фрагмента кода идентичны с точки зрения байтового кода после компилятора с ними:

Java 5:

List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);

Java 1.4 и до:

List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);

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

Все было сделано для того, чтобы старые библиотеки и новый расширенный код взаимодействовали без какой-либо необходимости перекомпилировать существующие библиотеки. Это основное преимущество над способом .NET, когда родовые классы и не общие файлы живут бок о бок, но не могут быть взаимозаменяемы свободно.

Оба подхода имеют свои плюсы и минусы, но так, как в Java.

Чтобы вернуться к исходному вопросу: вы не сможете получить информацию о типе во время выполнения, потому что его просто больше нет, как только компилятор выполнил свою работу. Это, безусловно, ограничивает в некотором роде и есть некоторые капризные способы вокруг него, которые обычно основаны на хранении экземпляра класса где-то, но это не стандартная функция.

Ответ 3

Из-за типа erasure, нет никакого способа сделать это напрямую. Однако вы можете сделать a Class<T> в конструкторе и удерживать его внутри вашего класса. Затем вы можете проверить его на три возможных типа Class, которые вы разрешаете.

Однако, если существует только три возможных типа, вам может потребоваться вместо этого рефакторинг enum.

Ответ 4

Проблема в том, что большая часть Generic будет исчезать во время компиляции.

Одним из распространенных решений является сохранение типа во время создания объекта.

Для краткого введения в поведение типа Erasure java прочтите эту страницу

Ответ 5

Если вы знаете несколько конкретных типов, которые имеют смысл, вы должны создать подклассы вашего общего типа с реализацией.

Итак,

public class Foo<T>

public ???? Bar()
{
    //else condition goes here
}

И затем

public class DateFoo extends Foo<Date>

public ???? Bar()
{
    //Whatever you would have put in if(T == Date) would go here.
}

Ответ 6

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

Ответ 7

Похоже, что вы хотите на самом деле не общий класс, а интерфейс с множеством различных реализаций. Но, может быть, станет ясно, если бы вы заявили о своей конкретной конкретной цели.

Ответ 8

Я согласен с Visage. Генерики предназначены для проверки времени компиляции, а не для динамического набора времени выполнения. Похоже, что вам нужно всего лишь шаблон factory. Но если ваше "делать это" не является инстанцированием, то, скорее всего, будет работать простой Enum. Как и то, что сказал Майкл, если у вас есть немного более конкретный пример, вы получите лучшие ответы.