构造函数中的泛型推理



如果我有一个类Foo:

public class Foo<T> {
    public Foo(T t) {
        //do something
    }
    public static <E> void bar(E e) {
         //do something
    }
}

为什么Foo.bar("String");推断E是一个字符串(因此不抛出编译器警告),但new Foo("String");不推断T是一个字符串?

因为构造函数可以被认为是一个特殊的实例方法,所以它不是类型化的——它从类名(带有类型参数)获取类型,例如Foo<String>。即构造函数没有定义为:

public <T> Foo(T t) ...

也不可能。这样做会使隐藏类的泛型类型(您将得到一个警告)

而静态方法类型的。仅供参考,一旦推断出类型,则无泛型参数调用相当于:
Foo.<String>bar("String");

当Java实现泛型时,决定在没有类型参数的情况下实例化的泛型类将始终返回原始类型。这与缺少类型参数的泛型方法不同,编译器会尝试推断其类型。来自Java教程:

一般来说,Java编译器可以推断出泛型方法调用的类型参数。因此,在大多数情况下,您不必指定它们。

但是当讨论转向构造函数时:

注意,要在泛型类实例化期间利用自动类型推断,必须指定菱形。在下面的例子中,编译器会生成一个未检查的转换警告,因为HashMap()构造函数引用的是HashMap原始类型,而不是Map<String, List<String>>类型:

Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning

来源:http://download.oracle.com/javase/tutorial/java/generics/gentypeinference.html

这在Java 7中保持不变,但是他们试图通过支持菱形语法来减少重复。例如:Foo<String> foo = new Foo<>("String")。请参阅同一篇文章的这一部分。

我想你需要这么做

new Foo<String>("String");

告诉获取传递的泛型信息;

考虑到这一点,我将在这里进行猜测。考虑以下内容:

public class Foo {
    public <E> Foo(E t) {
        //do something
    }
    public static <E> void bar(E e) {
         //do something
    }
}

在上面的类中,当像下面这样实例化Foo时,您不会得到任何警告:

Foo f = new Foo("String");

之所以有效,是因为这里正在推断E的类型。就像你期望在方法的情况下发生的那样。然而,您得到的错误不是因为没有推断参数类型,而是因为无法推断类的原始类型。

我认为这归结为类的原始类型可以传播到方法,但方法不能使用推断来设置类的原始类型。

@忽必烈的答案是正确的;为了向后兼容,new Foo(s)的类型是原始Foo

Java7的构造函数菱形类型推断(new Foo<>(s))与方法上的方法类型推断相同,并且是根据方法类型推断来定义的。

http://cr.openjdk.java.net/达西/ProjectCoin ProjectCoin-Documentation-v0.9375.html #钻石

如果类实例创建表达式使用"<>"要省略类类型参数,方法列表m1…Mk是为了重载解析和类型参数推断而定义的…

…然后m1中的一个…使用§15.12.2(确定方法签名)

中描述的过程选择mk。

你的怀疑是正确的,构造函数可以像方法一样使用推理,没有本质上的区别。由于向后兼容性问题,您只需要添加<>

为什么Java花了6年的时间来添加这个特性是另一回事。

最新更新