Как получить атрибут `.class` из параметра общего типа?
В принятом ответе на этот вопрос описывается, как создать экземпляр T
в классе Generic<T>
. Это включает в себя передачу параметра Class<T>
конструктору Generic
и вызов метода newInstance
из этого.
Затем создается новый экземпляр Generic<Bar>
и передается параметр Bar.class
.
Что вы будете делать, если параметр generic type для нового класса Generic
не является некоторым известным классом, например Bar
, но сам является параметром типового типа? Предположим, что у меня был другой класс Skeet<J>
, и я хотел создать новый экземпляр Generic<J>
изнутри этого класса. Затем, если я попытаюсь пройти в J.class
, я получаю следующую ошибку компилятора:
cannot select from a type variable.
Есть ли способ обойти это?
Конкретный бит кода, вызывающий ошибку для меня:
public class InputField<W extends Component & WidgetInterface>
extends InputFieldArray<W>
{
public InputField(String labelText)
{
super(new String[] {labelText}, W.class);
}
/* ... */
}
public class InputFieldArray<W extends Component & WidgetInterface>
extends JPanel
{
/* ... */
public InputFieldArray(String[] labelText, Class<W> clazz)
throws InstantiationException, IllegalAccessException
{
/* ... */
for (int i = 0 ; i < labelText.length ; i++) {
newLabel = new JLabel(labelText[i]);
newWidget = clazz.newInstance();
/* ... */
}
/* ... */
}
/* ... */
}
Ошибка происходит, потому что я не могу написать W.class
. Есть ли другой способ передачи в той же информации?
Ответы
Ответ 1
Использование .class
в параметре типа недопустимо - из-за типа erasure, W
будет стерто до Component
во время выполнения. InputField
необходимо также взять Class<W>
от вызывающего, например InputFieldArray
:
public InputField(String labelText, Class<W> clazz)
{
super(new String[] {labelText}, clazz);
}
Ответ 2
W может быть недоступен из-за стирания типа. Вы должны потребовать, чтобы в метод был передан Class<W>
. Вы получаете объект класса, и его общий способ гарантирует, что из-за ковариации передается только W
и никакого подкласса.
public InputField(String labelText, Class<W> cls)
{
super(new String[] {labelText}, cls);
}
возьмет W.class
, но не WSubtype.class
.
Ответ 3
Я сделал это вот так:
Это определение моего класса:
public class ManagerGeneric <T> {
Это в моем методе:
// Get the type of generic parameter
Type typeOfT = new TypeToken<T>(){}.getType();
// Deserialize
T data = gson.fromJson(json, typeOfT);