说我有这个代码:
class Demo
{
static <T> T pick(T a1, T a2)
{
return a2;
}
public static void main(String[] args)
{
pick("d", 123);
}
}
Run Code Online (Sandbox Code Playgroud)
从我所学到的,似乎我已经说过两个参数a1,a2并且返回类型pick必须在同一个泛型类型下T.
那么,为什么编译器让我传递String和Integer来pick?
这两个String和Integer是的子类Object,在Java中所有其他类型一起.在编译泛型方法(或类)时,Java会尝试查找泛型类型的每个实例之间共享的最接近的超类型.这部分永远不会失败,因为Object存在.但是如果解决了泛型类型Object,它可能就不再有用了.
那么如果编译器允许使用任何类型,那么在这里使用泛型有什么意义呢?这与返回类型有关.假设您的定义pick(),当您尝试编译这些行时,您认为会发生什么?
Object o = pick("Hello", 123); // 1
String s = pick("Hello", 123); // 2
String s = pick("Hello", "world"); // 3
Integer i = pick("Hello", 123); // 4
Integer i = pick(123, 456); // 5
int i = pick(123, 456); // 6
Run Code Online (Sandbox Code Playgroud)
1编译得很好,但是你丢失了任何有用的类型信息.如果你根本不使用泛型,那就会发生这种情况,而只是用于Object所有事情.这是你在Java 5之前必须做的事情,以及丰富的转换和异常捕获.
2和4将无法编译:
error: incompatible types: inferred type does not conform to upper bound(s)
Run Code Online (Sandbox Code Playgroud)
由于这两个参数pick()只能共享Object一个共同的超类型,T变得Object和Object返回,你不能分配Object给一个String或一个Integer.
3虽然工作得很好.两个参数都具有相同的类型,因此T很容易确定String.5出于类似的原因.
6也有效,但不是因为T变成了int.int是一种原始类型,因此不能用于泛型.在尝试解析泛型类型时T,编译器首先将原始参数自动装箱为"真实"类(Integer在本例中).这也发生在4和5,甚至当你只是分配一个文字像Integer i = 123;.这里的不同之处在于结果(a Integer)被取消装箱,int以便可以分配给它i.
在您的示例实现中pick(),返回值应与第二个参数具有相同的类型.如果您的API指定结果始终主要来自该参数,则可以使用两种泛型类型:
static <T, U> T pick(U a1, T a2) {
return a2;
}
Run Code Online (Sandbox Code Playgroud)
通过这个添加,2仍然无法编译,但4工作正如您所期望的那样.
| 归档时间: |
|
| 查看次数: |
64 次 |
| 最近记录: |