Универсальное использование типа стирания.По сути, это означает, что генерики являются не более чем неявными приведениями, поэтому когда вы делаете:
List<Integer> ...
, это ничем не отличается от нормального List
и может содержать Integer
с или что-то еще.Вы просто говорите Java, чтобы привести get()
к Integer
(и другим вещам).Тип просто не сохраняется во время выполнения (в основном).
Массивы различны.Массивы - это то, что называется ковариант .Это означает, что их тип сохраняется во время выполнения.Таким образом, вы можете сделать:
List<Integer> list1 = new ArrayList<Integer>();
list2 = (List<String>)list1;
list2.add("hello");
, что совершенно законно и будет компилироваться и запускаться.Но:
Integer[] arr1 = new Integer[10];
String[] arr2 = (String[])arr1; // compiler error
Но это становится более тонким, чем это.
Integer[] arr1 = new Integer[10];
Object[] arr2 = (Object[])arr1;
arr2[5] = "hello"; // runtime error!
Что касается вашей функции.Когда вы пишете:
public static <T> T f(T x) {
Integer[] arr = new Integer[4];
T ret = (T) arr[2];
return ret;
}
, вы указываете компилятору выводить T
, являющийся типом аргумента и типом возврата, из аргумента.Поэтому, когда вы передаете Integer
, тип возвращаемого значения Integer
.Когда вы звоните:
Integer i = f(new Integer(4));
, компилятор просто следует вашим инструкциям.Функция принимает и возвращает Object
в скомпилированном виде, но просто делает это:
Integer i = (Integer)f(new Integer(4));
неявно.
Как и в примере List
, описанном выше, у вас ничего не останавливаетсяf()
возвращает все, что вам нравится, а не то, что он должен возвращать, основываясь на параметризованном типе.