1

I am trying understand the following code snippet, searched links on stackoverflow with regards to lowerbound and upperbound

Just trying to get over the confusion in the following line ,

si=s//OK why? arrays of objects can be implicitly casted to arrays of integers?

 List<? extends Number> l = new ArrayList<>();
 List<? extends Integer> i = new  ArrayList<>();
 l = i;//OK i is a subtype of l

 List<? super Number> s = new ArrayList<>();
 List<? super Integer> si = new  ArrayList<>();

 si = new ArrayList<Integer>();//OK understand integer matches the pattern of ? super Integer
 s = new ArrayList<Object>();//OK understand that object is superclass of Number

 si=s//OK why?  arrays of objects can be implicitly casted to arrays of integers?

 //consider this
 List<Integer> integers = new ArrayList<Integer>();
 List<Object> objects = new ArrayList<Object>();
 integers = objects; //NOT OK Type mismatch: cannot convert from List<Object> to List<Integer>

 //consider this
 Integer ten = 10; //integer ten
 Object none = new Object();//some none
 ten = none;//NOT OK  none cannot be implicitly casted to ten  

Any help is appreciated

Community
  • 1
  • 1
chebus
  • 762
  • 1
  • 8
  • 26

2 Answers2

2

Remember that gnerics are for the benefit of the compiler not runtime information.

When you do si = s you are assigning a List of something that is a superclass of Number to a variable that can reference a List of something that is a superclass of Integer.

If it was a list of Number it would still be a list of Something that is a superclass of Integer.

We know it is actually an Arraylist of Object because you have assigned so previously.

We also know that ArrayList of Object extends List of Object.

List of Object is a List of something that is a superclass of Number which is why the previous assignment worked.

We also know that List of Object is a list of something that is a superclass of Integer but that is irrelevant to the compiler it only cares that any superclass of Number is also a superclass of Integer.

redge
  • 1,182
  • 7
  • 6
  • Just to get compiler parsing correctly w.r.t generics, if i say {si array of super of integer} = {s array of super of number} compiler does not care if type argument in right side(super of numbers) can be cast to left side(super of integers) ....it only cares if left type argument is descendant/subtype of right type argument or not OR it only cares if right type argument is supertype/ancestor of left type argument ? – chebus Jun 28 '15 at 04:56
  • No the compiler does care but any super of Number is a super of Integer because Number is a super of Integer. Also be careful of equating Array of with List of as Arrays are funny objects that are sort of primitive and sort of class and an Array of Integer CAN be assigned to Array of Number but a List of Integer CANNOT be assigned to List of Number because the generic system does not allow it.. – redge Jun 28 '15 at 06:19
  • I understand that Number is superclass of integer. Assume this scenario , List super A> lst= new ArrayList<>(); lst.add({instance of A or A's subclass, it can be anything be it A1, A2, etc.. ); assume i have added s.add(A2); Now, List super A1> sl= new ArrayList<>(); sl.add({instance of A1 or subclass of A1 )}) assume i added sl.add(A1); assume lst = sl; // this means in sl i can only add A1 or subclasses of A1 .All these subclasses inherits A anyway . Hence we say list of subclass of A1(inherited from A) are safe to assigned to list of sublcases of A ? – chebus Jun 28 '15 at 10:53
  • First I dont think you not do type inference where the variable is wildcarded. – redge Jun 28 '15 at 10:57
  • 1
    Second don't confuse generic wildcarding for a list with the items the list can contain. The difference is that the wildcard limits the type of list that can be assigned. The list itself will limit the things that can be added. Terrible Tadpoles answer goes someway to explainig the issues here. And the lack of reality in the esample code you provided in terme of a realistic real world scenario. – redge Jun 28 '15 at 11:03
1

I wonder if you're clear on why you would use <? super Number> instead of <? extends Number>...

Declaring a type with <? extends Number> guarantees to anything that takes that type that it will at least honour the contract of a Number. But a piece of code given a list of such type cannot add new members to the list. Consider this code:

void appendInteger (List <? extends Number> list) {
   list.add (new Integer (3)); // Compiler error on this line
}

You could call this with appendInteger (new ArrayList <Double> ()); Now, both Double and Integer extend Number, so the parameter will be accepted by the compiled. But you can see that if the append is allowed then the contract of the declaration in the calling code will be violated. For that reason the compiler will not allow any code that adds or replaces members in any structure declared with <? extends T>. The above method will cause a compiler error.

In brief, with upper-bounded wild-card types you can read the items but not place members into the structure.

Conversely, using List <? super Number> means that the objects in the list are not more specific than Number. Consider this method:

void getInteger (java.util.List <? extends Number> list) {
    Number n = list.get (0); // Compiler error on this line
}

The code has no idea what the type is of the elements in list. So the compiler will vomit with the method too. You can add or replace members in list with objects of any type that is in the inheritance path of Number. But to read the members of the list you have to treat them as type Object or use a type cast:

Object v = list.get (0);  // this will work
Number n = (Number) list.get (0);  // this will also work

Given this knowledge, look again at the objects involved in si = s. Remember that you cannot read items from these structures, only add or replace members. Any object that you can place in s will also be acceptable in si. So therefore it is acceptable to assign s to si.

Terrible Tadpole
  • 607
  • 6
  • 20
  • Thanks ! **But you canonly read the members of the list into variables of type Object unless you use a type cast.** I dont think that is true if you are talking about super (lower bound), when you read the members of list into the variables it can be assigned to Object(at the least) however it cannot be assigned to Number(or specific lower bounded type argument). Object obj = s.get(0); // works fine Also this is not true **In brief, with lower-bounded wild-card types you can read the items but not place members into the structure** it should be upperbounded that can read and not add – chebus Jun 28 '15 at 05:09
  • Thank you. Edited in response. – Terrible Tadpole Jun 28 '15 at 14:30