use*_*844 6 java diamond-operator
class A {}
class B extends A {}
class Holder<T> {
T object;
Holder(T object) {
this.object = object;
}
}
Run Code Online (Sandbox Code Playgroud)
有一个Holder类来保存一些使用泛型创建的对象.在main()中,当使用菱形运算符初始化时,它不会编译(Java 7),派生类传递给Holder的构造函数(需要A /找到B):
public static void main(String[] args) {
Holder<A> holder = new Holder<>(new B());
}
Run Code Online (Sandbox Code Playgroud)
但是,如果在右侧部分指定了基本类型,它将编译并运行:
public static void main(String[] args) {
Holder<A> holder = new Holder<A>(new B());
}
Run Code Online (Sandbox Code Playgroud)
为什么?钻石操作员是否使用与左侧相同的类型参数定义赋值的右侧部分?
首先观察:
Holder<B> h = new Holder<>(new B());
Run Code Online (Sandbox Code Playgroud)
使用Java 8和Java 7编译,并Holder<B>在这种情况下创建.所以使用<>带有参数的构造函数是可以的.
然而:
Holder<A> h = new Holder<>(new B());
Run Code Online (Sandbox Code Playgroud)
Holder<B>并给出编译错误,因为a Holder<B>无法转换为aHolder<A>.new Holder<A>(new B())可以实际工作并自动神奇地完成.这要归功于一个名为"目标类型"的新功能 - 请参阅教程的最后一部分,了解类型推断的概述.更详细地说,Java 8的改进是由于poly表达式的引入(强调我的):
独立表达式的类型可以完全根据表达式的内容来确定; 相反,poly表达式的类型可能受表达式的目标类型(§5(转换和上下文))的影响.
这是Java 8的一个非常强大的功能(Java 7仅提供不考虑表达式上下文的独立表达式).
泛型类实例创建是一个多义表达式,JLS#15.9解释了(强调我的):
如果类实例创建表达式使用菱形表示类的类型参数,它就出现在赋值上下文或调用上下文中(第5.2节,第5.3 节),它是一个多表达式(第15.2 节).否则,它是一个独立的表达式.
由于这个新规则,Java 8允许您使用上面的第二个表单并自动推断new B()应该被视为A(加宽引用转换)并且您打算Holder<A>在该上下文中创建一个.