Вы совсем близко.Время компиляции проверяет все панорамирование:
a
имеет тип List
, поэтому вызов
a.add("test");
завершается.b
относится к типу (время компиляции) ArrayList<Integer>
, поэтому
b.get(0)
также проверяется.Обратите внимание, что проверки выполняются только для типов переменных во время компиляции.Когда компилятор видит a.add("test")
, он не знает значение времени выполнения объекта, на который ссылается переменная a
.В общем, это действительно невозможно (в теоретической информатике есть результат), хотя анализ типа потока управления может уловить многих таких вещей.Такие языки, как TypeScript, могут делать удивительные вещи во время компиляции.
Теперь вы можете предположить, что во время выполнения такие вещи могут быть проверены.Увы, на Яве они не могут.Java стирает универсальные типы.Найдите статью о стирании типов Java для более подробной информации.TL; DR - то, что List<Integer>
во время компиляции становится необработанным List
во время выполнения.У JVM не было способа «переопределить» дженерики (хотя это делают другие языки!), Поэтому, когда дженерики были представлены, было принято решение, что Java просто удалит дженерики.Поэтому во время выполнения в вашем коде нет проблем с типами.
Давайте посмотрим на скомпилированный код:
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: astore_2
10: aload_2
11: ldc #4 // String test
13: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
18: pop
19: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
22: aload_1
23: iconst_0
24: invokeinterface #7, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
29: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
32: return
Здесь вы можете непосредственно увидеть, что нет никаких проверок типов во время выполнения.Итак, полный (но, казалось бы, легкомысленный) ответ на ваш вопрос заключается в том, что Java проверяет только типы во время компиляции на основе типов переменных (известных во время компиляции), но параметры универсальных типов стираются икод запускается без них.