根据我的理解,java中的以下泛型函数:
public static <T> T f(T x) {
Integer[] arr = new Integer[4];
T ret = (T) arr[2];
return ret;
}
编译为以下形式(因为它是无界的):
public static Object f(Object x) {
Integer[] arr = new Integer[4];
Object ret = (Object) arr[2];
return ret;
}
但是,当我运行以下语句时,编译器能够确定返回值为Integer类型。编译器如何解决这个问题?
Integer i = f(new Integer(4));
上述语句不能写成以下函数吗?
public static <T extends Integer> T f(T x) {
Integer[] arr = new Integer[4];
T ret = (T) arr[2];
return ret;
}
答案 0 :(得分:7)
泛型使用类型擦除。这基本上意味着泛型只不过是隐式转换,所以当你这样做时:
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()
返回任何你喜欢的内容,而不是基于参数化类型返回的内容。
答案 1 :(得分:6)
在这个主题上有更多知识的人可能会稍后进入,同时我的谦虚解释是:
你说的是对的,泛型有类型擦除,这意味着通用信息在运行时不可用。然而 时可以在编译时获得,这就是编译器可以判断出你是混合类型的方式。
希望有所帮助!
答案 2 :(得分:2)
在您的示例中,编译器认为返回类型与传递给函数的参数的类型相同,因为它们都被参数化为类型T,它被解析为Integer
。生成字节码时,然后erases类型参数信息。