Скажем, у меня есть следующий класс:
public class MyClass<T> {
Class<T> type;
List<T> items;
public Class<T> getType() { return type; }
...
}
Мне нужно хранить объекты вышеуказанного класса в общем контейнере:
public class MyContainer<T> {
Class<T> type;
List<MyClass<T>> myClasses;
public Class<T> getType() { return type; }
...
}
Скажем позже в моем коде, мне предоставляется общий объект в качестве аргумента:
public class Main {
public static void main() {
List<MyContainer<?>> containers;
...
}
public void someMethod(MyClass<?> myClass){
...
}
}
У меня тип T как отражение. Мне нужно вернуть MyClass<?>
Обратно к его предполагаемому типу. Поэтому, если он был объявлен как MyClass<String>
мне нужно вернуть его в MyClass<String>
. Я не могу сделать этого с типом отражения, потому что он способен только набрасывать T, а не MyClass<T>
.
Я мог бы бросить T, сделав это, например:
myClass.getType().cast(myClass.getItem()); // Where getItem returns an object of the type T
Но я хочу, чтобы это:
myClass.getType().cast(myClass); // getType() returns T not MyClass<T>
Итак, вопрос в том, как я применил общий базовый тип вместе с его типом отражения, учитывая приведенный выше сценарий?
Это невозможно из-за стирания типа. Отражение не может помочь вам здесь, потому что во время выполнения общая информация типа недоступна. Другими словами, во время выполнения нет MyClass<String>
, есть только MyClass
. MyClass<String>
- это чистая компиляция.
Если у вас есть часть кода, ожидающая определенного типа, объявите это во время компиляции. Ожидание этого типа может быть конкретным или общим:
public void someMethod(MyClass<String> myClass)
или
public <T> void someMethod(MyClass<T> myClass)
Если вы знаете тип, вам не нужен cast()
, вы можете просто нажать:
@SuppressWarnings("unchecked")
MyClass<String> myClassStr = (MyClass<String>)expression;
Поскольку T
не существует во время выполнения, что вы знаете, вы не можете его использовать. Вы также не можете получить Class<List<T>>
.
myClass.getType().cast(myClass.getItem())
действительно не работает для вас, потому что если у вас есть MyClass<?>
то у вас также есть Class<?>
который возвращает объект. Class<T>
тоже не поможет, потому что вам действительно нужно знать, что такое T
Вы можете в значительной степени сделать две вещи.
Использовать решения:
if(myClass.getType() == String.class) {
@SuppressWarnings("unchecked")
final MyClass<String> myStrings = (MyClass<String>)myClass;
// use MyClass<String> ...
}
Использовать полиморфизм:
MyClass<String> myClass = new MyClass<String>(...,
new BiConsumer<String, JTable>() { // (or lambda ...)
@Override
public void accept(String s, JTable table) {
// use String ...
// configure JTable ...
}
});
... elsewhere ...
public void someMethod(MyClass<?> myClass) {
someCaptureMethod(myClass);
}
private <T> void someCaptureMethod(MyClass<T> myClass) {
Consumer<T, JTable> consumer = myClass.getConsumer();
for(T theT : myClass.getList()) {
consumer.accept(theT, myTable);
}
}
Как правило, второй пример считается "лучшим", но код может быть длиннее в версиях Java до 8.
T
Главное, на что я отвечаю - это два варианта.
T
не существует во время выполнения (когда происходит отражение), поэтому я не совсем понимаю, что вы пытаетесь сделать.