6
class A {}

class B extends A {}

class Holder<T> {

    T object;

    Holder(T object) {
        this.object = object;
    }
}

有一个 Holder 类来保存一些使用泛型创建的对象。在 main() 中,当使用菱形运算符初始化时,它不会编译(Java 7),派生类传递给 Holder 的构造函数(需要 A / found B):

public static void main(String[] args) {    
    Holder<A> holder = new Holder<>(new B());        
}

但是如果在右侧指定了基本类型,它就会编译并工作:

public static void main(String[] args) {
    Holder<A> holder = new Holder<A>(new B());
}

为什么?菱形运算符不使用与左侧相同的类型参数定义赋值的右侧部分吗?

4

2 回答 2

8

第一个观察:

Holder<B> h = new Holder<>(new B());

使用 Java 8 和 Java 7 编译,并且都Holder<B>在该场景中创建。因此,将 a<>与带有参数的构造函数一起使用是可以的。

但是:

Holder<A> h = new Holder<>(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>在该上下文中创建 a。

于 2014-05-07T21:35:12.803 回答
1

你会得到

Type mismatch: cannot convert from Holder<B> to Holder<A>

原因是,

new Holder<>(new B()); 

将调用构造函数Holder(T object),它将设置<T>B您的左手赋值匹配的类型Holder<A> holder

如果您将左手类型更改为,Holder<B> holder或者Holder<? extends A> holder即使没有在右侧<>括号中输入类型,它也可以正常工作。

记住B是的子类A,所以A可以持有的引用,B这就是为什么

Holder<A> holder = new Holder<A>(new B());

或者

Holder<? extends A> holder = new Holder<>(new B());

已验证

于 2014-05-07T20:58:00.937 回答