Différence entre Arrays.asList (array) et new ArrayList <Integer> (Arrays.asList (array))

119

Quelle est la différence entre

1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy
2.List<Integer> list2 = Arrays.asList(ia);

iaest un tableau d'entiers.

J'ai appris que certaines opérations ne sont pas autorisées list2. pourquoi en est-il ainsi? comment est-il stocké en mémoire (références / copie)?

Lorsque je mélange les listes, list1n'affecte pas le tableau d'origine mais le list2fait. Mais c'est encore list2un peu déroutant.

En quoi la ArrayListmise à niveau vers la liste diffère de la créationArrayList

list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Dineshkumar
la source
2
Je vous suggère de vous occuper de l' option de Google Guava . Lists.newArrayList(ia)fait une copie indépendante, comme la première option. C'est simplement plus général et mieux à regarder.
qben

Réponses:

228
  1. Voyons d'abord ce que cela fait:

    Arrays.asList(ia)

    Il prend un tableau iaet crée un wrapper qui implémente List<Integer>, ce qui rend le tableau d'origine disponible sous forme de liste. Rien n'est copié et tout, un seul objet wrapper est créé. Les opérations sur le wrapper de liste sont propagées au tableau d'origine. Cela signifie que si vous mélangez le wrapper de liste, le tableau d'origine est également mélangé, si vous écrasez un élément, il est écrasé dans le tableau d'origine, etc. Bien sûr, certaines Listopérations ne sont pas autorisées sur le wrapper, comme l'ajout ou en supprimant des éléments de la liste, vous ne pouvez lire ou écraser que les éléments.

    Notez que le wrapper de liste ne s'étend pas ArrayList- c'est un autre type d'objet. ArrayLists ont leur propre tableau interne, dans lequel ils stockent leurs éléments, et sont capables de redimensionner les tableaux internes, etc. Le wrapper n'a pas son propre tableau interne, il propage uniquement les opérations sur le tableau qui lui est donné.

  2. D'autre part, si vous créez par la suite un nouveau tableau comme

    new ArrayList<Integer>(Arrays.asList(ia))

    puis vous créez un nouveau ArrayList, qui est une copie complète et indépendante de l'original. Bien qu'ici vous créez également le wrapper en utilisant Arrays.asList, il n'est utilisé que pendant la construction du nouveau ArrayListet est ensuite récupéré. La structure de ce nouveau ArrayListest complètement indépendante du tableau d'origine. Il contient les mêmes éléments (le tableau d'origine et cette nouvelle ArrayListréférence les mêmes entiers en mémoire), mais il crée un nouveau tableau interne qui contient les références. Ainsi, lorsque vous le mélangez, ajoutez, supprimez des éléments, etc., le tableau d'origine reste inchangé.

Petr Pudlák
la source
9
@Dineshkumar Un wrapper est un modèle de conception qui traduit une interface pour une classe en une autre interface. Consultez l' article sur le modèle de wrapper . | Où avez-vous besoin de upcast? Je suggère d'utiliser List<Integer>pour vos types de variables (ou arguments de méthode, etc.). Cela rend votre code plus générique et vous pouvez facilement passer à une autre Listimplémentation si nécessaire, sans avoir à réécrire beaucoup de code.
Petr Pudlák
C'est une bonne explication. Pour étendre cette question, la méthode Arrays.asList () prend également des varargs. Si je passe des valeurs spécifiques, disons: Arrays.asList (1,3,5) deux fois, retournera-t-il la même liste?
sbsatter le
27

Eh bien c'est parce que ArrayListrésultant de Arrays.asList()n'est pas du type java.util.ArrayList. Arrays.asList()crée un ArrayListtype java.util.Arrays$ArrayListqui ne s'étend pas java.util.ArrayListmais qui ne s'étend quejava.util.AbstractList

Chris
la source
9
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy

Dans ce cas, list1est de type ArrayList.

List<Integer> list2 = Arrays.asList(ia);

Ici, la liste est renvoyée sous forme de Listvue, ce qui signifie qu'elle n'a que les méthodes attachées à cette interface. D'où pourquoi certaines méthodes ne sont pas autorisées list2.

ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));

Ici, vous créez un nouveau ArrayList. Vous lui passez simplement une valeur dans le constructeur. Ce n'est pas un exemple de casting. En casting, cela pourrait ressembler davantage à ceci:

ArrayList list1 = (ArrayList)Arrays.asList(ia);
christophe
la source
4

Je suis assez tard ici, de toute façon senti qu'une explication avec des références doc serait meilleure pour quelqu'un qui cherche une réponse.

  1. java.util.Arrays
  • Ceci est une classe utilitaire avec un tas de méthodes statiques pour opérer sur un tableau donné
  • asList est l'une de ces méthodes statiques qui prend un tableau d'entrée et renvoie un objet de java.util.Arrays.ArrayList qui est une classe imbriquée statique qui étend AbstractList qui implémente à son tour l'interface List.
  • Donc, Arrays.asList (inarray) renvoie un wrapper List autour du tableau d'entrée mais ce wrapper est java.util.Arrays.ArrayList et non java.util.ArrayList et il fait référence au même tableau donc l'ajout d'éléments supplémentaires au tableau encapsulé List affecterait orignal un aussi et nous ne pouvons pas non plus changer la longueur.
  1. java.util.ArrayList
  • ArrayList a un tas de constructeurs surchargés

    public ArrayList () - // retourne arraylist avec une capacité par défaut de 10

    public ArrayList (Collection c)

    public ArrayList (int initialCapacity)

  • Ainsi, lorsque nous passons l'objet retourné Arrays.asList, c'est-à-dire List (AbstractList) au deuxième constructeur ci-dessus, il créera un nouveau tableau dynamique (cette taille de tableau augmente à mesure que nous ajoutons plus d'éléments que sa capacité et les nouveaux éléments n'affecteront pas le tableau orignal ) copie superficielle du tableau d'origine ( copie superficielle signifie qu'elle copie uniquement les références et ne crée pas un nouvel ensemble des mêmes objets que dans le tableau orignal)

Gautam Tadigoppula
la source
4
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> namesList = Arrays.asList(names);

ou

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> temp = Arrays.asList(names);         

La déclaration ci-dessus ajoute le wrapper sur le tableau d'entrée. Ainsi, les méthodes comme ajouter et supprimer ne seront pas applicables sur l'objet de référence de liste 'namesList'.

Si vous essayez d'ajouter un élément dans le tableau / liste existant, vous obtiendrez "Exception dans le thread" main "java.lang.UnsupportedOperationException".

L'opération ci-dessus est en lecture seule ou en lecture seule.
Nous ne pouvons pas effectuer d'opération d'ajout ou de suppression dans l'objet de liste. Mais

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.ArrayList<String> list1 = new ArrayList<>(Arrays.asList(names));

ou

String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> listObject = Arrays.asList(names);
java.util.ArrayList<String> list1 = new ArrayList<>(listObject);

Dans l'instruction ci-dessus, vous avez créé une instance concrète d'une classe ArrayList et passé une liste en tant que paramètre.

Dans ce cas, la méthode add & remove fonctionnera correctement car les deux méthodes proviennent de la classe ArrayList, donc ici, nous n'obtiendrons pas d'exception UnSupportedOperationException.
Les modifications apportées à l'objet Arraylist (méthode d'ajout ou de suppression d'un élément dans / d'une arraylist) ne seront pas reflétées dans l'objet java.util.List d'origine.

String names[] = new String[] {
    "Avinash",
    "Amol",
    "John",
    "Peter"
};

java.util.List < String > listObject = Arrays.asList(names);
java.util.ArrayList < String > list1 = new ArrayList < > (listObject);
for (String string: list1) {
    System.out.print("   " + string);
}
list1.add("Alex"); //Added without any exception
list1.remove("Avinash"); //Added without any exception will not make any changes in original list in this case temp object.


for (String string: list1) {
    System.out.print("   " + string);
}
String existingNames[] = new String[] {
    "Avinash",
    "Amol",
    "John",
    "Peter"
};
java.util.List < String > namesList = Arrays.asList(names);
namesList.add("Bob"); // UnsupportedOperationException occur
namesList.remove("Avinash"); //UnsupportedOperationException
Avinash Pande
la source
3

Tout d'abord, la classe Arrays est une classe utilitaire qui ne contient aucun fichier. de méthodes utilitaires pour opérer sur des tableaux (grâce à la classe Arrays sinon nous aurions dû créer nos propres méthodes pour agir sur les objets Array)

Méthode asList ():

  1. asListmethod est l'une des méthodes utilitaires de la Arrayclasse, c'est une méthode statique c'est pourquoi nous pouvons appeler cette méthode par son nom de classe (comme Arrays.asList(T...a))
  2. Maintenant, voici la torsion, veuillez noter que cette méthode ne crée pas de nouvel ArrayListobjet, elle renvoie simplement une référence List à un Arrayobjet existant (donc maintenant, après l'utilisation de la asListméthode, deux références à un Arrayobjet existant sont créées)
  3. et c'est la raison pour laquelle, toutes les méthodes qui opèrent sur un Listobjet, peuvent NE PAS fonctionner sur cet objet Array en utilisant une Listréférence comme par exemple, la Arraytaille de s est de longueur fixe, donc vous ne pouvez évidemment pas ajouter ou supprimer des éléments de l' Arrayobjet en utilisant cette Listréférence (comme list.add(10)ou list.remove(10);sinon, il lancera une exception UnsupportedOperationException)
  4. toute modification que vous effectuez à l'aide de la référence de liste sera reflétée dans la sortie de l' Arrayobjet s (lorsque vous travaillez sur un objet Array existant en utilisant une référence de liste)

Dans le premier cas, vous créez un nouvel Arraylistobjet (dans le 2ème cas, seule la référence à un objet Array existant est créée mais pas un nouvel ArrayListobjet), donc maintenant il y a deux objets différents, l'un est un Arrayobjet et un autre est un ArrayListobjet et aucune connexion entre eux (donc change dans un objet ne sera pas reflété / affecté dans un autre objet (c'est-à-dire dans le cas 2 Arrayet Arraylistsont deux objets différents)

cas 1:

Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  // new ArrayList object is created , no connection between existing Array Object
list1.add(5);
list1.add(6);
list1.remove(0);
list1.remove(0);
System.out.println("list1 : "+list1);
System.out.println("Array : "+Arrays.toString(ia));

cas 2:

Integer [] ia = {1,2,3,4};
System.out.println("Array : "+Arrays.toString(ia));
List<Integer> list2 = Arrays.asList(ia); // creates only a (new ) List reference to existing Array object (and NOT a new ArrayList Object)
//  list2.add(5); //  it will throw java.lang.UnsupportedOperationException - invalid operation (as Array size is fixed)
list2.set(0,10);  // making changes in existing Array object using List reference - valid 
list2.set(1,11); 
ia[2]=12;     // making changes in existing Array object using Array reference - valid
System.out.println("list2 : "+list2);
System.out.println("Array : "+Arrays.toString(ia));
irfan
la source
3

Beaucoup de gens ont déjà répondu aux détails mécaniques, mais cela vaut la peine de noter: il s'agit d'un mauvais choix de conception, de Java.

La asListméthode Java est documentée comme "Renvoie une liste de taille fixe ...". Si vous prenez son résultat et appelez (disons) la .addméthode, il lance un fichier UnsupportedOperationException. C'est un comportement peu intuitif! Si une méthode dit qu'elle renvoie a List, l'attente standard est qu'elle renvoie un objet qui prend en charge les méthodes d'interface List. Un développeur ne devrait pas avoir à mémoriser laquelle des innombrables util.Listméthodes crée des Lists qui ne prennent pas en charge toutes les Listméthodes.

S'ils avaient nommé la méthode asImmutableList, cela aurait du sens. Ou s'ils avaient juste la méthode renvoyer un réel List(et copier le tableau de sauvegarde), cela aurait du sens. Ils ont décidé de favoriser à la fois les performances d'exécution et les noms courts, au détriment de la violation à la fois du principe de la moindre surprise et de la bonne pratique d'éviter l' UnsupportedOperationExceptionart.

(En outre, les concepteurs auraient pu en faire un interface ImmutableList, pour éviter une pléthore de UnsupportedOperationExceptions.)

pas seulement yeti
la source
2

Notez que, dans Java 8, «ia» ci-dessus doit être Integer [] et non int []. Arrays.asList () d'un tableau int renvoie une liste avec un seul élément. Lors de l'utilisation de l'extrait de code d'OP, le compilateur détecte le problème, mais certaines méthodes (par exemple Collections.shuffle ()) échouent silencieusement à faire ce que vous attendez.

Carl Burke
la source
1
J'ai rencontré ce problème de compilateur quand j'ai fait ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)); où a était un int []. Mon al a juste un élément unique qui, une fois imprimé, avait l'air poubelle. Quel est cet élément? Et comment est-ce arrivé là-bas? J'ai rencontré ce problème dans Java 7
Jyotsana Nandwani
@JyotsanaNandwani Veuillez vérifier ma réponse: stackoverflow.com/a/54105519/1163607
NINCOMPOOP
1
package com.copy;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class CopyArray {

    public static void main(String[] args) {
        List<Integer> list1, list2 = null;
        Integer[] intarr = { 3, 4, 2, 1 };
        list1 = new ArrayList<Integer>(Arrays.asList(intarr));
        list1.add(30);
        list2 = Arrays.asList(intarr);
        // list2.add(40); Here, we can't modify the existing list,because it's a wrapper
        System.out.println("List1");
        Iterator<Integer> itr1 = list1.iterator();
        while (itr1.hasNext()) {
            System.out.println(itr1.next());
        }
        System.out.println("List2");
        Iterator<Integer> itr2 = list2.iterator();
        while (itr2.hasNext()) {
            System.out.println(itr2.next());
        }
    }
}
VicXj
la source
1

Arrays.asList()

Cette méthode retourne sa propre implémentation de List.Il prend un tableau comme argument et construit des méthodes et des attributs par-dessus, car il ne copie aucune donnée d'un tableau mais utilise le tableau d'origine, cela provoque une altération du tableau d'origine lorsque vous modifiez liste renvoyée par la Arrays.asList()méthode.

d'autre part.
ArrayList(Arrays.asList()); est un constructeur de ArrayListclasse qui prend une liste comme argument et retourne un ArrayListqui est indépendant de la liste ie. Arrays.asList()dans ce cas passé en argument. c'est pourquoi vous voyez ces résultats;

Kunal Singh Gusain
la source
0
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));  //copy
2.List<Integer> list2 = Arrays.asList(ia);

À la ligne 2, Arrays.asList(ia)renvoie une Listréférence d'objet de classe interne défini dans Arrays, qui est également appelé ArrayListmais qui est privé et ne s'étend que AbstractList. Cela signifie que ce qui est renvoyé Arrays.asList(ia)est un objet de classe différent de ce que vous obtenez new ArrayList<Integer>.

Vous ne pouvez pas utiliser certaines opérations sur la ligne 2 car la classe privée interne Arraysne fournit pas ces méthodes.

Jetez un œil à ce lien et voyez ce que vous pouvez faire avec la classe interne privée: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

La ligne 1 crée un nouvel ArrayListobjet en copiant les éléments de ce que vous obtenez de la ligne 2. Ainsi, vous pouvez faire ce que vous voulez puisque java.util.ArrayListfournit toutes ces méthodes.

zek_w
la source
0

Résumé de la différence -

lorsque la liste est créée sans utiliser le nouvel opérateur de la méthode Arrays.asList (), elle renvoie Wrapper ce qui signifie

1. vous pouvez effectuer une opération d'ajout / de mise à jour.

2. les modifications effectuées dans le tableau d'origine seront également reflétées dans List et vice versa.

Raj
la source
0

En réponse à quelques commentaires posant des questions sur le comportement de Arrays.asList () depuis Java 8:

    int[] arr1 = {1,2,3};
    /* 
       Arrays are objects in Java, internally int[] will be represented by 
       an Integer Array object which when printed on console shall output
       a pattern such as 
       [I@address for 1-dim int array,
       [[I@address for 2-dim int array, 
       [[F@address for 2-dim float array etc. 
   */
    System.out.println(Arrays.asList(arr1)); 

    /* 
       The line below results in Compile time error as Arrays.asList(int[] array)
       returns List<int[]>. The returned list contains only one element 
       and that is the int[] {1,2,3} 
    */
    // List<Integer> list1 = Arrays.asList(arr1);

    /* 
       Arrays.asList(arr1) is  Arrays$ArrayList object whose only element is int[] array
       so the line below prints [[I@...], where [I@... is the array object.
    */
    System.out.println(Arrays.asList(arr1)); 

    /* 
     This prints [I@..., the actual array object stored as single element 
     in the Arrays$ArrayList object. 
    */
    System.out.println(Arrays.asList(arr1).get(0));

    // prints the contents of array [1,2,3]
    System.out.println(Arrays.toString(Arrays.asList(arr1).get(0)));

    Integer[] arr2 = {1,2,3};
    /* 
     Arrays.asList(arr) is  Arrays$ArrayList object which is 
     a wrapper list object containing three elements 1,2,3.
     Technically, it is pointing to the original Integer[] array 
    */
    List<Integer> list2 = Arrays.asList(arr2);

    // prints the contents of list [1,2,3]
    System.out.println(list2);
CORNICHON
la source