477

Java 7 のダイヤモンド演算子は、次のようなコードを許可します。

List<String> list = new LinkedList<>();

ただし、Java 5/6 では、次のように簡単に記述できます。

List<String> list = new LinkedList();

型消去についての私の理解では、これらはまったく同じです。(とにかくジェネリックは実行時に削除されます)。

なぜダイヤモンドを気にするのですか?どのような新しい機能/タイプ セーフが許可されますか? 新しい機能が得られない場合、なぜ彼らはそれを機能として言及するのですか? この概念に対する私の理解は間違っていますか?

4

7 に答える 7

524

の問題

List<String> list = new LinkedList();

左側ではジェネリック型を使用List<String>していますが、右側では生の型を使用していますLinkedList。Java の生の型は、事実上、ジェネリック前のコードとの互換性のためにのみ存在し、絶対に必要な場合を除き、新しいコードでは決して使用しないでください。

ここで、Java が最初からジェネリックを持っていて、ジェネリックを持つLinkedList前に最初に作成された などの型を持っていなかった場合、ジェネリック型のコンストラクターがその型パラメーターを左から自動的に推論するようにすることができたはずです。 -可能であれば、割り当ての側を渡します。しかし、そうではなく、下位互換性のために生の型とジェネリック型を異なる方法で処理する必要があります。そのため、型パラメータを繰り返さずにジェネリック オブジェクトの新しいインスタンスを宣言する、わずかに異なるが同様に便利な方法を作成する必要があります... ダイヤモンド演算子です。

の元の例に関する限りList<String> list = new LinkedList()、コンパイラはその割り当てに対して警告を生成する必要があるためです。このことを考慮:

List<String> strings = ... // some list that contains some strings

// Totally legal since you used the raw type and lost all type checking!
List<Integer> integers = new LinkedList(strings);

ジェネリックは、間違ったことを行うことに対するコンパイル時の保護を提供するために存在します。上記の例では、生の型を使用すると、この保護が得られず、実行時にエラーが発生します。これが生の型を使用すべきでない理由です。

// Not legal since the right side is actually generic!
List<Integer> integers = new LinkedList<>(strings);

ただし、ひし形演算子を使用すると、割り当ての右側を、左側と同じ型パラメーターを持つ真のジェネリック インスタンスとして定義できます。これらのパラメーターを再度入力する必要はありません。raw 型を使用するのとほぼ同じ労力で、ジェネリックの安全性を維持できます。

理解すべき重要なことは、生の型 ( なし<>) はジェネリック型と同じように扱うことができないということです。生の型を宣言すると、ジェネリックの利点と型チェックがまったく得られません。また、ジェネリクスは Java 言語の汎用的な部分であることも覚えておく必要があります。ジェネリクスは s の引数なしのコンストラクタだけに適用されるわけではありませんCollection!

于 2010-11-12T17:03:32.140 に答える
40

あなたの理解には少し欠陥があります。ひし形演算子は、同じことを繰り返す必要がないため、優れた機能です。型を宣言するときに型を一度定義するのは理にかなっていますが、右側で再度定義するのは意味がありません。DRYの原則。

ここで、型の定義に関するあいまいさをすべて説明します。実行時に型が削除されるのは正しいですが、型定義を使用してリストから何かを取得したい場合は、リストを宣言するときに定義した型としてそれを取得します。そうしないと、すべての特定の機能が失われ、取得したオブジェクトを元の型にキャストする場合を除き、オブジェクトの機能は非常に扱いにくく、ClassCastException が発生する場合があります。

を使用List<String> list = new LinkedList()すると、rawtype の警告が表示されます。

于 2010-11-12T16:52:25.087 に答える
16

この行により、[unchecked] 警告が発生します。

List<String> list = new LinkedList();

新しいコレクションが作成された場合にのみ、[チェックされていない] 警告が自動的に抑制されないのはなぜですか?

機能を追加するよりもはるかに難しい作業になると思います<>

UPD :生の型を「ほんの少しのこと」のために合法的に使用することが合法であるとしたら、混乱が生じると思います。

于 2010-11-12T16:51:45.393 に答える
12

理論的には、ダイヤモンド演算子を使用すると、繰り返される型引数を保存することで、よりコンパクトな (そして読みやすい) コードを記述できます。実際には、紛らわしい文字が 2 つ増えるだけで、何も得られません。なんで?

  1. 新しいコードで生の型を使用する正気のプログラマーはいません。したがって、コンパイラは、型引数を記述しないことで、それらを推論したいと単純に想定できます。
  2. ダイヤモンド演算子は型情報を提供せず、コンパイラに「大丈夫です」と言うだけです。したがって、省略しても害はありません。ダイヤモンド演算子が合法である場所では、コンパイラによって「推論」される可能性があります。

私見ですが、ソースを Java 7 としてマークするための明確で簡単な方法があることは、そのような奇妙なことを発明するよりも便利です。そのようにマークされたコードでは、何も失うことなく未加工の型を禁止できます。

ところで、コンパイルスイッチを使用して行うべきではないと思います。プログラム ファイルの Java バージョンはファイルの属性であり、オプションはまったくありません。次のような些細なことを使用する

package 7 com.example;

明確にすることができます (1 つ以上の派手なキーワードを含む、より洗練されたものを好む場合があります)。異なる Java バージョン用に書かれたソースを一緒に問題なくコンパイルすることもできます。これにより、互換性を失うことなく、新しいキーワード (「モジュール」など) を導入したり、廃止された機能 (1 つのファイル内の複数の非パブリックでネストされていないクラスなど) を削除したりできます。

于 2011-01-19T11:37:00.170 に答える
8

を記述するList<String> list = new LinkedList();と、コンパイラは「チェックされていない」警告を生成します。無視してもかまいませんが、これらの警告を無視していた場合は、実際の型安全性の問題について通知する警告を見逃す可能性があります。

したがって、余分な警告を生成しないコードを作成することをお勧めします。ダイアモンド演算子を使用すると、不要な繰り返しなしで便利な方法でコードを実行できます。

于 2010-11-12T16:53:57.753 に答える
4

他の回答で述べられていることはすべて有効ですが、ユースケースは完全に有効ではありません。Guava 、特にコレクション関連のものをチェックアウトすると、同じことが静的メソッドで行われました。たとえば、 Lists.newArrayList()を使用すると、次のように記述できます

List<String> names = Lists.newArrayList();

または静的インポート

import static com.google.common.collect.Lists.*;
...
List<String> names = newArrayList();
List<String> names = newArrayList("one", "two", "three");

Guava にはこのような非常に強力な機能が他にもありますが、実際には <> の用途はあまり思いつきません。

ひし形の演算子の動作をデフォルトにする、つまり、式の左側から型が推論されるか、左側から型が推論される場合は、より便利でした。後者は Scala で起こることです。

于 2012-01-04T11:29:32.420 に答える
3

ダイヤモンド演算子のポイントは、ジェネリック型を宣言するときにコードの入力を減らすことです。ランタイムにはまったく影響しません。

Java 5 と 6 で指定した場合の唯一の違いは、

List<String> list = new ArrayList();

に指定する必要があるということです@SuppressWarnings("unchecked")listそうしないと、チェックされていないキャストの警告が表示されます)。私の理解では、ダイヤモンド オペレーターは開発を容易にしようとしています。ジェネリックの実行時実行にはまったく関係ありません。

于 2010-11-12T16:57:14.840 に答える