Quelle est la différence entre
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
2.List<Integer> list2 = Arrays.asList(ia);
où ia
est un tableau d'entiers.
J'ai appris que certaines opérations ne sont pas autorisées dans list2
. pourquoi est-il ainsi? comment est-il stocké en mémoire (références/copie)?
Lorsque je mélange les listes, list1
n'affecte pas le tableau d'origine, mais list2
le fait. Mais toujours list2
est un peu déroutant.
La différence de ArrayList
dans la liste diffère de la création d'une nouvelle ArrayList
list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Tout d'abord, voyons ce que cela fait:
Arrays.asList(ia)
Il prend un tableau ia
et 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 tous, un seul objet wrapper est créé. Les opérations sur le wrapper de liste sont propagées dans le 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 opérations List
ne sont pas autorisées sur le wrapper, comme l'ajout ou en supprimant des éléments de la liste, vous pouvez uniquement les lire ou les écraser.
Notez que le wrapper de liste n’étend pas ArrayList
- c’est un type d’objet différent. ArrayList
s ont leur propre tableau interne, dans lequel ils stockent leurs éléments et sont capables de redimensionner les tableaux internes, etc. Le wrapper ne possède pas son propre tableau interne, il ne fait que propager des opérations dans le tableau qui lui est attribué.
D'autre part, si vous créez ensuite un nouveau tableau en tant que
new ArrayList<Integer>(Arrays.asList(ia))
ensuite, vous créez un nouveau ArrayList
, qui est une copie complète et indépendante de l’original. Bien que ici, vous créez le wrapper en utilisant également Arrays.asList
, il est utilisé uniquement lors de la construction du nouveau ArrayList
et est ensuite récupéré. La structure de cette nouvelle ArrayList
est complètement indépendante du tableau d'origine. Il contient les mêmes éléments (le tableau d'origine et cette nouvelle référence ArrayList
font référence aux mêmes entiers en mémoire), mais il crée un nouveau tableau interne contenant les références. Ainsi, lorsque vous mélangez, ajoutez, supprimez des éléments, etc., le tableau d'origine reste inchangé.
Eh bien, c'est parce que ArrayList
résultant de Arrays.asList()
n'est pas du type Java.util.ArrayList
. Arrays.asList()
crée une ArrayList
de type Java.util.Arrays$ArrayList
qui n’étend pas Java.util.ArrayList
mais étend seulement Java.util.AbstractList
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
Dans ce cas, list1
est de type ArrayList
.
List<Integer> list2 = Arrays.asList(ia);
Ici, la liste est renvoyée sous forme d'une vue List
, ce qui signifie qu'elle ne possède que les méthodes attachées à cette interface. Par conséquent, certaines méthodes ne sont pas autorisées sur list2
.
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Ici, vous créez une nouvelle ArrayList
. Vous lui transmettez 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);
Je suis assez en retard ici, de toute façon, j'ai pensé qu'une explication avec des références doc serait préférable pour quelqu'un qui cherche une réponse.
ArrayList a un groupe de constructeurs surchargés
public ArrayList () - // retourne une liste avec une capacité par défaut 10
public ArrayList (Collection c)
public ArrayList (int initialCapacity)
Ainsi, lorsque nous passons Arrays.asList renvoyé objet, c'est-à-dire List (AbstractList), au deuxième constructeur ci-dessus, il crée un nouveau tableau dynamique (la taille de ce tableau augmente à mesure que nous ajoutons plus d'éléments que sa capacité. De plus, les nouveaux éléments n'affectent pas le tableau d'origine. ) copie superficielle du tableau d'origine ( copie superficielle signifie qu'il copie uniquement sur les références et ne crée pas un nouvel ensemble de mêmes objets que dans le tableau d'origine)
Notez que, dans Java 8, 'ia' ci-dessus doit être Integer [] et non int []. Arrays.asList () d'un tableau int retourne une liste avec un seul élément. Lorsqu’il utilise l’extrait de code d’OP, le compilateur détecte le problème, mais certaines méthodes (par exemple, Collections.shuffle ()) échouent en silence à faire ce que vous attendez.
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);
Au-dessus de la déclaration ajoute le wrapper sur le tableau d'entrée. Ainsi, les méthodes telles que add & remove ne seront pas applicables sur l'objet de référence de la liste 'namesList'.
Si vous essayez d'ajouter un élément dans le tableau/la liste existant, vous obtiendrez "Exception dans le fil" principal "Java.lang.UnsupportedOperationException".
L'opération ci-dessus est en lecture seule ou en lecture seule.
Nous ne pouvons pas effectuer d’ajout ou de suppression d’opération dans un 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 sont issues de la classe ArrayList. Par conséquent, nous n'obtiendrons aucune exception UnSupportedOperationException.
Les modifications apportées à l'objet Arraylist (méthode permettant d'ajouter ou de supprimer un élément dans/d'un 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
Beaucoup de gens ont déjà répondu aux détails mécaniques, mais il convient de noter: Ceci est un choix de conception médiocre, par Java.
La méthode asList
de Java est documentée sous la forme "Retourne une taille fixe liste ...". Si vous prenez son résultat et appelez (par exemple) la méthode .add
, il jette un UnsupportedOperationException
. C'est un comportement non intuitif! Si une méthode dit qu'elle renvoie List
, l'attente standard est qu'elle renvoie un objet prenant en charge les méthodes de l'interface List
. Un développeur ne devrait pas avoir à mémoriser which des nombreuses méthodes util.List
et créer des List
qui ne prennent pas en charge toutes les méthodes List
.
S'ils avaient nommé la méthode asImmutableList
, cela aurait du sens. Ou bien, si la méthode retournait simplement un List
(et copiait le tableau de sauvegarde), cela aurait du sens. Ils ont décidé de privilégier les noms abrégés et performances d'exécution, au détriment de la violation du principe de moindre surprise et du code OO. pratique d'éviter UnsupportedOperationException
s.
(En outre, les concepteurs ont peut-être créé un interface ImmutableList
afin d'éviter une multitude de UnsupportedOperationException
s.)
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());
}
}
}
Résumé de la différence -
lorsque la liste est créée sans utiliser de nouvel opérateur, la méthode Arrays.asList () renvoie le wrapper qui signifie
1. vous pouvez effectuer une opération d'ajout/mise à jour.
2. les modifications effectuées dans le tableau d'origine seront également répercutées sur Liste et vice versa.
En réponse à certains 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);
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
2.List<Integer> list2 = Arrays.asList(ia);
Dans la ligne 2, Arrays.asList(ia)
renvoie une référence List
d'objet de classe interne défini dans Arrays
, également appelé ArrayList
mais qui est privé et étend uniquement AbstractList
. Cela signifie que ce qui est retourné de Arrays.asList(ia)
est un objet de classe différent de ce que vous obtenez de new ArrayList<Integer>
.
Vous ne pouvez pas utiliser certaines opérations sur la ligne 2 car la classe privée interne dans Arrays
ne fournit pas ces méthodes.
Jetez un coup d’œ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 objet ArrayList
en copiant des éléments à partir de ce que vous obtenez à la ligne 2. Vous pouvez donc faire ce que vous voulez, car Java.util.ArrayList
fournit toutes ces méthodes.