Этот вопрос был введен qaru.site/info/845811/.... Отвечая на вопрос, с которым я столкнулся, я не мог объяснить, основываясь исключительно на спецификации
Я нашел следующее выражение в Учебниках Java на Документация Oracle:
- Вставьте тип при необходимости, чтобы сохранить безопасность типа. Учебники Java: Тип Erasure
Не объясняется, что "если необходимо" означает точно, и Я нашел никаких упоминаний об этих приведениях в Java Language Спецификация, поэтому я начал экспериментировать.
Посмотрим на следующий фрагмент кода:
// Java source
public static <T> T identity(T x) {
return x;
}
public static void main(String args[]) {
String a = identity("foo");
System.out.println(a.getClass().getName());
// Prints 'java.lang.String'
Object b = identity("foo");
System.out.println(b.getClass().getName());
// Prints 'java.lang.String'
}
Скомпилирован с javac
и декомпилирован с Java Decompiler:
// Decompiled code
public static void main(String[] paramArrayOfString)
{
// The compiler inserted a cast to String to ensure type safety
String str = (String)identity("foo");
System.out.println(str.getClass().getName());
// The compiler omitted the cast, as it is not needed
// in terms of runtime type safety, but it actually could
// do an additional check. Is it some kind of optimization
// to decrease overhead? Where is this behaviour specified?
Object localObject1 = identity("foo");
System.out.println(localObject1.getClass().getName());
}
Я вижу, что есть отливка, которая обеспечивает безопасность типа в первом случае,
но во втором случае он опускается. это
конечно, потому что я хочу сохранить возвращаемое значение в Object
типизированная переменная, поэтому приведение не является строго необходимым в соответствии с безопасностью типа. Однако это приводит к интересному поведению с небезопасными нажатиями:
public class Erasure {
public static <T> T unsafeIdentity(Object x) {
return (T) x;
}
public static void main(String args[]) {
// I would expect c to be either an Integer after this
// call, or a ClassCastException to be thrown when the
// return value is not Integer
Object c = Erasure.<Integer>unsafeIdentity("foo");
System.out.println(c.getClass().getName());
// but Prints 'java.lang.String'
}
}
Скомпилированный и декомпилированный, я не вижу приведения типов для обеспечения правильного типа возвращаемого значения во время выполнения:
// The type of the return value of unsafeIdentity is not checked,
// just as in the second example.
Object localObject2 = unsafeIdentity("foo");
System.out.println(localObject2.getClass().getName());
Это означает, что если общая функция должна возвращать объект заданного
тип, он не гарантирует, что он вернет этот тип в конечном счете.
приложение, использующее вышеуказанный код, потерпит неудачу в первой точке, где он пытается
чтобы вернуть возвращаемое значение в Integer
, если это вообще произойдет, поэтому я чувствую, что
он нарушает принцип отказоустойчивости.
Каковы точные правила компилятора, вставляющие этот листинг во время компиляция, которая обеспечивает безопасность типов и где указаны эти правила?
EDIT:
Я вижу, что компилятор не будет копаться в коде и попытаться доказать, что общий код действительно возвращает то, что он должен, но он может вставлять утверждение или, по крайней мере, типу (который он уже делает в определенных случаях, как показано в первом примере) для обеспечения правильного типа возврата, поэтому последний будет вызывать ClassCastException
:
// It could compile to this, throwing ClassCastException:
Object localObject2 = (Integer)unsafeIdentity("foo");