Впихнуть невпихуемое, или кратко о type erasure в Java на примере

Dec 1, 2013   #java  #ни о чём 

Type erasure (стирание типов) в Java — это такой однажды вставленный в язык костыль для поддержки generics — параметризации типов у классов/методов. Нужен он был для совместимости байткода с предыдущими версиями Java, а заключается он в том, что проверка на соответствие типов данных в generics производится исключительно во время компиляции, а не во время выполнения.
Из этого следует то, что можно обхитрить систему во время компиляции и попробовать этим воспользоваться для запутывания самих себя в рантайме.

Итак, код.

private static class Foo<T> {
    T value1, value2;

    public void print() {
        System.out.println(value1);
        System.out.println(value2);
    }
}

public static <T> Foo<T> create(Object o1, Object o2) {
    Foo<T> result = new Foo<T>();
    result.value1 = (T) o1;
    result.value2 = (T) o2;
    return result;
}

public static void main(String[] args) {
    Double pi = 3.14;
    String hello = "hello";
    Foo<Integer> test = create(pi, hello);
    test.print();
}

Суть кода: создаём объект класса Foo с двумя членами типа Integer, помещаем в них объекты типа Double и String и пытаемся их вывести на экран.
Логично предположить, что приложение ругнётся на этот код, так как несоответствие типов данных налицо. Однако же результатом работы будет следующий вывод:

3.14
hello

Что же случилось? Стёрлись типы. На самом деле, во время компиляции код преобразовался к виду:

private static class Foo {
    Object value1, value2;
    ...
}
...

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

comments powered by Disqus