use*_*215 10 java generics covariance
根据我的理解,java中的以下泛型函数:
public static <T> T f(T x) {
Integer[] arr = new Integer[4];
T ret = (T) arr[2];
return ret;
}
Run Code Online (Sandbox Code Playgroud)
编译为以下形式(因为它是无界的):
public static Object f(Object x) {
Integer[] arr = new Integer[4];
Object ret = (Object) arr[2];
return ret;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我运行以下语句时,编译器能够确定返回值为Integer类型.编译器如何解决这个问题?
Integer i = f(new Integer(4));
Run Code Online (Sandbox Code Playgroud)
对于上述声明,该函数是否应该写成以下函数?
public static <T extends Integer> T f(T x) {
Integer[] arr = new Integer[4];
T ret = (T) arr[2];
return ret;
}
Run Code Online (Sandbox Code Playgroud)
泛型使用类型擦除.这基本上意味着泛型只不过是隐式转换,所以当你这样做时:
List<Integer> ...
Run Code Online (Sandbox Code Playgroud)
它与正常情况没什么不同List
,可能Integer
真的包含s或任何东西.你只是告诉Java的投get()
给Integer
(和其他东西).该类型在运行时(大多数情况下)不会保留.
数组是不同的.数组是所谓的协变.这意味着它们的类型在运行时保留.所以你可以这样做:
List<Integer> list1 = new ArrayList<Integer>();
list2 = (List<String>)list1;
list2.add("hello");
Run Code Online (Sandbox Code Playgroud)
这是完全合法的,将编译和运行.但:
Integer[] arr1 = new Integer[10];
String[] arr2 = (String[])arr1; // compiler error
Run Code Online (Sandbox Code Playgroud)
但它也比这更微妙.
Integer[] arr1 = new Integer[10];
Object[] arr2 = (Object[])arr1;
arr2[5] = "hello"; // runtime error!
Run Code Online (Sandbox Code Playgroud)
至于你的功能.当你写:
public static <T> T f(T x) {
Integer[] arr = new Integer[4];
T ret = (T) arr[2];
return ret;
}
Run Code Online (Sandbox Code Playgroud)
你告诉编译器T
从参数派生出来,作为参数类型和返回类型.所以当你传入一个Integer
返回类型是Integer
.你打电话的时候:
Integer i = f(new Integer(4));
Run Code Online (Sandbox Code Playgroud)
编译器只是按照你的指示.该函数确实采用并Object
以编译形式返回,但它只是这样做:
Integer i = (Integer)f(new Integer(4));
Run Code Online (Sandbox Code Playgroud)
含蓄.
就像List
上面的例子一样,没有什么可以阻止你f()
返回任何你想要的东西而不是根据参数化类型返回的东西.
在这个主题上有更多知识的人可能会稍后进入,同时我的谦虚解释是这样的:
你说的是对的,泛型有类型擦除,这意味着通用信息在运行时不可用.但是它可以在编译时使用,这就是编译器可以判断出你是混合类型的方式.
希望有所帮助!