类型推断如何用于方法调用?

时间:2018-04-24 17:46:20

标签: java generics

考虑以下示例:

public class Learn {
    public static <T> T test (T a, T b) {
        System.out.println(a.getClass().getSimpleName());
        System.out.println(b.getClass().getSimpleName());
        b = a;
        return a;
    }

    public static void main (String[] args) {
        test("", new ArrayList<Integer>());
    }
}

main方法中,我使用testString对象调用ArrayList <Integer>。两者都是不同的东西,并将ArrayList分配给String(通常)会产生编译错误。

String aString = new ArrayList <Integer> (); // won't compile

但是我在test的第3行正是这样做的,程序编译并运行正常。首先,我认为类型参数T被替换为与StringArrayList兼容的类型(如Serializable)。但println内的两个test语句分别将“{1}}和a打印为”{1}}和“{{}}”。我的问题是,如果b在运行时aStringb,我们如何将ArrayList分配给a

2 个答案:

答案 0 :(得分:10)

对于通用方法,Java编译器ab都将infer the most specific common type

  

推理算法确定参数的类型,如果可用,还确定分配或返回结果的类型。最后,推理算法试图找到适用于所有参数的特定类型。

您没有将test的调用结果分配给任何内容,因此没有影响推理的目标。

在这种情况下,即使StringArrayList<Integer>也有一个共同的超类型Serializable,因此T被推断为Serializable,您始终可以指定一个相同类型的变量到另一个变量。对于其他示例,您甚至可以将Object视为常见的超类型。

但仅仅因为你有T类型的变量推断为Serializable,对象本身仍然是StringArrayList,所以得到他们的类和打印他们的名字仍会打印StringArrayList。你不打印变量的类型;你正在打印对象的类型。

答案 1 :(得分:4)

test("", new ArrayList<Integer>());

这相当于以下内容:

Learn.test("", new ArrayList<Integer>());

这也等同于以下内容:

Learn.<Serializable>test("", new ArrayList<Integer>());

如果您明确指定Serializable(或Object)以外的泛型类型,例如String,则无法编译:

Learn.<String>test("", new ArrayList<Integer>()); // DOES NOT COMPILE

因此,在您的情况下,基本上两个参数都被视为Serializable