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

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)

cle*_*tus 7

泛型使用类型擦除.这基本上意味着泛型只不过是隐式转换,所以当你这样做时:

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()返回任何你想要的东西而不是根据参数化类型返回的东西.

  • 我不认为'covariant'意味着它们的类型在运行时保留...不协变和逆变与继承有关,如果子类可以取代超类? (5认同)
  • Pablo Fernandez是正确的,协方差与运行时是否保留类型无关.你正在寻找的词是"具体化的". (4认同)

Pab*_*dez 6

在这个主题上有更多知识的人可能会稍后进入,同时我的谦虚解释是这样的:

你说的是对的,泛型有类型擦除,这意味着通用信息在运行时不可用.但是可以在编译时使用,这就是编译器可以判断出你是混合类型的方式.

希望有所帮助!