web-dev-qa-db-fra.com

Polymorphisme: Pourquoi utiliser "List list = new ArrayList" au lieu de "ArrayList list = new ArrayList"?

Duplicate possible:
Pourquoi l'interface pour une classe Java devrait-elle être préférée?

Quand devrais-je utiliser

List<Object> list = new ArrayList<Object>();

ArrayList hérite de List, donc si certaines fonctionnalités de ArrayList ne sont pas dans List, j'aurais perdu certaines fonctionnalités de ArrayList, c'est ça? Et le compilateur remarquera une erreur en essayant d'accéder à ces méthodes?

136
hqt

La raison principale est de découpler votre code d'une implémentation spécifique de l'interface. Lorsque vous écrivez votre code comme ceci:

List list = new ArrayList();  

le reste de votre code sait seulement que les données sont de type List, ce qui est préférable car cela vous permet de basculer facilement entre les différentes implémentations de l'interface List.

Par exemple, supposons que vous écriviez une assez grande bibliothèque tierce partie et que vous avez décidé d'implémenter le noyau de votre bibliothèque avec un LinkedList. Si votre bibliothèque dépend fortement de l'accès aux éléments de ces listes, vous constaterez finalement que vous avez pris une mauvaise décision de conception; vous vous rendrez compte que vous auriez dû utiliser un ArrayList (qui donne O(1) _ temps d'accès) au lieu de LinkedList (qui donne O(n) heure d'accès). En supposant que vous programmiez une interface, il est facile de faire un tel changement. Vous voudriez simplement changer l'instance de List de,

List list = new LinkedList();

à

List list = new ArrayList();  

et vous savez que cela fonctionnera car vous avez écrit votre code pour respecter le contrat fourni par l'interface List.

D'un autre côté, si vous aviez implémenté le noyau de votre bibliothèque en utilisant LinkedList list = new LinkedList(), effectuer un tel changement ne serait pas aussi facile, car rien ne garantit que le reste de votre code ne sera pas utilisé. de méthodes spécifiques à la classe LinkedList.

Dans l’ensemble, le choix est simplement une question de conception ... mais ce type de conception est très important (surtout lorsque vous travaillez sur de grands projets), car il vous permettra d’apporter ultérieurement des modifications spécifiques à l’implémentation sans altérer le code existant.

242
Alex Lockwood

Ceci s'appelle la programmation à l'interface. Cela vous sera utile si vous souhaitez passer ultérieurement à une autre implémentation de List. Si vous voulez des méthodes dans ArrayList, il vous faudra programmer pour l'implémentation c'est-à-dire ArrayList a = new ArrayList().

67
tsatiz

Ceci est également utile lors de l'exposition d'une interface publique. Si vous avez une méthode comme celle-ci,

public ArrayList getList();

Ensuite, vous décidez de le changer en,

public LinkedList getList();

Toute personne qui faisait ArrayList list = yourClass.getList() devra changer de code. D'autre part, si vous le faites,

public List getList();

Changer d'implémentation ne change rien aux utilisateurs de votre API.

21
Brendan Long

Je pense que la réponse de @ tsatiz est généralement correcte (programmation sur une interface plutôt que sur une implémentation). Cependant, en programmant sur l'interface, vous ne perdrez aucune fonctionnalité. Laissez-moi expliquer.

Si vous déclarez votre variable en tant que List<type> list = new ArrayList<type></ code> vous ne perdez pas réellement les fonctionnalités de ArrayList. Tout ce que vous avez à faire est de convertir votre list en un ArrayList. Voici un exemple:

List<String> list = new ArrayList<String>();
((ArrayList<String>) list).ensureCapacity(19);

En fin de compte, je pense que tsatiz est correct, car une fois que vous lancez un tableau sur une liste de tableaux, vous ne codez plus sur une interface. Cependant, il est toujours recommandé de coder dans un premier temps sur une interface et, si cela devient nécessaire par la suite, de coder dans une implémentation si vous le souhaitez.

J'espère que ça t'as aidé!

10
SecondSun24

Cela vous permet d'écrire quelque chose comme:

void doSomething() {
    List<String>list = new ArrayList<String>();
    //do something
}

Plus tard, vous voudrez peut-être le changer pour:

void doSomething() {
    List<String>list = new LinkedList<String>();
    //do something
}

sans avoir à changer le reste de la méthode.

Toutefois, si vous souhaitez utiliser un CopyOnWriteArrayList par exemple, vous devez le déclarer comme tel et non comme une liste si vous souhaitez utiliser ses méthodes supplémentaires (addIfAbsent par exemple ):

void doSomething() {
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();
    //do something, for example:
    list.addIfAbsent("abc");
}
7
assylias

Je suppose que le cœur de votre question est de savoir pourquoi program to an interface, not to an implementation

Simplement parce qu'une interface vous donne plus d'abstraction et rend le code plus flexible et résilient aux changements, car vous pouvez utiliser différentes implémentations de la même interface (dans ce cas, vous voudrez peut-être modifier votre implémentation de List en une linkedList au lieu d'une ArrayList) sans changer de client.

5
Mouna Cheikhna

J'utilise cette construction chaque fois que je ne veux pas ajouter de complexité au problème. C'est juste une liste, inutile de dire de quel type de liste il s'agit, cela n'a pas d'importance pour le problème. J'utilise souvent Collection pour la plupart de mes solutions, comme à la fin, la plupart du temps, pour le reste du logiciel, ce qui compte vraiment, c'est le contenu qu'il contient et je ne souhaite pas ajouter de nouveaux objets à la Collection. .

De plus, vous utilisez cette construction lorsque vous pensez pouvoir modifier l’implémentation de la liste que vous utilisez. Supposons que vous utilisiez la construction avec une ArrayList et que votre problème n'était pas thread-safe. Désormais, vous souhaitez sécuriser les threads et, pour une partie de votre solution, vous devez utiliser un vecteur, par exemple. En ce qui concerne les autres utilisations de cette liste, qu’il s’agisse d’une AraryList ou d’un Vector, il n’y aura pas d’importantes modifications.

5
SHiRKiT

En général, vous voulez programmer sur une interface. Cela vous permet d’échanger l’implémentation à tout moment. Ceci est très utile surtout lorsque vous avez réussi une implémentation que vous ne connaissez pas.

Cependant, dans certaines situations, vous préférez utiliser la mise en œuvre concrète. Par exemple, quand sérialiser dans GWT.

2
stefan bachert