Универсальный метод ограниченного параметра типа и стирание типа
Общий метод согласно ниже:
static <E, K extends E> void someMethod(K k, E[] e) {}
Я предположил, что при стирании тип стирания будет:
static void someMethod(Object k, Object[] e) {}
Просто интересно, как параметр type узнает ограничения после стирания типа? Этот параметр типа K ограничен E?
3 ответа
Вы правы насчет удаления. На самом деле, среда выполнения не знает об ограничениях. Только компилятор делает.
Ваша стертая подпись верна. Однако ограничения метода не стираются во время компиляции. Они кодируются в метаданных, которые используются во время компиляции (и обычно не используются во время выполнения, хотя к ним можно получить доступ посредством отражения *). Например, класс java.util.ArrayList<E>
имеет метод:
public E get(int index)
Который с type-erasure становится:
public Object get(int index)
Тем не менее, в вашем коде, если вы параметризируете ArrayList
с String
тогда вы будете называть get(...)
метод без необходимости приводить результат к String
несмотря на тип-стирание.
Это отличается от того, что происходит при параметризации вызова класса или метода. Предоставленные параметризации полностью стираются во время компиляции. Например:
ArrayList<String> myList = new ArrayList<String>();
После компиляции эквивалентно:
ArrayList myList = new ArrayList();
* Доступ к этой информации во время выполнения посредством отражения может быть сделан с использованием методов отражения, которые возвращают java.lang.reflect.Type
экземпляров. Например, чтобы получить ограничения вашего метода во время выполнения, вы можете вызвать java.lang.reflect.Method
"s getGenericParameterTypes()
метод. Обработка этой возвращенной информации позволила бы определить ограничения во время выполнения.
Хочу отметить, что на самом деле ваше ограничение типа
static <E, K extends E> void someMethod(K k, E[] e) {}
имеет тот же эффект (во время компиляции), что и
static void someMethod(Object k, Object[] e) {}
Попробуйте позвонить someMethod("foo", new Integer[3])
если ты мне не веришь.
Это потому, что компилятор может сделать вывод Object
в качестве параметров для обоих E
а также K
(поскольку любой K
Объект также является экземпляром Object
и любой E[]
Объект также является экземпляром Object[]
(помните, что типы массивов ковариантны в Java)).
Это распространенная ошибка в Java Generics. Например, Arrays.fill()
метод имеет подпись static void fill(Object[] a, Object val)
; для них не возможно ограничить это далее.