1

Why can NOT be added a new Object into a List if with this type is supposed to be able to add any supertype of Apple?

import java.util.List;
import java.util.ArrayList;
class Apple{}
public class Macintosh extends Apple {
    public static void main(String[] munch){
        List<Apple> a = new ArrayList<Apple>();
        basket(a);
    }
    static void basket(List<? super Apple> list){ list.add(new Object());}
}

If we change argument to List list, of course it works :s


class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
public class Mixer<A extends Animal>{
    public <C extends Cat> Mixer<? super Dog> useMe(A a, C c){
        return new Mixer<Animal>();
    }
}

Why can we use Mixer in return time if the compiler in the case before didn't know about the Class of the object, now is because of is a class ?¿?

Joe
  • 7,749
  • 19
  • 60
  • 110
  • 1
    Any good guide for wildcards, I read SCJP 6 and oracle documentation but I still have a lot of doubts. `Source - Guideline for Wildcard use` http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html – Joe Oct 18 '12 at 12:17

3 Answers3

0

You are trying to add to a List of Apples something that is not an Apple (Object is not a sublcass of Apple). Hence, the compilation error.

richardtz
  • 4,993
  • 2
  • 27
  • 38
0

You cannot add anything other than Apple and its subtypes to a List<? super Apple>, because the ? means 'some type' not 'any type'. It is a list of instances of some type that is either Apple or a supertype of Apple, and there is no way of knowing which exact type the ? means.

I'd suggest avoiding these constraints if you can, they don't help very often and they can easily lead to confusion.

Ricky Clarkson
  • 2,909
  • 1
  • 19
  • 21
0

As noted by others, wildcard types are existentially quantified types, not universally quantified. This means that, when using a variable of a type with wildcards, you can assign any matching type you wish when you are writing to it, but you cannot assume any particular type when you read from the variable. When writing, you control the choice, but when reading, others choose it for you.

More Detailes

  • You have full control when writing. The return value of a method is written to inside its body, in a return statement. Its parameters are written to where you invoke the method. You can happily assign a particular type to a wildcard return statement or pass a particular type to a wildcard method parameter.

  • The choice is forced upon you when reading. The return value of a method is read where you invoke the method. Its parameters are read inside its body, where you define the method. You face difficulties inside basket() when you try to use the passed list.

If we change argument to List list, of course it works :s

That's a totally different story. List is a raw type. As you discovered yourself, you can do unsafe things, like adding an Orange or any other Object to a List<Apple> if you use raw types. Java supports raw types mostly for historical reasons like backward compatibility. They are unsound by design. If you use raw types in this fashion you are likely to get a ClassCastExceptions later:

    List<Apple> a = new ArrayList<Apple>();
    basket(a);
    for (Apple apple : a) {     // Is not assignable to Apple, throws ClassCastException
        System.out.println(apple);
    }
Saintali
  • 4,482
  • 2
  • 29
  • 49