6
class A {}

class B extends A {}

class Holder<T> {

    T object;

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

ジェネリックを使用して作成されたオブジェクトを保持するための Holder クラスがあります。main() では、ダイヤモンド演算子を使用して初期化すると、ホルダーのコンストラクターに渡された派生クラスでコンパイルされません (Java 7) (必要な A / 見つかった 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 を作成します。したがって、<>引数を取るコンストラクターで a を使用しても問題ありません。

ただし、次の場合:

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

より詳細には、Java 8 での改善は、poly 式の導入によるものです(強調は私のものです)。

スタンドアロンの式の型は、式の内容から完全に決定できます。対照的に、poly 式の型は、式のターゲット型の影響を受ける場合があります(§5 (変換とコンテキスト))。

これは Java 8 の非常に強力な機能です (Java 7 は、式のコンテキストを考慮しないスタンドアロンの式のみを提供します)。

ジェネリック クラス インスタンスの作成は poly 式であり、JLS #15.9で説明されています (強調は私のものです)。

クラス インスタンス作成式は、クラスへの型引数にひし形形式を使用し、代入コンテキストまたは呼び出しコンテキスト (§5.2、§5.3) に現れる場合、poly 式 (§15.2) です。それ以外の場合は、スタンドアロンの式です。

その新しいルールにより、Java 8 では上記の 2 番目の形式を使用できるようになり、 (拡張参照変換)new B()として扱われるべきであり、そのコンテキストでa を作成するつもりだったことが自動的に推測されます。AHolder<A>

于 2014-05-07T21:35:12.803 に答える