3

I have a class

public class OrderedBox<T> {}    


Compiler doesn't allow to create member/local variable like these.

OrderedBox<? extends T> testItems1 = new OrderedBox<? extends T>();
List<? extends T> testItems2 = new ArrayList<? extends T>();

Its understandable cause at runtime, it doesn't guarantee the type of objects (upper bounded by T) will be inserted and will defy the typesafety.

But it allows to create member/local variable like these. Why and How does it allow this ?

private List<OrderedBox<? extends T>> testItems = new ArrayList<OrderedBox<? extends T>>();



Note: I have this doubt while going through http://www.onjava.com/pub/a/onjava/excerpt/javaian5_chap04/index1.html

Probable duplicates :
Creating new generic object with wildcard
Generics wildcard instantiation

But both of these questions provides the reasoning for the compilation failure of the 2 options. I couldn't understand why and how the last 1 is allowed.

Community
  • 1
  • 1
arc
  • 113
  • 9
  • Two questions: What version of Java are you running, and why aren't you using the diamond `<>` operator which would take care of this problem? – Makoto Oct 18 '16 at 17:43
  • First answer on your mentioned link "Creating new generic object with wildcard" explains the reason why you are not allowed first time (because you are not telling for what class testItems1 object will get created) and why you are allowed second time (because you are telling list should of type OrderedBox) – Naresh Joshi Oct 18 '16 at 17:49
  • @Makoto, 1st: Java7. 2nd: Thanks, the <> solves. But my query is why it resolves it ? – arc Oct 18 '16 at 17:56
  • @NareshJoshi but the type inference of the OrderedBox is not specified – arc Oct 18 '16 at 18:01
  • Yes but for creating object of list you don't need it, for list object creation you just need the type of object which you are going to store in list which is OrderedBox, but the same case is not applied to your first scenario. – Naresh Joshi Oct 19 '16 at 04:30

2 Answers2

5

The answer for the one line variation is actually explained in the second SO question you posted: Generics wildcard instantiation

The One-liner does declare a type of OrderedBox but does not create an instance of it.

private List<OrderedBox<? extends T>> testItems = new ArrayList<OrderedBox<? extends T>>();

This says that you will have an OrderedBox but it does not say which one. You will have troubles when trying to create an instance like

testItems.add(new OrderedBox<? extends T>())

Because at that time, you will fix the type.

Community
  • 1
  • 1
Simon
  • 2,353
  • 1
  • 13
  • 28
  • Your explanation was really a help. I tried and it worked like you mentioned. But I would like to know how it works at runtime :). Editing the question – arc Oct 18 '16 at 21:20
  • Java compiler does a `type erasure` (this is the keyword to look for). So this is transformed into `OrderedBox` at runtime and you can put anything into it in theory. But the compiler will prevent you from doing it beforehand. – Simon Oct 18 '16 at 21:32
0

Your list object is bag a where you can keep many OrderedBox objects

private List<OrderedBox<? extends T>> testItems = new ArrayList<OrderedBox<? extends T>>();

It doesn't matter what that OrderedBox have in it at compile time, using this kind of syntax will cause you problems when you try to insert objects into that list.

You should use generics (wildcard) while declaring a class, But While creating objects for that class you should be specific like

private List<OrderedBox<Object>> testItems = new ArrayList<OrderedBox<Object>>();

Compiler will not allow

OrderedBox<? extends T> testItems1 = new OrderedBox<? extends T>();

because here you are not telling, what is the type of OrderedBox, you should be specific here as well.

Naresh Joshi
  • 4,188
  • 35
  • 45