Когда вы пишете цепочку вызовов метода:
System.out.println(t.second.getClass().getSimpleName());
компилятор эффективно расширяет это:
TypeOfTSecond tmpTSecond = t.second;
Class<?> clazzTmp = tmp.getClass();
String nameTmp = clazzTmp.getSimpleName();
System.out.println(nameTmp);
Теперь, если это произойдет, что t.second
является универсальным типом, компилятор вставит литой к типу, что это вещи t.second
будет:
Bar tmpTSecond = (Bar) t.second;
Так что, даже если вы никогда не обращаетесь к какой-либо функциональной функции Bar
, вы получите ClassCastException
.
Чтобы продемонстрировать это, вот байткодом:
public static void main(java.lang.String[]);
Code:
0: invokestatic #2 // Method Test.f:()LTuple;
3: astore_1
4: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
7: aload_1
8: getfield #4 // Field Tuple.second:Ljava/lang/Object;
11: checkcast #5 // class Bar
14: invokevirtual #6 // Method java/lang/Object.getClass:()Ljava/lang/Class;
17: invokevirtual #7 // Method java/lang/Class.getSimpleName:()Ljava/lang/String;
20: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: return
линия 8, где t.second
помещается в стек; строка 11, где происходит отливка до Bar
.
Это только происходит из-сырьевых типов, используемых при объявлении test.f()
:
static Tuple f(){return new Tuple("test", 8);}
Если бы это было правильно объявлен
static Tuple<String, Integer> f(){return new Tuple<>("test", 8);}
тогда эта линия
Tuple<String, Bar> t = Test.f();
не будет компилироваться. Но использование необработанных типов отключает проверку типа компилятора, поэтому невозможно избежать ошибок времени выполнения, подобных этому.
Основная уборка - never use raw types.
Вторичный урок обращает внимание на предупреждения вашего компилятора (или IDE). Компиляция кода, мне сказали:
Note: Main.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
и когда я перекомпилировать с этим флагом:
Main.java:19: warning: [unchecked] unchecked call to Tuple(K,V) as a member of the raw type Tuple
return new Tuple("test", 8);
^
where K,V are type-variables:
K extends Object declared in class Tuple
V extends Object declared in class Tuple
Main.java:26: warning: [unchecked] unchecked conversion
Tuple<String, Bar> t = Test.f();
^
required: Tuple<String,Bar>
found: Tuple
2 warnings
Я понимаю, что не будет работать в Java. Вашим дженерикам не дают тип, они - Дженерики. Это сработало бы, если бы у вас было что-то наподобие «public final K», и оно вернет String. –
'Test.f()' возвращает необработанный тип. Эта ошибка будет легче поймать, если вы избежите использования необработанных типов. Тип возвращаемого значения 'Test.f()' должен быть определен как 'Tuple' для соответствия возвращаемому значению. Это приведет к ошибке компиляции в 'Tuple t = Test.f()'. Тип безопасности - это мощная функция. –
Вы должны публиковать полную ошибку: 'Исключение в потоке" main "java.lang.ClassCastException: java.lang.Integer не может быть отброшен в Bar' - теперь он становится намного яснее ... – alfasin