34

The implementation of java.util.ArrayList implements List as well as extends AbstractList. But in java docs you can see that AbstractList already implements List. Then wouldn't it be redundant to implement List as well as extend AbstractList?
My second question

Please have a look at the following code :

String str = "1,2,3,4,5,6,7,8,9,10";
String[] stra = str.split(",");
List<String> a = Arrays.asList(stra);

The Arrays.asList() method of the Arrays class contains its own implementation of ArrayList. But this one only extends AbstractList but does not implement List. But the above code compiles.
BUT when the code is modified to the following

String str = "1,2,3,4,5,6,7,8,9,10";
String[] stra = str.split(",");
java.util.ArrayList<String> a = Arrays.asList(stra);

I get an error : cannot convert form List<String> to ArrayList<String>
What is the reason behind this?
EDIT
Arrays.asList() does return its own implementation of ArrayList. Check this out.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Ashwin
  • 12,691
  • 31
  • 118
  • 190
  • 1
    The answer to your first question is yes but java is just like that – tom Sep 01 '13 at 12:44
  • [`Arrays#asList`](http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#asList%28T...%29) **does not** return an `ArrayList`. – Maroun Sep 01 '13 at 12:46
  • 1
    you **cant** assign one class to another class that implements the same interface but you can assign them to that interface. – Anirudha Sep 01 '13 at 12:59
  • @tommycake50 - That answer is incorrect. In fact, there is a sound reason for explicitly implementing `List`. See @Pshemo's answer. – Stephen C Sep 01 '13 at 13:12
  • the operation "new ArrayList() instanceof List" would be slower when ArrayList would not implement List. But the JVM could optimize this by adding all the interfaces of subclasses to a given class. – neoexpert Jan 13 '20 at 13:41

8 Answers8

31

Then wouldn't it be redundant to implement List as well as extend AbstractList?

Yes, it is 100% redundant. However, Java implementors added interfaces very consistently in all public implementation of the collections library:

  • LinkedList<E> and ArrayList<E> extend AbstractList<E> which implements List<E>, and then implement List<E> themselves.
  • HashSet<E> and TreeSet<E> extend AbstractSet<E> which implements Set<E>, and then implement Set<E> themselves.
  • HashMap<K,V> and TreeMap<E> extend AbstractMap<K,V> which implements Map<K,V>, and then implement Map<K,V> themselves.

My understanding is that they did so for documentation purposes: the authors wanted to show that ArrayList<E> is primarily a List<E>; the fact that ArrayList<E> extends AbstractList<E> is a less significant detail of its implementation. Same goes for the other public collection types.

Note that Arrays.ArrayList<E> class is not publicly visible, so its authors did not care to include List<T> explicitly.

As far as the failed conversion goes, this should come as no surprise, because the inner class Arrays.ArrayList<E> and the public class ArrayList<E> are unrelated to each other.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
10

For your first question take a look at Why does ArrayList have "implements List"?


To answer your second question

java.util.ArrayList<String> a = Arrays.asList(stra);

as you mentioned Arrays.asList returns its own implementation of AbstractList and unfortunately creators of this code also named this class ArrayList. Now because we cant cast horizontally but only vertically returned array list can't be cast to java.utli.ArrayList but only to java.util.AbstractList or its super types like java.util.List that is why your first code example works.

Community
  • 1
  • 1
Pshemo
  • 122,468
  • 25
  • 185
  • 269
4

Arrays.asList returns a List. So casting it to ArrayList is not safe as you do not know what type of List is being returned (depends on the array type it's creating the list from). Your second snippet wants an ArrayList implicitly. Hence it fails while your first snippet compiles fine because it expects a List. You can do-

ArrayList<String> a = new ArrayList<String>(Arrays.asList(stra));
Sajal Dutta
  • 18,272
  • 11
  • 52
  • 74
3

The answer to your first question is that implementing List is a contract. That contract can be defined by both AbstractList and ArrayList. ArrayList implements List to publish the fact that will respect the List contract in the future when it might be necessary to extend not from AbstractList that may or may not implement a List.

For the second question: Arrays.asList returns a List. It could happen that in the current implementation returns ArrayList. In the next version could return a different list LinkedList for example and the contract(defined by the method signature) will still be respected.

raisercostin
  • 8,777
  • 5
  • 67
  • 76
3

I believe, there is a reason. This is just my thought and I didn't find it anywhere in JLS.

If I am a developer who is writing an API which is to be widely used, why will I do this?

There is absolutely no reason of doing this, but consider this scenario, where I have written the List interface and provided the ArrayList implementation for the the List interface.

I have not yet written any abstract class AbstractList till now.

One day a requirement comes, where I am asked to write few more implementations of the List interface where most of them are having similar or same concrete methods for the abstract methods in List interface.

I will go ahead and write an AbstractList with necessary implementation for all those methods. But now I will not like that half of my classes to implement the List interface and half of them extending AbstractList.

Also, I cannot just go and remove the 'implements List` from the classes I wrote earlier, might be because this is not the right time or I do not want other's code to break with my new release.

Note This is solely my opinion.

dharam
  • 7,882
  • 15
  • 65
  • 93
2

1) ArrayList implements List is redundant but still legal. Only JCF (Java Collection Framework) designers could answer why. Since the lead JCF designer J.Bloch does not say why it's like this in "Effective Java" it seems we will never know why.

2) Arrays.asList returns

public class Arrays {
   ...

    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
...

it's not java.util.ArrayList and it cannot be cast to it

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
1

I will be simple and direct in my answers.

wouldn't it be redundant to implement List as well as extend AbstractList?

Yes, it is, but they did it just to clarify the code, to be easy to see that the class implements List interface.

The Arrays.asList() method of the Arrays class contains its own implementation of ArrayList. But this one only extends AbstractList but does not implement List.

As you could see, that was redundant, you don't need to re-declare the implementation of List interface if AbstractList already declares that implementation.

I get an error : cannot convert form List to ArrayList What is the reason behind this?

Arrays.asList() returns a List, it could be any type of List. The ArrayList implemented in that code is not the same ArrayList of java.util.ArrayList, they just share the same name, but they are not the same code.

ceklock
  • 6,143
  • 10
  • 56
  • 78
1

just wanna to complement answers to question 2

java.util.ArrayList<String> a=Arrays.asList(stra);

compiler just knows the return type of Arrays.asList is List, but does not know its exact implementation which may not be java.util.ArrayList. So you got this compile time error.

Type mismatch: cannot convert from List to ArrayList

you can force an upper cast explicitly like this,

java.util.ArrayList<String> a =(java.util.ArrayList<String>)Arrays.asList(stra);

The code will compile successfully, but a runtime exception will happen,

java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList

this is because java.util.Arrays$ArrayList (the type of implemenation which Arrays.asList returns) is not a subtype of java.util.ArrayList.

Kang
  • 169
  • 1
  • 5