Voici un joli piège que je viens de rencontrer. Considérez une liste d'entiers:
List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);
Une supposition éclairée sur ce qui se passe lorsque vous exécutez list.remove(1)
? Et alors list.remove(new Integer(1))
? Cela peut provoquer des bugs désagréables.
Quelle est la bonne façon de faire la différence entre 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 principal point à considérer ici est celui mentionné par @Nikita - la correspondance exacte des paramètres a priorité sur la boxe automatique.
java
collections
overloading
Yuval Adam
la source
la source
Réponses:
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'y a pas de méthode pouvant être appelée sans casting / boxe automatique.
L'interface List spécifie deux méthodes de suppression (veuillez noter la dénomination des arguments):
remove(Object o)
remove(int index)
Cela signifie que
list.remove(1)
supprime l'objet à la position 1 etremove(new Integer(1))
supprime la première occurrence de l'élément spécifié de cette liste.la source
Integer.valueOf(1)
est une meilleure pratique quenew Integer(1)
. La méthode statique peut faire la mise en cache et ainsi de suite, donc vous obtiendrez de meilleures performances.new Integer(1)
, mais je suis d'accordInteger.valueOf(1)
ou(Integer) 1
sont équivalents.Vous pouvez utiliser le casting
et
Peu importe si n est un entier ou un entier, la méthode appellera toujours celle que vous attendez.
Utiliser
(Integer) n
ouInteger.valueOf(n)
est plus efficace quenew Integer(n)
les deux premiers peuvent utiliser le cache Integer, tandis que le dernier créera toujours un objet.la source
Je ne connais pas la bonne façon, mais la façon dont vous avez suggéré fonctionne très bien:
supprime l'élément à une position donnée et
supprime l'objet donné de la liste.
C'est parce que VM essaie d'abord de trouver la méthode déclarée avec exactement le même type de paramètre et essaie seulement ensuite la case automatique.
la source
list.remove(4)
est une correspondance exacte delist.remove(int index)
, il sera donc appelé. Si vous voulez appelerlist.remove(Object)
procédez comme suit:list.remove((Integer)4)
.la source
(Integer)
casting simple comme vous l'avez écrit ci-dessus semble être l'approche la plus simple pour moi.Inutile de deviner. Le premier cas entraînera
List.remove(int)
un appel et l'élément en position1
sera supprimé. Le deuxième cas entraîneraList.remove(Integer)
un 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 correspondante 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
List.remove
méthodes 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 de l'autoboxing dans Java 1.5. Avec le recul, 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.la source
Notez que même si la machine virtuelle n'a pas fait la bonne chose, ce qu'elle fait, vous pouvez toujours garantir un comportement correct en utilisant le fait qui
remove(java.lang.Object)
fonctionne sur des objets arbitraires:la source
equals
méthode, spécifiquement (à partir de la Javadoc) "Elle est symétrique: pour toute valeur de référence non nulle x et y, x.equals (y) doit retourner vrai si et seulement si y.equals ( x) renvoie vrai. ". En tant que tel, il n'est pas garanti de fonctionner sur toutes les implémentations deList
, car toute implémentation de List est autorisée à permuter le x et le yx.equals(y)
à volonté, car le Javadoc deObject.equals
dit que cela devrait être valide.J'ai simplement aimé suivre comme suggéré par #decitrig dans le premier commentaire de réponse acceptée.
Cela m'a aidé. Merci encore #decitrig pour votre commentaire. Cela peut aider quelqu'un.
la source
Eh bien, voici l'astuce.
Prenons deux exemples ici:
Voyons maintenant la sortie:
Analysons maintenant la sortie:
Lorsque 3 est supprimé de la collection, il appelle la
remove()
méthode de la collection qui prendObject o
comme paramètre. Par conséquent, il supprime l'objet3
. Mais dans l'objet arrayList, il est remplacé par l'index 3 et donc le 4ème élément est 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 queobject
.Et cela peut être fait par cast ou wrapping en utilisant la classe wrapper
Integer
.Par exemple:
la source