Liste Type de rapport type ArrayList en Java
(1) List<?> myList = new ArrayList<?>();
(2) ArrayList<?> myList = new ArrayList<?>();
Je comprends que (1), les implémentations de la Liste interface peut être échangé. Il semble que (1) est généralement utilisé dans une application indépendamment du besoin (moi je l'utilise toujours).
Je me demandais si quelqu'un utilise (2)?
Aussi, combien de fois (et puis-je s'il vous plaît obtenir un exemple) la situation réellement besoin de l'aide des (1) (2) (c'est à dire où (2) ne suffira pas..à part codage des interfaces et meilleures pratiques etc.)
- Plus d'infos ici: stackoverflow.com/questions/716597/...
- Double Possible de Java - déclarant à partir de l'Interface type au lieu de la Classe
- Voir ma réponse sur la Sérialisation où vous devez utiliser (2)!
InformationsquelleAutor kji | 2010-02-17
Vous devez vous connecter pour publier un commentaire.
Presque toujours le premier est préféré au cours de la deuxième. La première a l'avantage de la mise en œuvre de la
List
peut changer (pour unLinkedList
par exemple), sans affecter le reste du code. Ce sera une tâche difficile à faire avec unArrayList
, non seulement parce que vous aurez besoin de changerArrayList
àLinkedList
partout, mais aussi parce que vous avez utiliséeArrayList
des méthodes spécifiques.Vous pouvez lire sur
List
implémentations ici. Vous pouvez commencer avec unArrayList
, mais peu de temps après, de découvrir qu'une autre mise en œuvre est plus approprié.keySet
dansConcurrentHashMap
entre Java 7 et 8.LinkedList
?Oui. Mais rarement pour de bonnes raisons (OMI).
Et les gens ont brûlé parce qu'ils ont utilisé
ArrayList
quand ils devraient avoir utiliséList
:Méthodes de l'utilitaire, comme
Collections.singletonList(...)
ouArrays.asList(...)
ne retourne pas uneArrayList
.Méthodes dans le
List
API ne garantit pas pour retourner une liste du même type.Par exemple de quelqu'un se brûler, en https://stackoverflow.com/a/1481123/139985 l'affiche avait des problèmes de "découpage" parce que
ArrayList.sublist(...)
ne retourne pas uneArrayList
... et il avait conçu son code à utiliserArrayList
que le type de l'ensemble de sa liste de variables. Il a fini par "résoudre" le problème en copiant le sous-liste dans une nouvelleArrayList
.L'argument que vous avez besoin de savoir comment le
List
se comporte est en grande partie résolues par l'utilisation de laRandomAccess
interface marqueur. Oui, c'est un peu maladroit, mais l'alternative est pire.La "combien de fois" partie de la question est, objectivement, sans réponse.
Occasionnellement, l'application peut exiger que vous utilisez des méthodes dans le
ArrayList
API qui sont pas dans leList
API. Par exemple,ensureCapacity(int)
,trimToSize()
ouremoveRange(int, int)
. (Et le dernier, ne se posent que si vous avez créé un sous-type de liste de tableaux qui déclare la méthode àpublic
.)C'est la seule bonne raison pour le codage de la classe plutôt que de l'interface, de l'OMI.
(Il est théoriquement possible que vous obtiendrez une légère amélioration de la performance ... dans certaines circonstances ... sur certaines plates-formes ... mais à moins que vous vraiment besoin de ce dernier à 0,05%, il n'est pas en vaut la peine. Ce n'est pas une bonne raison, de l'OMI.)
Qui est un bon point. Cependant, Java fournit de meilleures façons de traiter avec que; par exemple,
Si vous l'appelez avec une liste qui n'en œuvre
RandomAccess
, vous obtiendrez une erreur de compilation.Vous pouvez également tester dynamiquement ... à l'aide de
instanceof
... si le typage statique est trop maladroit. Et vous pouvez même écrire votre code pour utiliser différents algorithmes (dynamiquement) en fonction de si oui ou non une liste soutenue de l'accès aléatoire.Noter que
ArrayList
n'est pas le seul de la liste de la classe qui implémenteRandomAccess
. D'autres incluentCopyOnWriteList
,Stack
etVector
.J'ai vu des gens faire le même argument à propos des
Serializable
(parce queList
n'est pas mise en œuvre) ... mais l'approche ci-dessus résout ce problème aussi. (Dans la mesure où il est résoluble à tous les à l'aide d'exécution types. UnArrayList
échouera sérialisation si aucun élément n'est pas sérialisable.)Par exemple, vous pourriez décider d'un
LinkedList
est le meilleur choix pour votre application, mais plus tard déciderArrayList
pourrait être un meilleur choix pour des raisons de performances.Utilisation:
Au lieu de:
Pour référence:
(posté principalement pour la Collecte schéma)
Il est considéré comme bon style pour stocker une référence à un
HashSet
ouTreeSet
dans une variable de type Ensemble.Set<String> names = new HashSet<String>();
De cette façon, vous avez à changer une seule ligne si vous décidez d'utiliser un
TreeSet
à la place.Aussi, les méthodes qui fonctionnent sur des ensembles devraient spécifier les paramètres de type de Jeu:
public static void print(Set<String> s)
Puis la méthode peut être utilisée pour définir tous les implémentations.
En théorie, nous devrions faire la même recommandation pour les listes liées, à savoir sauver des
LinkedList références dans des variables de type Liste. Cependant, dans la bibliothèque Java, la Liste de l'interface est commune à la fois à l'
ArrayList
et laLinkedList
classe. En particulier, il a des méthodes get et set pour un accès aléatoire, même si ces méthodes sont très inefficace pour les listes chaînées.Vous ne pouvez pas écrire du code efficace si vous ne savez pas si d'accès aléatoire est efficace ou pas.
Ce n'est manifestement une grave erreur de conception dans la bibliothèque standard, et je ne peux pas recommander l'utilisation d'
la Liste de l'interface pour cette raison.
Pour voir juste comment embarrassant que l'erreur est, jetez un oeil à
le code source de la
binarySearch
méthode de la Collections classe. Cette méthode prend unParamètre de liste, mais la recherche binaire n'a pas de sens pour une liste liée. Le code puis maladroitement
essaie de découvrir si la liste est une liste chaînée, et passe ensuite à une recherche linéaire!
La
Set
de l'interface et laMap
de l'interface, sont bien conçus, et vous devez les utiliser.RandomAccess
qui est appliqué à tous les typesList
sous-classes qui ont efficace de l'accès aléatoire. Par exempleArrayList
la met en œuvre, etLinkedList
ne l'est pas. Vous pouvez utiliser cette option pour choisir entre les algorithmes qui nécessitent un accès aléatoire ou pas.J'utilise (2) si le code est le "propriétaire" de la liste. C'est par exemple vrai pour les locaux-seules les variables. Il n'y a pas de raison d'utiliser le type abstrait
List
au lieu deArrayList
.Un autre exemple pour démontrer la propriété:
LinkedList
va fonctionner mieux qu'unArrayList
, vous auriez à changer la signature de l'évaluateur méthodes, qui signifie aussi la chose à l'aide de ces méthodes devront être examinés et éventuellement refait... qui peuvent chaîne tout le chemin jusqu'au plus haut niveau.getStrings
renvoie uneList
, plutôt que deArrayList
. Tout appelant qui devrait s'en occuper, le membre d'une manière abstraite, va utiliser ce accesseur.getStringsCopy()
qui crée une copie destrings
.strings
est une variable interne, de sorte que vous pouvez changer autant de fois que vous en avez besoin pour répondre à l'évolution des besoins. Mais l'interface (les méthodes publiques) ne devrait pas changer si vous pouvez l'aider. Au retour d'uneArrayList
les verrous de la classe à l'aide d'unArrayList
mise en œuvre, lorsqueArrayList
est simplement unList
l'utilisation de tableaux pour mettre en œuvre le comportement, de sorte qu'il n'a pas ajouté des fonctionnalités plusList
à tous.ArrayList
. Mais @mazatwork a aussi un point avec son "propriétaire" de la définition. Si le propriétaire sait que la Liste doit être d'un certain type, alors il doit s'assurer que, et donc de la déclarer. Voir aussi ma réponse à propos de la SérialisationLorsque vous écrivez
List
, vous fait dire que votre objet implémenteList
seulement l'interface, mais vous ne précisez pas quelle classe est votre objet appartient.Lorsque vous écrivez
ArrayList
, vous spécifiez que votre classe d'objet est un redimensionnable-tableau.Ainsi, la première version rend votre code plus souple à l'avenir.
Regarder Java docs:
La classe
ArrayList
Redimensionnable-tableau de mise en œuvre de laList
interface.L'Interface
List
- Une collection ordonnée (aussi connu comme une séquence). L'utilisateur de cette interface a un contrôle précis où, dans la liste de chaque élément est inséré.Array
- objet conteneur qui contient un nombre fixe de valeurs d'un type unique.(3) de la Collection myCollection = new ArrayList();
J'utilise habituellement. Et seulement si j'ai besoin de la Liste des méthodes, je vais utiliser la Liste. Même avec ArrayList. Vous pouvez toujours passer à plus "étroite" de l'interface, mais vous ne pouvez pas passer pour plus "large".
Je pense que les gens qui les utilisent (2) ne sait pas le Principe de substitution de Liskov ou la Inversion de dépendance principe. Ou qu'ils ont vraiment à utiliser
ArrayList
.En fait, il ya des occasions où (2) n'est pas seulement souhaitable, mais obligatoire et je suis très surpris que personne n'en parle ici.
Sérialisation!
Si vous avez une classe sérialisable et vous voulez pour contenir une liste, vous devez déclarer le terrain, de béton et serializable type comme
ArrayList
parce que leList
interface ne s'étend pasjava.io.Serializable
Évidemment, la plupart des gens n'ont pas besoin de sérialisation et de l'oublier.
Un exemple:
Serializable
. Et lorsque vous le faites, vous pouvez faire quelque chose comme ceci:public <T extends List & Serializable> void test(T list) { ... }
.De deux suivantes:
Première est généralement préféré. Comme vous allez être en utilisant des méthodes de
List
seulement l'interface, il vous offre la liberté d'utiliser certains autres de la mise en œuvre deList
par exempleLinkedList
à l'avenir. Donc, il dissocie vous de mise en œuvre spécifiques. Maintenant, il y a deux points qui méritent une mention particulière:ArrayList
surLinkedList
. Plus ici.Oui parfois (rarement lu). Lorsque nous avons besoin de méthodes qui font partie de la mise en œuvre de
ArrayList
mais ne faisant pas partie de l'interfaceList
. Par exempleensureCapacity
.Presque toujours vous préférez l'option (1). C'est un classique du design pattern en programmation orientée objet, où vous essayez toujours de dissocier votre code d'spécifiques de mise en œuvre et le programme de l'interface.
Liste est une interface.Il n'a pas de méthodes. Lorsque vous appelez la méthode sur une Liste de référence. En fait, elle appelle la méthode de la liste de tableaux dans les deux cas.
Et pour le futur, vous pouvez modifier
List obj = new ArrayList<>
àList obj = new LinkList<>
ou d'un autre type qui implémente Liste de l'interface.Quelqu'un a demandé à ce nouveau (double) qui m'a fait aller un peu plus loin sur cette question.
Si nous utilisons un bytecode viewer (j'ai utilisé http://asm.ow2.org/eclipse/index.html) weĺl voir la suite (seulement la liste d'initialisation et affectation) pour notre liste extrait de:
et pour accédez à la liste:
La différence est liste finit par appeler INVOKEINTERFACE alors que accédez à la liste appels INVOKEVIRTUAL. Accoding à la Bycode Contour Plugin de référence,
tout invokevirtual
En résumé, invokevirtual pop objectref hors de la pile alors que pour invokeinterface
Si je comprends bien, la différence est fondamentalement la façon dont chaque chemin récupère objectref.
INVOKEVIRTUAL
instructions bytecode se transformer en non-envoi d'appel de séquences au niveau du code natif.Le seul cas que je connaisse où (2) peut être mieux, c'est lors de l'utilisation de GWT, parce qu'il réduit la demande de l'empreinte (pas mon idée, mais le google web toolkit de l'équipe qui l'affirme). Mais pour les java s'exécutant à l'intérieur de la JVM (1) est sans doute toujours mieux.
Je dirais que 1 est préféré, à moins que
Ma conjecture est que dans 99% des cas vous pouvez vous en tirer avec une Liste, qui est préféré.
removeAll
, ouadd(null)
List
interface ont plusieurs classes différentes -ArrayList
etLinkedList
.LinkedList
est utilisée pour créer des collections indexées etArrayList
- créer des listes triées. Ainsi, vous pouvez utiliser l'une dans vos arguments, mais vous pouvez permettre à d'autres développeurs qui utilisent votre code, bibliothèque, etc. pour utiliser différents types de listes, non seulement que vous utilisez, ainsi, dans cette méthodevous pouvez l'utiliser uniquement avec
ArrayList
, pasLinkedList
, mais vous pouvez vous permettre d'utiliser tout deList
classes sur d'autres lieux où la méthode est à l'aide, c'est juste votre choix, en utilisant une interface peut permettre:Dans cette méthode, les arguments que vous pouvez utiliser n'importe quel de
List
les classes que vous souhaitez utiliser:CONCLUSION:
Utiliser les interfaces partout quand c'est possible, de ne pas restreindre vous ou d'autres personnes à utiliser les différentes méthodes qui ils veulent utiliser.