Ответ 1
Я думаю, что токены супертекста могут решить эту проблему для вас.
Моя цель - создать класс, который может выводить объект определенного класса.
public class GetMe<T> {
public T get() {
Object obj = generateObject();
return (T) obj;
}
}
Теперь я знаю, что это невозможно из-за стирания. Итак, мы можем передать экземпляр класса и использовать его для создания.
public class GetMe<T> {
public GetMe<T>(Class<T> clazz) {
this.clazz = clazz;
}
public T get() {
Object obj = generateObject();
return clazz.cast(obj);
}
}
Это отлично работает! Пока класс не параметризуется. Если да, то у меня проблема.
Мне не разрешено использовать List<String>.class
. Если я передаю параметр ParameterizedType (который сам по себе сложно сгенерировать), не существует метода cast
.
Есть ли выход из этой трясины?
Я думаю, что токены супертекста могут решить эту проблему для вас.
Проблема с List<String>
заключается в том, что из-за стирания это было бы во время выполнения неотличимым от любого другого List<?>
. Самый простой способ - создать новый класс или интерфейс, который имеет общую "фиксированную" часть, например
public interface StringList extends List<String> {
/* nothing to see here */
}
Таким образом, у вас есть токен типа (объект StringList.class
), который вы можете передавать во время выполнения, и указывает именно то, что вы хотите, но без необходимости создания дженериков во время выполнения.
Вот только небольшая идея. Я не уверен, будет ли он соответствовать вашему контексту, но тем не менее:
public class GetMe<T>
{
public List<T> getList() {
@SuppressWarnings("unchecked")
List<T> result = (List<T>) new LinkedList();
return result;
}
}
Ура!
Первая проблема заключается в том, как вы планируете создавать экземпляр объекта List
. Если вы раскрываете больше того, что вы пытаетесь построить, мы можем помочь вам лучше.
Вы можете использовать Type вместо класса. Тип может представлять все общие типы, хотя с ним не приятно работать.
abstract public class GetMe<T>
{
Type type;
public GetMe<T>(Type type)
{
this.type = type;
}
}
Другая проблема заключается в том, как создать общий тип типа List<String>
. "Символ супер-типа" выглядит аккуратным в синтаксисе, на самом деле он в основном
static class XX extends TypeReference<List<String>>{}
....
Type typeListString = Util.extract(XX.class);
Я бы предпочел этот вариант
List<String> f;
Type typeListString = getDeclaredField("f").getGenericType();
На самом деле, многие из этих фреймворков, которые придумывают общие магические матчи среды выполнения, работают только с полями экземпляра.
Я думаю, что путаница возникает из-за того, что вы пытаетесь создать объект из List<>
, который на первый взгляд является интерфейсом, а не объектом.
Таким образом, независимо от того, что вы попробуете, вы просто не можете создать экземпляр List<>
, (интерфейсы не являются фактическими классами и не имеют конструкторов)
Попробуйте использовать ограничение, чтобы не вставлять интерфейсы в объявление:
public class GetMe<T extends Object>
Это гарантирует, что T является фактическим классом, а не интерфейсом.