Java泛型方法不起作用 - 参数不受限制

Cod*_*755 1 java generics

说我有这个代码:

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.

那么,为什么编译器让我传递StringIntegerpick

MTC*_*ter 5

这两个StringInteger是的子类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之前必须做的事情,以及丰富的转换和异常捕获.

24将无法编译:

error: incompatible types: inferred type does not conform to upper bound(s)
Run Code Online (Sandbox Code Playgroud)

由于这两个参数pick()只能共享Object一个共同的超类型,T变得ObjectObject返回,你不能分配Object给一个String或一个Integer.

3虽然工作得很好.两个参数都具有相同的类型,因此T很容易确定String.5出于类似的原因.

6也有效,但不是因为T变成了int.int是一种原始类型,因此不能用于泛型.在尝试解析泛型类型时T,编译器首先将原始参数自动装箱为"真实"类(Integer在本例中).这也发生在45,甚至当你只是分配一个文字像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工作正如您所期望的那样.