Общий параметр ограниченного типа и стирание типа

Общий метод, описанный ниже:

static <E, K extends E> void someMethod(K k, E[] e) {}

Я предполагал, что стирание будет выглядеть следующим образом:

static void someMethod(Object k, Object[] e) {}

Любопытно, как параметр type знает ограничения после стирания типа? Этот параметр типа K ограничен E?

Ответы

Ответ 1

Вы правы в стирании. Собственно, среда выполнения не знает об ограничениях. Только компилятор делает.

Ответ 2

Подтвержденная ваша подпись. Однако при компиляции ограничения метода не стираются. Они кодируются в метаданных, которые используются во время компиляции (и обычно не используются во время выполнения, хотя к нему можно получить доступ через отражение *). Например, класс java.util.ArrayList<E> имеет метод:

public E get(int index)

Что с типом стирания становится:

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 getGenericParameterTypes(). Обработка этой возвращенной информации позволит определить ограничения во время выполнения.

Ответ 3

Хочу отметить, что на самом деле ограничение типа

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 также является экземпляром Object[] (помните, что типы массивов ковариантны в Java)).

Это обычная ошибка в Java Generics. Например, метод Arrays.fill() имеет подпись static void fill(Object[] a, Object val); их невозможно ограничить.