如何在java中实现泛型函数?

时间:2010-02-03 02:59:18

标签: java generics covariance

根据我的理解,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;
    }

3 个答案:

答案 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类型参数信息。