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 и т.д., но я не могу сделать из них головы или хвосты. Я чувствую, что я рядом, и мне просто нужно объединить несколько звонков, но продолжайте быстро.
Чтобы быть более конкретным, я пытаюсь определить, был ли экземпляр класса одним из трех возможных типов.
Ответы
Ответ 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. Как и то, что сказал Майкл, если у вас есть немного более конкретный пример, вы получите лучшие ответы.