Voici un piège que je viens de rencontrer… .. Prenons une liste d'entiers:
List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);
Toute supposition éclairée sur ce qui se passe lorsque vous exécutez list.remove(1)
? Qu'en est-il de list.remove(new Integer(1))
? Cela peut causer des bugs méchants.
Quelle est la bonne façon de différencier remove(int index)
, qui supprime un élément d'un index donné, et remove(Object o)
, qui supprime un élément par référence, lorsqu'il s'agit de listes d'entiers?
Le point principal à considérer ici est celui @Nikita mentionné - la correspondance exacte des paramètres a préséance sur la boxe automatique.
Java appelle toujours la méthode qui convient le mieux à votre argument. La boxe automatique et la conversion ascendante implicite ne sont effectuées que s’il n’ya aucune méthode qui puisse être appelée sans casting/boxe automatique.
L’interface List spécifie deux méthodes de suppression (veuillez noter le nom des arguments):
remove(Object o)
remove(int index)
Cela signifie que list.remove(1)
supprime l'objet en position 1 et que remove(new Integer(1))
supprime la première occurrence de l'élément spécifié de cette liste.
Vous pouvez utiliser le casting
list.remove((int) n);
et
list.remove((Integer) n);
Peu importe que n soit un entier ou un entier, la méthode appellera toujours celle que vous attendez.
Utiliser (Integer) n
ou Integer.valueOf(n)
est plus efficace que new Integer(n)
car les deux premiers peuvent utiliser le cache Integer, tandis que le dernier créera toujours un objet.
Je ne sais pas ce qu'il faut faire, mais la façon dont vous avez suggéré fonctionne parfaitement:
list.remove(int_parameter);
supprime l'élément à la position donnée et
list.remove(Integer_parameter);
supprime un objet donné de la liste.
C'est parce que VM essaie d'abord de trouver une méthode déclarée avec exactement le même type de paramètre et essaie seulement alors de faire une sélection automatique.
list.remove(4)
est une correspondance exacte de list.remove(int index)
; elle sera donc appelée. Si vous souhaitez appeler list.remove(Object)
, procédez comme suit: list.remove((Integer)4)
.
Toute supposition éclairée sur ce qui se passe lorsque vous exécutez list.remove (1)? Qu'en est-il de list.remove (new Integer (1))?
Il n'y a pas besoin de deviner. Le premier cas entraînera l'appel de List.remove(int)
et l'élément à la position 1
sera supprimé. Dans le second cas, List.remove(Integer)
sera appelé et l'élément dont la valeur est égale à Integer(1)
sera supprimé. Dans les deux cas, le compilateur Java sélectionne la surcharge la plus proche.
Oui, il y a un risque de confusion (et de bugs) ici, mais c'est un cas d'utilisation assez rare.
Lorsque les deux méthodes List.remove
ont été définies dans Java 1.2, les surcharges n'étaient pas ambiguës. Le problème ne s'est posé qu'avec l'introduction des génériques et l'autoboxing dans Java 1.5. En rétrospective, il aurait été préférable de donner un nom différent à l’une des méthodes de suppression. Mais il est trop tard maintenant.
Notez que même si VM ne faisait pas ce qu'il fallait, vous pouvez quand même vous assurer d'un comportement correct en utilisant le fait que remove(Java.lang.Object)
opère sur des objets arbitraires:
myList.remove(new Object() {
@Override
public boolean equals(Object other) {
int k = ((Integer) other).intValue();
return k == 1;
}
}
J'ai simplement aimé suivre comme suggéré par #decitrig dans le premier commentaire accepté.
list.remove(Integer.valueOf(intereger_parameter));
Cela m'a aidé. Merci encore #decitrig pour votre commentaire. Cela peut aider pour quelqu'un.
Eh bien voici le truc.
Prenons deux exemples ici:
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);
}
}
Voyons maintenant le résultat:
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]
Analysons maintenant le résultat:
Lorsque 3 est supprimé de la collection, il appelle la méthode remove()
de la collection qui prend Object o
en tant que paramètre. Par conséquent, l'objet 3
..__ est supprimé, mais il est remplacé par l'index 3 dans l'objet arrayList et le quatrième élément est donc supprimé.
Par la même logique de suppression d'objet, null est supprimé dans les deux cas dans la deuxième sortie.
Donc, pour supprimer le nombre 3
qui est un objet, nous devrons explicitement passer 3 en tant que object
.
Et cela peut être fait en convertissant ou en encapsulant en utilisant la classe wrapper Integer
.
Par exemple:
Integer removeIndex = Integer.valueOf("3");
collection.remove(removeIndex);