Diferencia entre Arrays.asList (matriz) y la nueva ArrayList <Integer> (Arrays.asList (matriz))


119

Cuál es la diferencia entre

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

donde iaes una matriz de enteros.

Llegué a saber que algunas operaciones no están permitidas list2. ¿por que es esto entonces? ¿Cómo se almacena en la memoria (referencias / copia)?

Cuando mezclo las listas, list1no afecta a la matriz original, pero list2sí. Pero todavía list2es algo confuso.

En qué ArrayListse diferencia de la creación de nuevasArrayList

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

2
Le sugiero que cuide la opción de Google Guava . Lists.newArrayList(ia)realiza una copia independiente, al igual que la primera opción. Es simplemente más general y mejor de mirar.
qben

Respuestas:


228
  1. Primero, veamos qué hace esto:

    Arrays.asList(ia)

    Toma una matriz iay crea un contenedor que implementa List<Integer>, lo que hace que la matriz original esté disponible como una lista. No se copia nada y todo, solo se crea un único objeto contenedor. Las operaciones en el contenedor de la lista se propagan a la matriz original. Esto significa que si mezcla la envoltura de la lista, la matriz original también se mezcla, si sobrescribe un elemento, se sobrescribe en la matriz original, etc. Por supuesto, algunas Listoperaciones no están permitidas en la envoltura, como agregar o eliminando elementos de la lista, solo puede leer o sobrescribir los elementos.

    Tenga en cuenta que la envoltura de la lista no se extiende ArrayList, es un tipo diferente de objeto. ArrayListLos s tienen su propia matriz interna, en la que almacenan sus elementos, y pueden cambiar el tamaño de las matrices internas, etc. El contenedor no tiene su propia matriz interna, solo propaga operaciones a la matriz que se le ha asignado.

  2. Por otro lado, si posteriormente crea una nueva matriz como

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

    luego crea una nueva ArrayList, que es una copia completa e independiente de la original. Aunque aquí también crea el contenedor usando Arrays.asList, solo se usa durante la construcción del nuevo ArrayListy luego se recolecta la basura. La estructura de este nuevo ArrayListes completamente independiente de la matriz original. Contiene los mismos elementos (tanto la matriz original como esta nueva ArrayListreferencia tienen los mismos enteros en la memoria), pero crea una nueva matriz interna que contiene las referencias. Entonces, cuando lo mezcla, agrega, elimina elementos, etc., la matriz original no cambia.


9
@Dineshkumar Un contenedor es un patrón de diseño que traduce una interfaz para una clase en otra interfaz. Consulte el artículo sobre el patrón de envoltura . | ¿Dónde necesitas hacer upcast? Sugeriría usar List<Integer>para sus tipos de variables (o argumentos de método, etc.). Esto hace que su código sea más genérico y puede cambiar fácilmente a otra Listimplementación según sea necesario, sin tener que reescribir mucho código.
Petr Pudlák

Esa es una buena explicación. Ampliando esta pregunta, el método Arrays.asList () también toma varargs. Si paso valores específicos, digo que sí: Arrays.asList (1,3,5) dos veces, ¿devolverá la misma lista?
sbsatter

27

Bueno, esto se debe a que el ArrayListresultado de Arrays.asList()no es del tipo java.util.ArrayList. Arrays.asList()crea un ArrayListtipo java.util.Arrays$ArrayListque no se extiende java.util.ArrayListsino que solo se extiendejava.util.AbstractList


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

En este caso, list1es de tipo ArrayList.

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

Aquí, la lista se devuelve como una Listvista, lo que significa que solo tiene los métodos adjuntos a esa interfaz. De ahí por qué algunos métodos no están permitidos list2.

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

Aquí, ESTÁS creando un nuevo ArrayList. Simplemente le está pasando un valor en el constructor. Este no es un ejemplo de casting. En el casting, podría verse más como esto:

ArrayList list1 = (ArrayList)Arrays.asList(ia);

4

Llego bastante tarde aquí, de todos modos sentí que una explicación con referencias de documentos sería mejor para alguien que busca una respuesta.

  1. java.util.Arrays
  • Esta es una clase de utilidad con un montón de métodos estáticos para operar en una matriz dada
  • asList es uno de esos métodos estáticos que toma una matriz de entrada y devuelve un objeto de java.util.Arrays.ArrayList, que es una clase anidada estática que extiende AbstractList, que a su vez implementa la interfaz List.
  • Entonces Arrays.asList (inarray) devuelve un contenedor de lista alrededor de la matriz de entrada, pero este contenedor es java.util.Arrays.ArrayList y no java.util.ArrayList y se refiere a la misma matriz, por lo que agregar más elementos a la matriz envuelta de lista afectaría original también y tampoco podemos cambiar la longitud.
  1. java.util.ArrayList
  • ArrayList tiene un montón de constructores sobrecargados

    public ArrayList () - // devuelve lista de matrices con capacidad predeterminada 10

    public ArrayList (Colección c)

    public ArrayList (int initialCapacity)

  • Entonces, cuando pasamos el objeto devuelto Arrays.asList, es decir, List (AbstractList) al segundo constructor anterior, creará una nueva matriz dinámica (este tamaño de matriz aumenta a medida que agregamos más elementos que su capacidad y también los nuevos elementos no afectarán la matriz original ) copia superficial de la matriz original ( copia superficial significa que copia solo las referencias y no crea un nuevo conjunto de los mismos objetos que en la matriz original)


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

o

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

La declaración anterior agrega el contenedor en la matriz de entrada. Por lo tanto, los métodos como agregar y eliminar no serán aplicables en el objeto de referencia de la lista 'namesList'.

Si intenta agregar un elemento en la matriz / lista existente, obtendrá "Excepción en el hilo" principal "java.lang.UnsupportedOperationException".

La operación anterior es de solo lectura o solo visualización.
No podemos realizar la operación de agregar o quitar en el objeto de lista. Pero

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

o

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

En la declaración anterior, ha creado una instancia concreta de una clase ArrayList y ha pasado una lista como parámetro.

En este caso, el método add & remove funcionará correctamente ya que ambos métodos son de la clase ArrayList, por lo que aquí no obtendremos ninguna UnSupportedOperationException.
Los cambios realizados en el objeto Arraylist (método para agregar o eliminar un elemento en / de una lista de arreglos) no se reflejarán en el objeto java.util.List original.

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

3

En primer lugar, la clase Arrays es una clase de utilidad que no contiene. de métodos de utilidad para operar en Arrays (gracias a la clase Arrays, de lo contrario, habríamos necesitado crear nuestros propios métodos para actuar sobre objetos Array)

método asList ():

  1. asListEl método es uno de los métodos de utilidad de la Arrayclase, es un método estático, por eso podemos llamar a este método por su nombre de clase (como Arrays.asList(T...a))
  2. Ahora aquí está el giro, tenga en cuenta que este método no crea un nuevo ArrayListobjeto, solo devuelve una referencia de lista al Arrayobjeto existente (por lo que ahora, después de usar el asListmétodo, Arrayse crean dos referencias al objeto existente )
  3. y esta es la razón, es posible que todos los métodos que operan en un Listobjeto NO funcionen en este objeto Array usando una Listreferencia como, por ejemplo, Arrayel tamaño de s tiene una longitud fija, por lo que obviamente no puede agregar o eliminar elementos del Arrayobjeto usando estoList referencia (como list.add(10)o list.remove(10);de lo contrario, arrojará UnsupportedOperationException)
  4. cualquier cambio que esté haciendo usando la referencia de lista se reflejará al salir Array del objeto s (ya que está operando en un objeto Array existente usando la referencia de lista)

En el primer caso, está creando un nuevo Arraylistobjeto (en el segundo caso, solo se crea una referencia al objeto Array existente pero no un ArrayListobjeto nuevo ), por lo que ahora hay dos objetos diferentes, uno es un Arrayobjeto y otro es un ArrayListobjeto y no hay conexión entre ellos (por lo que cambia en un objeto no se reflejará / afectará en otro objeto (es decir, en el caso 2Array y Arraylistson dos objetos diferentes)

caso 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));

caso 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));

3

Mucha gente ya ha respondido a los detalles mecánicos, pero vale la pena señalar: esta es una mala elección de diseño de Java.

El asListmétodo de Java está documentado como "Devuelve una lista de tamaño fijo ...". Si toma su resultado y llama (digamos) al .addmétodo, arroja un UnsupportedOperationException. ¡Este es un comportamiento poco intuitivo! Si un método dice que devuelve un List, la expectativa estándar es que devuelva un objeto que admita los métodos de interfaz List. Un desarrollador no debería tener que memorizar cuál de los innumerables util.Listmétodos crea Lists que en realidad no son compatibles con todos los Listmétodos.

Si hubieran nombrado el método asImmutableList, tendría sentido. O si solo tuvieran el método devolviendo un valor real List(y copiando la matriz de respaldo), tendría sentido. Decidieron favorecer tanto el rendimiento en tiempo de ejecución como los nombres cortos, a expensas de violar tanto el Principio de la menor sorpresa como la buena práctica de OO de evitarUnsupportedOperationException s.

(Además, los diseñadores podrían haber hecho un interface ImmutableList, para evitar una plétora de UnsupportedOperationExceptions).


2

Tenga en cuenta que, en Java 8, 'ia' anterior debe ser Integer [] y no int []. Arrays.asList () de una matriz int devuelve una lista con un solo elemento. Cuando se usa el fragmento de código de OP, el compilador detectará el problema, pero algunos métodos (por ejemplo, Collections.shuffle ()) fallarán silenciosamente en hacer lo que espera.


1
Me enfrenté a este problema del compilador cuando hice ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)); donde a era un int []. Mi al obtuvo un solo elemento que también cuando se imprimió parecía basura. ¿Qué es ese elemento? ¿Y cómo es que llega allí? Me enfrenté a este problema en Java 7
Jyotsana Nandwani

@JyotsanaNandwani Por favor, compruebe mi respuesta: 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());
        }
    }
}

1

Arrays.asList()

este método devuelve su propia implementación de List. Toma una matriz como argumento y construye métodos y atributos encima de ella, ya que no está copiando ningún dato de una matriz, pero usando la matriz original, esto causa alteración en la matriz original cuando modificas lista devuelta por el Arrays.asList()método.

por otra parte.
ArrayList(Arrays.asList()); es un constructor de ArrayListclase que toma una lista como argumento y devuelve una ArrayListque es independiente de la lista, es decir. Arrays.asList()en este caso pasó como argumento. es por eso que ves estos resultados;


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

En la línea 2, Arrays.asList(ia)devuelve una Listreferencia del objeto de clase interno definido dentro Arrays, que también se llama ArrayListpero es privado y solo se extiende AbstractList. Esto significa que lo que regresa Arrays.asList(ia)es un objeto de clase diferente de lo que obtiene new ArrayList<Integer>.

No puede usar algunas operaciones en la línea 2 porque la clase privada interna dentro Arrays no proporciona esos métodos.

Eche un vistazo a este enlace y vea lo que puede hacer con la clase interna privada: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

La línea 1 crea un nuevo ArrayListobjeto copiando elementos de lo que obtiene de la línea 2. Entonces puede hacer lo que quiera, ya que java.util.ArrayListproporciona todos esos métodos.


0

Resumen de la diferencia -

cuando la lista se crea sin usar el nuevo método Arrays.asList () del operador, devuelve Wrapper, lo que significa

1. puede realizar la operación de agregar / actualizar.

2. Los cambios realizados en la matriz original también se reflejarán en la Lista y viceversa.


0

En respuesta a algunos comentarios que hacen preguntas sobre el comportamiento de Arrays.asList () desde 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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.