0

I want to be able to make a list like so -

List<Object> l = new ArrayList<String>();

The standard library implementation of ArrayList does not allow this. It gives compile time error. So I am writing my own implementation of the ArrayList.

So far I have tried this -

public class ArrayList<Y extends X> implements List<X> {...}
public class ArrayList<X super Y> implements List<X> {...}

which do not compile.

So, how can I write an ArrayList where I would be able to use it like I mentioned above?

List<Object> l = new ArrayList<String>();

People have pointed out this post Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?

But I still don't understand. The reason given was that we want to avoid situations like so -

List<Object> l = new ArrayList<String>();
l.add(new Dog()); 

While this makes sense, I can do a similar kind of thing with Java Arrays which compiles but throws Exception at runtime.

Object o[] = new String[10];
o[0] = new Dog();

So what is the rationale behind allowing the latter code to compile but not the former?

EDIT - Similar question has already been asked as indicated above. This question also helps Why is the ArrayStoreException a RuntimeException?

Yasser Hussain
  • 854
  • 7
  • 21
  • 2
    Why does the linked question not answer your question? I mean it explains why Java does not support this kind of syntax. What exactly do you want to achieve if not that? If you write `new ArrayList()` that list will **only** accept `String` and subtypes of it. If you write `new ArrayList()` instead, you can add all you want. – Zabuzard Dec 05 '17 at 14:03
  • Are you saying you'd rather have an exception at runtime than a compile error? That doesn't seem to make much sense. – Marvin Dec 05 '17 at 14:17
  • No I am not saying that. I am just asking what is the reason behind this. – Yasser Hussain Dec 05 '17 at 14:17
  • Well, the whole point of generics is to avoid runtime exceptions, so... what other reasons do you need? – Marvin Dec 05 '17 at 14:20
  • I need the reason for why is the same thing allowed for Arrays, why not compile time error in that case? Basically what I am asking is why do we have this dual policy, one for Arrays and a different policy for generic ArrayLists? – Yasser Hussain Dec 05 '17 at 14:24

2 Answers2

2

Just as your link says, define your List like so:

List<? extends Object> l = new ArrayList<String>();

EDIT

Yes, the reason that

List<? extends Object> l = new ArrayList<String>(); l.add("asda");

doesn't work is to avoid runtime exceptions, because the Type of the List could be is anything extending Object so the compiler treats it as such (could be anything/unknown). However you can still edit the list if you keep a reference to the original.

List<String> strList = new ArrayList<>();
List<? extends Object> objList = strList;
strList.add("asdf");
// Will return Strings that only have the Object interface
Object o = objList.get(0);

The purpose of List<? extends Object> is just to give your code a type guarantee (some type extending Object in this case) and the compiler, thanks to generics, is able to ensure that condition at compile time but it also needs to ensure that you don't violate the original list. Take for example the following code:

List<Integer> intList = new ArrayList<>();
List<? extends Object> objList = intList;
// compile error to protect the original list
objList.add("asdf");

So because the objList is of type ? you can't add a String to it. Even though String is a subclass of Object it might not be (and isn't in this case) the same type as?.

Also don't forget that generic types are gone at runtime because of Type Erasure. Generics are a compile time guarantee.

Also, now I see your true question.

I need the reason for why is the same thing allowed for Arrays, why not compile time error in that case? Basically what I am asking is why do we have this dual policy, one for Arrays and a different policy for generic ArrayLists?

See this question and its related answers regarding that

xtratic
  • 4,600
  • 2
  • 14
  • 32
0

You can just write

List<Object> l = new ArrayList<Object>();

the type parameter exists only at compile time, so this makes no difference.

Claus Radloff
  • 357
  • 1
  • 11