これは私が今遭遇した素敵な落とし穴です。整数のリストを考えます:
List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);
list.remove(1)
を実行すると何が起こるかについての経験に基づいた推測はありますか? list.remove(new Integer(1))
はどうですか?これはいくつかの厄介なバグを引き起こす可能性があります。
特定のインデックスから要素を削除する remove(int index)
と remove(Object o)
、整数のリストを処理するときに、参照によって要素を削除しますか?
ここで考慮すべき主なポイントは、1つ @ Nikitaが言及した です。正確なパラメーターのマッチングは、オートボクシングより優先されます。
Javaは常に、引数に最適なメソッドを呼び出します。自動ボックス化と暗黙的なアップキャストは、キャスト/自動ボックス化なしで呼び出すことができるメソッドがない場合にのみ実行されます。
Listインターフェースは2つのremoveメソッドを指定します(引数の命名に注意してください):
remove(Object o)
remove(int index)
つまり、list.remove(1)
は位置1のオブジェクトを削除し、remove(new Integer(1))
はこのリストから指定された要素の最初の出現を削除します。
キャストを使用できます
list.remove((int) n);
そして
list.remove((Integer) n);
NがintまたはIntegerの場合は問題ではありません。メソッドは常に期待するものを呼び出します。
(Integer) n
またはInteger.valueOf(n)
を使用すると、最初の2つは整数キャッシュを使用できるため、new Integer(n)
よりも効率的ですが、後者は常にオブジェクトを作成します。
「適切な」方法については知りませんが、あなたが提案した方法はうまくいきます:
list.remove(int_parameter);
指定された位置の要素を削除し、
list.remove(Integer_parameter);
リストから指定されたオブジェクトを削除します。
これは、VMが最初にexactlyで宣言されたメソッドを同じパラメータータイプで見つけようとした後、オートボクシングを試みるためです。
list.remove(4)
はlist.remove(int index)
と完全に一致するため、呼び出されます。 list.remove(Object)
を呼び出す場合は、list.remove((Integer)4)
を実行します。
List.remove(1)を実行すると何が起こるかについて、経験に基づいた推測はありますか? list.remove(new Integer(1))はどうですか?
推測する必要はありません。最初のケースでは、List.remove(int)
が呼び出され、1
の位置にある要素が削除されます。 2番目のケースでは、List.remove(Integer)
が呼び出され、Integer(1)
に等しい値を持つ要素が削除されます。どちらの場合も、Javaコンパイラーは、最も近い一致するオーバーロードを選択します。
はい、ここでは混乱(およびバグ)の可能性がありますが、それはかなり一般的なユースケースです。
2つのList.remove
メソッドがJava 1.2で定義されたとき、オーバーロードはあいまいではありませんでした。この問題は、ジェネリックの導入とJava 1.5のオートボクシングでのみ発生しました。後から見ると、removeメソッドの1つに別の名前が付けられていた方がよかったでしょう。しかし、今では遅すぎます。
VMが正しいことをしなかった場合でも、remove(Java.lang.Object)
が任意のオブジェクトで動作するという事実を使用することで、適切な動作を保証できることに注意してください。
myList.remove(new Object() {
@Override
public boolean equals(Object other) {
int k = ((Integer) other).intValue();
return k == 1;
}
}
単純に、受け入れられた回答の最初のコメントで#decitrigによって提案されているとおりにフォローしたかったのです。
list.remove(Integer.valueOf(intereger_parameter));
これは私を助けました。コメントしてくれてありがとう#decitrig。いくつかの助けになるかもしれません。
さて、ここにトリックがあります。
ここで2つの例を見てみましょう。
public class ArrayListExample {
public static void main(String[] args) {
Collection<Integer> collection = new ArrayList<>();
List<Integer> arrayList = new ArrayList<>();
collection.add(1);
collection.add(2);
collection.add(3);
collection.add(null);
collection.add(4);
collection.add(null);
System.out.println("Collection" + collection);
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(null);
arrayList.add(4);
arrayList.add(null);
System.out.println("ArrayList" + arrayList);
collection.remove(3);
arrayList.remove(3);
System.out.println("");
System.out.println("After Removal of '3' :");
System.out.println("Collection" + collection);
System.out.println("ArrayList" + arrayList);
collection.remove(null);
arrayList.remove(null);
System.out.println("");
System.out.println("After Removal of 'null': ");
System.out.println("Collection" + collection);
System.out.println("ArrayList" + arrayList);
}
}
次に、出力を見てみましょう。
Collection[1, 2, 3, null, 4, null]
ArrayList[1, 2, 3, null, 4, null]
After Removal of '3' :
Collection[1, 2, null, 4, null]
ArrayList[1, 2, 3, 4, null]
After Removal of 'null':
Collection[1, 2, 4, null]
ArrayList[1, 2, 3, 4]
次に、出力を分析しましょう。
3がコレクションから削除されると、Object o
をパラメーターとして取るコレクションのremove()
メソッドを呼び出します。したがって、オブジェクト3
を削除します。ただし、arrayListオブジェクトでは、インデックス3によってオーバーライドされるため、4番目の要素は削除されます。
オブジェクトの削除と同じロジックにより、2番目の出力の両方のケースでnullが削除されます。
したがって、オブジェクトである番号3
を削除するには、object
として3を明示的に渡す必要があります。
そして、それは、ラッパークラスInteger
を使用してキャストまたはラップすることで実行できます。
例えば:
Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);