Diferença entre Arrays.asList (array) e new ArrayList <Integer> (Arrays.asList (array))

119

Qual é a diferença entre

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

onde iaé uma matriz de inteiros.

Fiquei sabendo que algumas operações não são permitidas list2. por que é tão? como é armazenado na memória (referências / cópia)?

Quando eu embaralho as listas, list1não afeta a matriz original, mas afeta list2. Mas ainda list2é um pouco confuso.

Como ArrayListser atualizado para a lista difere da criação de novosArrayList

list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Dineshkumar
fonte
2
Eu sugiro que você tome cuidado com a opção do Google Guava . Lists.newArrayList(ia)faz uma cópia independente, como a primeira opção. É simplesmente mais geral e melhor de se olhar.
qben de

Respostas:

228
  1. Primeiro, vamos ver o que isso faz:

    Arrays.asList(ia)

    Ele pega um array iae cria um wrapper que o implementa List<Integer>, o que torna o array original disponível como uma lista. Nada é copiado e tudo, apenas um único objeto wrapper é criado. As operações no wrapper da lista são propagadas para a matriz original. Isso significa que se você embaralhar o invólucro da lista, o array original também será; se você sobrescrever um elemento, ele será sobrescrito no array original, etc. Claro, algumas Listoperações não são permitidas no invólucro, como adicionar ou removendo elementos da lista, você só pode ler ou sobrescrever os elementos.

    Observe que o wrapper de lista não se estende ArrayList- é um tipo diferente de objeto. ArrayLists têm seu próprio array interno, no qual armazenam seus elementos e são capazes de redimensionar os arrays internos, etc. O wrapper não tem seu próprio array interno, ele apenas propaga operações para o array fornecido a ele.

  2. Por outro lado, se você subsequentemente criar uma nova matriz como

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

    então você cria um novo ArrayList, que é uma cópia completa e independente do original. Embora aqui você também crie o wrapper usando Arrays.asList, ele é usado apenas durante a construção do novo ArrayListe é coletado como lixo posteriormente. A estrutura deste novo ArrayListé completamente independente da matriz original. Ele contém os mesmos elementos (o array original e esta nova ArrayListreferência os mesmos números inteiros na memória), mas cria um novo array interno que contém as referências. Então, quando você embaralha, adiciona, remove elementos, etc., o array original não é alterado.

Petr Pudlák
fonte
9
@Dineshkumar Um wrapper é um padrão de design que traduz uma interface de uma classe em outra interface. Veja o artigo sobre padrões de invólucro . | Onde você precisa fazer o upcast? Eu sugiro usar List<Integer>para seus tipos de variáveis ​​(ou argumentos de método, etc.). Isso torna seu código mais genérico e você pode alternar facilmente para outra Listimplementação conforme necessário, sem ter que reescrever muito código.
Petr Pudlák
Essa é uma boa explicação. Estendendo essa questão, o método Arrays.asList () também aceita varargs. Se eu passar valores específicos, diga que faço: Arrays.asList (1,3,5) duas vezes, ele retornará a mesma List?
sbsatter
27

Bem, isso ocorre porque o ArrayListresultado de Arrays.asList()não é do tipo java.util.ArrayList. Arrays.asList()cria um ArrayListtipo java.util.Arrays$ArrayListque não se estende, java.util.ArrayListmas apenas se estendejava.util.AbstractList

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

Nesse caso, list1é do tipo ArrayList.

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

Aqui, a lista é retornada como uma Listvisualização, o que significa que ela possui apenas os métodos anexados a essa interface. Daí porque alguns métodos não são permitidos list2.

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

Aqui, você ESTÁ criando um novo ArrayList. Você está simplesmente passando um valor no construtor. Este não é um exemplo de elenco. No elenco, pode se parecer mais com isto:

ArrayList list1 = (ArrayList)Arrays.asList(ia);
Cristóvão
fonte
4

Estou muito atrasado aqui, de qualquer forma senti que uma explicação com referências de doc seria melhor para quem procura uma resposta.

  1. java.util.Arrays
  • Esta é uma classe de utilitário com um monte de métodos estáticos para operar em determinado array
  • asList é um desses métodos estáticos que obtém a matriz de entrada e retorna um objeto de java.util.Arrays.ArrayList, que é uma classe aninhada estática que estende AbstractList que, por sua vez, implementa a interface List.
  • Portanto, Arrays.asList (inarray) retorna um envoltório de Lista ao redor da matriz de entrada, mas esse envoltório é java.util.Arrays.ArrayList e não java.util.ArrayList e se refere à mesma matriz, portanto, adicionar mais elementos à matriz agrupada de Lista afetaria orignal um também e também não podemos alterar o comprimento.
  1. java.util.ArrayList
  • ArrayList tem um monte de construtores sobrecarregados

    public ArrayList () - // retorna arraylist com capacidade padrão 10

    public ArrayList (coleção c)

    public ArrayList (int initialCapacity)

  • Então, quando passamos o objeto retornado Arrays.asList, isto é, List (AbstractList) para o segundo construtor acima, ele criará um novo array dinâmico (o tamanho do array aumenta à medida que adicionamos mais elementos do que sua capacidade e também os novos elementos não afetarão o array original ) cópia superficial da matriz original ( cópia superficial significa que copia apenas sobre as referências e não cria um novo conjunto dos mesmos objetos da matriz original)

Gautam Tadigoppula
fonte
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);         

A Instrução Acima adiciona o invólucro na matriz de entrada. Portanto, os métodos como adicionar e remover não serão aplicáveis ​​no objeto de referência de lista 'namesList'.

Se você tentar adicionar um elemento na matriz / lista existente, obterá "Exceção no thread" main "java.lang.UnsupportedOperationException".

A operação acima é somente leitura ou visualização.
Não podemos realizar a operação de adicionar ou remover no objeto da lista. Mas

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

Na declaração acima, você criou uma instância concreta de uma classe ArrayList e passou uma lista como parâmetro.

Nesse caso, o método add & remove funcionará corretamente, pois ambos os métodos são da classe ArrayList, portanto, não obteremos nenhuma UnSupportedOperationException.
As alterações feitas no objeto Arraylist (método adicionar ou remover um elemento em / de uma arraylist) não serão refletidas no 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
Avinash Pande
fonte
3

Em primeiro lugar, a classe Arrays é uma classe de utilitário que contém no. de métodos utilitários para operar em Arrays (graças à classe Arrays, caso contrário, teríamos que criar nossos próprios métodos para agir em objetos Array)

Método asList ():

  1. asListmétodo é um dos métodos utilitários de Arrayclasse, é um método estático, por isso podemos chamar este método pelo seu nome de classe (como Arrays.asList(T...a))
  2. Agora aqui está a torção, por favor, note que este método não cria um novo ArrayListobjeto, ele apenas retorna uma referência de lista para o Arrayobjeto existente (agora, após usar o asListmétodo, duas referências ao Arrayobjeto existente são criadas)
  3. e esta é a razão, todos os métodos que operam no Listobjeto, podem NÃO funcionar neste objeto Array usando Listreferência como, por exemplo, Arrayo tamanho de s é fixo em comprimento, portanto, você obviamente não pode adicionar ou remover elementos do Arrayobjeto usando esta Listreferência (como list.add(10)ou list.remove(10);caso contrário, lançará UnsupportedOperationException)
  4. qualquer mudança que você estiver fazendo usando a referência de lista será refletida na saída Arraydo objeto s (já que você está operando em um objeto Array existente usando a referência de lista)

No primeiro caso, você está criando um novo Arraylistobjeto (no segundo caso, apenas a referência ao objeto Array existente é criada, mas não um novo ArrayListobjeto), então agora existem dois objetos diferentes, um é Arrayobjeto e o outro é ArrayListobjeto e nenhuma conexão entre eles (então as mudanças em um objeto não será refletido / afetado em outro objeto (que é no caso 2 Arraye Arraylistsão dois 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));
Irfan
fonte
3

Muitas pessoas já responderam aos detalhes mecânicos, mas é importante notar: Esta é uma escolha de design ruim, por Java.

O asListmétodo Java está documentado como "Retorna uma lista de tamanho fixo ...". Se você pegar seu resultado e chamar (digamos) o .addmétodo, ele lança um UnsupportedOperationException. Este é um comportamento não intuitivo! Se um método diz que retorna um List, a expectativa padrão é que ele retorne um objeto que suporte os métodos de interface List. Um desenvolvedor não deve ter que memorizar qual dos vários util.Listmétodos cria programas Listque não suportam realmente todos os Listmétodos.

Se eles tivessem nomeado o método asImmutableList, faria sentido. Ou se eles apenas tivessem o método retornando um real List(e copiasse a matriz de apoio), faria sentido. Eles decidiram favorecer o desempenho em tempo de execução e nomes curtos, às custas de violar o Princípio da Menor Surpresa e a prática OO bom de evitar UnsupportedOperationExceptions.

(Além disso, os designers podem ter feito um interface ImmutableList, para evitar uma infinidade de UnsupportedOperationExceptions.)

não apenas yeti
fonte
2

Observe que, em Java 8, 'ia' acima deve ser Integer [] e não int []. Arrays.asList () de uma matriz int retorna uma lista com um único elemento. Ao usar o trecho de código do OP, o compilador detectará o problema, mas alguns métodos (por exemplo, Collections.shuffle ()) falharão silenciosamente em fazer o que você espera.

Carl Burke
fonte
1
Eu enfrentei esse problema do compilador quando fiz ArrayList <Integer> al = new ArrayList <Integer> (Arrays.asList (a)); onde a era um int []. Meu al só tinha um único elemento que também parecia lixo quando impresso. Qual é esse elemento? E como é que vem aí? Enfrentei esse problema no Java 7
Jyotsana Nandwani
@JyotsanaNandwani Pls, verifique minha resposta: 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
fonte
1

Arrays.asList()

este método retorna sua própria implementação de List. Ele pega uma matriz como um argumento e cria métodos e atributos sobre ela, já que não está copiando nenhum dado de uma matriz, mas usando a matriz original, isso causa alteração na matriz original quando você modifica lista retornada pelo Arrays.asList()método.

por outro lado.
ArrayList(Arrays.asList()); é um construtor de ArrayListclasse que recebe uma lista como argumento e retorna um ArrayListque é independente da lista ie. Arrays.asList()neste caso, passou como um argumento. é por isso que você vê esses resultados;

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

Na linha 2, Arrays.asList(ia)retorna uma Listreferência do objeto de classe interna definido em Arrays, que também é chamado, ArrayListmas é privado e apenas estende AbstractList. Isso significa que o que retornou Arrays.asList(ia)é um objeto de classe diferente do que você obteve new ArrayList<Integer>.

Você não pode usar algumas operações na linha 2 porque a classe privada interna Arraysnão fornece esses métodos.

Dê uma olhada neste link e veja o que você pode fazer com a classe interna privada: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ Arrays.java # Arrays.ArrayList

A linha 1 cria um novo ArrayListobjeto copiando elementos do que você obtém na linha 2. Portanto, você pode fazer o que quiser, pois java.util.ArrayListfornece todos esses métodos.

zek_w
fonte
0

Resumo da diferença -

quando a lista é criada sem usar o novo método do operador Arrays.asList (), ele retorna Wrapper, o que significa

1. você pode realizar a operação de adicionar / atualizar.

2. as alterações feitas no array original também serão refletidas em List e vice-versa.

Raj
fonte
0

Em resposta a alguns comentários com perguntas sobre o comportamento 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);
PATETA
fonte