次の間に違いはありますか:
static void findMax(LinkedList<? extends Number> list){...}
と:
static <T extends Number> void findMax(LinkedList<T> list){...}
どちらも機能するため、2つに大きな違いがあるかどうか、どちらが推奨されているかを知りたいです。
主な違いは、2 番目のバージョンでは型にアクセスできるのT
に対し、最初のバージョンではアクセスできないことです。
たとえば、T にリンクされたものを返したい場合があります (たとえば、void の代わりに T を返す)。
static <T extends Number> T findMax(LinkedList<T> list){...}
または、Ts の新しいリストを作成する必要がある場合があります。
static <T extends Number> void findMax(LinkedList<T> list){
List<T> copyAsArrayList = new ArrayList<> (list);
//do something with the copy
}
にアクセスする必要がない場合T
、どちらのバージョンも機能的に同等です。
最初のものfindMax
は、特定の基準を満たすリストを受け入れるだけの場合に使用する必要があります(あなたの場合は、拡張するタイプのリストNumber
)。
static Number findMax(LinkedList<? extends Number> list) {
Number max = list.get(0);
for (Number number : list) {
if (number > max) {
max = number;
}
}
return max;
}
このメソッドは を返しますNumber
。たとえば、拡張Number
した独自のクラスがあり、このメソッドの結果に対して後で使用する特別なメソッドがある場合、これは問題になる可能性があります。
2 番目のものT
は、メソッド本体で正確な型をメソッド パラメーターとして、またはメソッドの戻り値の型として使用する予定がある場合に使用する必要があります。
static <T extends Number> T findMax(LinkedList<T> list, T currentMax) {
T max = currentMax;
for (T number : list) {
if (number > max) {
max = number;
}
}
return max;
}
結論:
機能的には、タイプが不明なリスト( ) を変更できないことを除けば、ほとんど同等です。?
ここに違いがあります
static void findMax(LinkedList<? extends Number> list){
list.add(list.get(0)); <-- compile error
}
null 以外はリストに追加できません。
同時に、これはエラーや警告なしでコンパイルされます
static <T extends Number> void findMax2(LinkedList<T> list){
list.add(list.get(0)); <-- no error
}
署名の力に関しては、どちらもまったく同じです。つまり、2 番目の署名を使用する API がある場合、それを最初の署名を使用する API に置き換えることができ、API を使用するコードは以前とまったく同じように機能し、以前は機能しなかったコードはすべて機能します。も機能しません。したがって、外部コードには、2 つの間に違いはありません。
2 番目の実装を最初の実装にどのように変更しますか? 他の人が の例を指摘していlist.add(list.get(0));
ます。最初の署名を持つ API はそのアクションを実行できますか? はい。とても簡単です。最初のもので2番目のものを呼び出すだけです(2番目のものを内部プライベートメソッドにします)。これはキャプチャ ヘルパーと呼ばれます。これを行うことができるという事実は、外部コードの観点から、両方が同じことを「行う」ことができることを証明しています (他のメソッドの呼び出しを含む内部手段を介して「行う」)。
static void findMax(LinkedList<? extends Number> list){
findMaxPrivate(list);
}
static static <T extends Number> void findMaxPrivate(LinkedList<T> list){
list.add(list.get(0));
}
2番目のメソッドの本体にあるパラメーター T のアクセスについては、すでに良い答えがあると思います。
タイプごとにリンクする必要がある多くのパラメーターがある場合は、2 番目の表記が必要になることを追加したいと思います。例:
static <T extends Number> int getPosition(LinkedList<T> list, T element){...}
ジェネリック型パラメーターを使用しないと、上記の制約を強制することはできません<T>
。