Java: экспериментирование с дженериками
Наконец, я немного экспериментирую с дженериками. Я придумал этот фрагмент кода:
public class Test {
static <T> void f(T x) {
x = (T) (Integer) 1234;
System.out.println(x);
}
public static void main(String[] args) {
f("a");
f(1);
f('a');
f(1.5);
f(new LinkedList<String>());
f(new HashMap<String, String>());
}
}
Я запустил это и получил этот вывод:
1234
1234
1234
1234
1234
1234
без исключений! Как это возможно?
Ответы
Ответ 1
Это из-за типа стирания (об этом написано много, просто Google для этого термина). После компиляции f
в байтовый код метод может выглядеть следующим образом:
static void f(Object x) {
x = (Object) (Integer) 1234;
System.out.println(x);
}
Итак System.out.println
просто вызовет метод toString
на объекте x
- и в вашем случае это Integer.toString()
.
Ответ 2
Из-за типа Erasure. Из Документация Oracle:
На язык Java были введены обобщения для обеспечения более жесткого типа проверяет время компиляции и поддерживает универсальное программирование. к реализовать generics, компилятор Java применяет стирание типа к:
-
Заменить все параметры типа в родовых типах своими границами или Объект, если параметры типа не ограничены. Произведенный байт-код, поэтому содержит только обычные классы, интерфейсы и методы.
-
При необходимости введите тип приведения, чтобы сохранить безопасность типа.
- Создание мостовых методов для сохранения полиморфизма в расширенных общих типах.
Стирание стилей гарантирует, что новые классы не будут созданы для параметризованных типы; следовательно, дженерики не имеют накладных расходов во время выполнения.