java java中泛型函数是如何实现的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2189370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 19:56:12  来源:igfitidea点击:

How is generic function implemented in java?

javagenericscovariance

提问by user236215

As per my understanding the following generic function in java:

根据我的理解,java中的以下通用函数:

public static <T> T f(T x) {
   Integer[] arr = new Integer[4];
   T ret = (T) arr[2];
   return ret;
}

is compiled to the following form (as it is unbounded):

被编译为以下形式(因为它是无界的):

public static Object f(Object x) {
   Integer[] arr = new Integer[4];
   Object ret = (Object) arr[2];
   return ret;
}

However, when I run the following statement, the compiler is able to figure out the return value to be Integer type. How does the compiler figure it out?

但是,当我运行以下语句时,编译器能够确定返回值是 Integer 类型。编译器是如何计算出来的?

Integer i = f(new Integer(4));

Shouldn't the function be written as following for the above statement to work?

为了使上述语句起作用,该函数不应该如下编写吗?

  public static <T extends Integer> T f(T x) {
       Integer[] arr = new Integer[4];
       T ret = (T) arr[2];
       return ret;
    }

采纳答案by cletus

Generics use type erasure. That basically means that generics are nothing more than implicit casts so when you do:

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

List<Integer> ...

it's no different to a normal Listand may contain Integers or anything really. You're just telling Java to cast get()to an Integer(and other things). The type simply isn't retained at runtime (mostly).

它与普通的没有什么不同List,可能Integer真的包含s 或任何东西。您只是告诉 Java 强制get()转换为Integer( 和其他东西)。该类型在运行时根本不保留(大多数情况下)。

Arrays are different. Arrays are what's called covariant. That means their type is retained at runtime. So you can do:

数组不一样。数组就是所谓的covariant。这意味着它们的类型在运行时保留。所以你可以这样做:

List<Integer> list1 = new ArrayList<Integer>();
list2 = (List<String>)list1;
list2.add("hello");

which is perfectly legal and will compile and run. But:

这是完全合法的,可以编译和运行。但:

Integer[] arr1 = new Integer[10];
String[] arr2 = (String[])arr1; // compiler error

But it gets more subtle than that too.

但它也变得更加微妙。

Integer[] arr1 = new Integer[10];
Object[] arr2 = (Object[])arr1;
arr2[5] = "hello"; // runtime error!

As to your function. When you write:

至于你的功能。当你写:

public static <T> T f(T x) {
  Integer[] arr = new Integer[4];
  T ret = (T) arr[2];
  return ret;
}

you're telling the compiler to derive T, being the argument type and the return type, from the argument. So when you pass in an Integerthe return type is Integer. When you call:

您告诉编译器T从参数派生,即参数类型和返回类型。所以当你传入一个时Integer,返回类型是Integer. 你打电话的时候:

Integer i = f(new Integer(4));

the compiler is simply following your instructions. The function does take and return an Objectin compiled form but it just does this:

编译器只是按照您的指示进行操作。该函数确实以Object编译形式接受并返回一个,但它只是这样做:

Integer i = (Integer)f(new Integer(4));

implicitly.

含蓄地。

Just like the Listexample above there is nothing stopping you have f()return anything you like rather than what it's supposed to return based on the parameterized type.

就像List上面的例子一样,没有什么可以阻止你f()返回任何你喜欢的东西,而不是它应该根据参数化类型返回的东西。

回答by Pablo Fernandez

Somebody with more knowledge in this topic might jump in later, meanwhile my humble explanation is this:

对这个话题有更多了解的人可能会在稍后加入,同时我的谦虚解释是这样的:

What you say is right, generics have type erasurewhich means that generic information is not available at runtime. It ishowever available at compiletime and that's how the compiler can figure out that you're mixing types.

你说的是对的,泛型具有类型擦除,这意味着泛型信息在运行时不可用。然而,编译时可用,这就是编译器如何确定您正在混合类型的方式。

Hope that helps!

希望有帮助!

回答by Jord?o

In your example, the compiler figures that the return type is the same type as the parameter passed to the function, since they're both parameterized to type T, which is resolved to be Integer. When generating the bytecode, it then erasesthe type parameters information.

在您的示例中,编译器认为返回类型与传递给函数的参数类型相同,因为它们都被参数化为类型 T,该类型被解析为Integer. 在生成字节码时,它会擦除类型参数信息。