如果我有课程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
是一个字符串?
答案 0 :(得分:10)
因为构造函数可以被认为是一个特殊的实例方法,所以它不是类型化的 - 它从类名(带有类型参数)获取它的类型,例如Foo<String>
。即构造函数未定义为:
public <T> Foo(T t) ...
也不是。这样做会隐藏类的泛型类型(并且会收到警告)
静态方法是类型。 FYI,一般推断类型的泛型无参数调用,相当于:
Foo.<String>bar("String");
答案 1 :(得分:3)
当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")
。请参阅this section of the same article。
答案 2 :(得分:1)
我认为你需要这样做
new Foo<String>("String");
告诉获取通用信息;类似于Collections API。
答案 3 :(得分:1)
调查一下,我将在这里猜测一下。请考虑以下事项:
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
的类型。就像你期望它在方法案例中发生一样。但是,您获得的错误不是因为没有推断出参数类型,而是因为无法推断出类的原始类型。
我认为这归结为类原始类型可以传播到方法,但方法不能使用推理设置类原始类型。
答案 4 :(得分:1)
new Foo(s)
的类型为raw Foo
,用于向后兼容性。
Java7的构造函数菱形类型推断(new Foo<>(s)
)与方法的方法类型推断相同,并在其中定义。
http://cr.openjdk.java.net/~darcy/ProjectCoin/ProjectCoin-Documentation-v0.9375.html#diamond
如果类实例创建表达式使用“&lt;&gt;”为了省略类类型参数,为了重载解析和类型参数推断,定义了方法列表m1 ... mk ...
...然后使用§15.12.2(确定方法签名)中描述的过程选择m1 ... mk中的一个
你的怀疑是正确的,构造函数可以像方法一样使用推理,没有本质区别。由于向后兼容性问题,您只需添加<>
。
为什么用Java 6年来添加此功能是另一回事。