What is the difference between
1.List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
2.List<Integer> list2 = Arrays.asList(ia);
where ia
is array of integers.
I came to know that some operations are not allowed in list2
. why is it so?
how is it stored in memory (references / copy)?
When I shuffle the lists, list1
doesn't affect the original array but list2
does. But still list2
is somewhat confusing.
How ArrayList
being upcasted to list differs from creating new ArrayList
list1 differs from (1)
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
This question is related to
java
list
collections
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> namesList = Arrays.asList(names);
or
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> temp = Arrays.asList(names);
Above Statement adds the wrapper on the input array. So the methods like add & remove will not be applicable on list reference object 'namesList'.
If you try to add an element in the existing array/list then you will get "Exception in thread "main" java.lang.UnsupportedOperationException".
The above operation is readonly or viewonly.
We can not perform add or remove operation in list object.
But
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.ArrayList<String> list1 = new ArrayList<>(Arrays.asList(names));
or
String names[] = new String[]{"Avinash","Amol","John","Peter"};
java.util.List<String> listObject = Arrays.asList(names);
java.util.ArrayList<String> list1 = new ArrayList<>(listObject);
In above statement you have created a concrete instance of an ArrayList class and passed a list as a parameter.
In this case method add & remove will work properly as both methods are from ArrayList class so here we won't get any UnSupportedOperationException.
Changes made in Arraylist object (method add or remove an element in/from an arraylist) will get not reflect in to original java.util.List object.
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
I am pretty late here, anyways felt an explanation with doc references would be better for someone looking for answer.
ArrayList has bunch of overloaded constructors
public ArrayList() - //returns arraylist with default capacity 10
public ArrayList(Collection c)
public ArrayList(int initialCapacity)
So when we pass Arrays.asList returned object i.e. List(AbstractList) to second constructor above, it will create a new dynamic array(this array size increases as we add more elements than its capacity and also the new elements will not affect the orignal array) shallow copying the original array(shallow copy means it copies over the references only and does not create a new set of same objects as in orignal array)
Note that, in Java 8, 'ia' above must be Integer[] and not int[]. Arrays.asList() of an int array returns a list with a single element. When using OP's code snippet, the compiler will catch the issue, but some methods (e.g. Collections.shuffle()) will silently fail to do what you expect.
List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia)); //copy
In this case, list1
is of type ArrayList
.
List<Integer> list2 = Arrays.asList(ia);
Here, the list is returned as a List
view, meaning it has only the methods attached to that interface. Hence why some methods are not allowed on list2
.
ArrayList<Integer> list1 = new ArrayList<Integer>(Arrays.asList(ia));
Here, you ARE creating a new ArrayList
. You're simply passing it a value in the constructor. This is not an example of casting. In casting, it might look more like this:
ArrayList list1 = (ArrayList)Arrays.asList(ia);
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());
}
}
}
First of all Arrays class is an utility class which contains no. of utility methods to operate on Arrays (thanks to Arrays class otherwise we would have needed to create our own methods to act on Array objects)
asList
method is one of the utility methods of Array
class ,it is static method thats why we can call this method by its class name (like Arrays.asList(T...a)
)ArrayList
object, it just returns a List reference to existing Array
object(so now after using asList
method, two references to existing Array
object gets created)List
object , may NOT work on this Array object using List
reference like
for example, Array
s size is fixed in length, hence you obviously can not add or remove elements from Array
object using this List
reference (like list.add(10)
or list.remove(10);
else it will throw UnsupportedOperationException)Array
s object ( as you are operating on existing Array object by using list reference)In first case you are creating a new Arraylist
object (in 2nd case only reference to existing Array object is created but not a new ArrayList
object) ,so now there are two different objects one is Array
object and another is ArrayList
object and no connection between them ( so changes in one object will not be reflected/affected in another object ( that is in case 2 Array
and Arraylist
are two different objects)
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));
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));
Many people have answered the mechanical details already, but it's worth noting: This is a poor design choice, by Java.
Java's asList
method is documented as "Returns a fixed-size list...". If you take its result and call (say) the .add
method, it throws an UnsupportedOperationException
. This is unintuitive behavior! If a method says it returns a List
, the standard expectation is that it returns an object which supports the methods of interface List
. A developer shouldn't have to memorize which of the umpteen util.List
methods create List
s that don't actually support all the List
methods.
If they had named the method asImmutableList
, it would make sense. Or if they just had the method return an actual List
(and copy the backing array), it would make sense. They decided to favor both runtime-performance and short names, at the expense of violating both the Principle of Least Surprise and the good-O.O. practice of avoiding UnsupportedOperationException
s.
(Also, the designers might have made a interface ImmutableList
, to avoid a plethora of UnsupportedOperationException
s.)
Summary of difference -
when list is created without using new operator Arrays.asList() method it return Wrapper which means
1. you can perform add/update Operation.
2. the changes done in original array will be reflected to List as well and vice versa.
In response to some comments asking questions about the behaviour of Arrays.asList() since 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);
In line 2, Arrays.asList(ia)
returns a List
reference of inner class object defined within Arrays
, which is also called ArrayList
but is private and only extends AbstractList
. This means what returned from Arrays.asList(ia)
is a class object different from what you get from new ArrayList<Integer>
.
You cannot use some operations to line 2 because the inner private class within Arrays
does not provide those methods.
Take a look at this link and see what you can do with the private inner class: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Arrays.java#Arrays.ArrayList
Line 1 creates a new ArrayList
object copying elements from what you get from line 2. So you can do whatever you want since java.util.ArrayList
provides all those methods.
Well this is because ArrayList
resulting from Arrays.asList()
is not of the type java.util.ArrayList
. Arrays.asList()
creates an ArrayList
of type java.util.Arrays$ArrayList
which does not extend java.util.ArrayList
but only extends java.util.AbstractList
Arrays.asList()
this method returns its own implementation of List.It takes an array as an argument and builds methods and attributes on top of it, since it is not copying any data from an array but using the original array this causes alteration in original array when you modify list returned by the Arrays.asList()
method.
on the other hand.
ArrayList(Arrays.asList());
is a constructor of ArrayList
class which takes a list as argument and returns an ArrayList
that is independent of list ie. Arrays.asList()
in this case passed as an argument.
that is why you see these results;
Source: Stackoverflow.com