为什么java中的这个通用代码会编译?

The*_*Guy 10 java

public static <T> T foo(T x, T x2) {
    return (T) (x + "   " + x2);
}

public static void main(String args[]) {
    System.out.println(foo(33, "232"));
}
Run Code Online (Sandbox Code Playgroud)

我知道T会成为参数中传递的类型.但这里有两种类型.哪一个是T?

当我调用foo时,编译器为什么不强迫我拥有相同类型的参数?

khe*_*ood 16

这是合法的,因为IntegerString有一个共同的基本类型.T可以Object,所以foo(T, T)将接受任何两个对象.32可以自动装箱到一个Integer,这是一种Object."232"是一种String,这是一种Object.

(正如评论所指出的那样,对于IntegerString,有一个更接近的共同基类型,Serializable但原则与编译器解析的基本类型相同T.)


And*_*ner 5

public static <T> T foo(T x, T x2) {
    return (T) (x + "   " + x2);
}
Run Code Online (Sandbox Code Playgroud)

应该注意的是,虽然这个编译,但它可能在运行时失败:

int f = foo(1, 2);
Run Code Online (Sandbox Code Playgroud)

将失败Ideone demo,因为该方法返回一个String,而不是一个Integer.

但是,它编译,因为类型擦除意味着T重写到上限,即Object.所以:

public static Object foo(Object x, Object x2) {
  return (Object) (x + "   " + x2);
}
Run Code Online (Sandbox Code Playgroud)

这很好,因为结果是a String,这是一个子类型Object.

我想这只是一个仿制药模型等待赶上你的情况.这就是为什么我会避免混合泛型和显式铸造.