<? extends Class> and <? super Class> in Java - why it works this way?

Victor Zhdanov

Yet another novice, trying to comprehend Java Generics. I've observed all topics, I found, but I still have huge questions. Could you please explain me the following things:

  1. <? extends SomeClass> means, that ? is "any type", and extends SomeClass means, that this any type can be only a subclass of SomeClass. OK, I write two elementary classes:
abstract class Person {
    private String name;
    public Person(String name) {
        this.name = name;
    }
}

class Student extends Person {
    public Student(String name) {
        super(name);
    }
}

Class Student will be ? in our example. ? extends Person, to be precise. Then I'm trying to add new student to ArrayList, that, as I understand from written above, applies all classes, that are subclasses of Person:

Student clarissa = new Student("Clarissa Starling");
List<? extends Person> list = new ArrayList<>();
list.add(clarissa); //Does not compile

Eclipse says:

"The method add(capture#3-of ? extends Person) in the type List is not applicable for the arguments (Student)"

How can class Student be not applicable, when we declared List, paramethrized by <? extends Person>, and Student exactly extends class Person?

Nevertheless, the following code:

List<? super Person> list = new ArrayList<>();
list.add(clarissa); 

compiles and works well (list.get(0), passed to println method, shows me the correct result of toString invocation). As I understand, List<? super Person> means, that I can pass to this list any type, that is super type for our Person class (in our case it is Object class only). But we see, that, contrary to logic, we can easy add subclass Student to our List<? super Person>!

OK, put aside our emotions, and let's see, what can happen with Clarissa Starling in our collection. Let's take our class Student, and add a couple of methods to it:

class Student extends Person {
    private int grant;
    public Student(String name) {
        super(name);
    }

    public void setGrant(int grant) {
        this.grant = grant;
    }

    public int getGrant() {
        return this.grant;
    }

}

Then we pass an object, instantiated from this renewed class (our object "clarissa", for example), to List<? extends Person>. Doing this, we mean, that we can store subclass in the collection of its superclasses. Maybe, I don't understand some fundamenthal ideas, but at this stage I don't see any difference between adding subclass to the collection of its superclasses and the assigning of the reference to object "clarissa" to variable, typed Person. We have the same reducing of invokable methods, when we want to treat one of them, using our superclass variable. So, why List<? extends SomeClass> does not work the same way, wherein List<? super SomeClass> works conversely?

  1. I don't understand the fundamenthal difference between <T> (or <E>, or any other letter from appropriate part of JLS) and <?>. Both <T> and <?> are typeholders, so why we have two "keywords" (this symbols are NOT keywords, I just used this word for emphasizing the heavy meaning of both symbols in Java language) for the same purpose?
sisyphus

The way I look at it is this - the placeholder T stands in for a definite type and in places where we need to know the actual type we need to be able to work it out. In contrast the wildcard ? means any type and I will never need to know what that type is. You can use the extends and super bounds to limit that wildcard in some way but there's no way to get the actual type.

So, if I have a List<? extends MySuper> then all I know about it is that every object in it implements the MySuper interface, and all the objects in that list are of the same type. I don't know what that type is, only that it's some subtype of MySuper. That means I can get objects out of that list so long as I only need to use the MySuper interface. What I can't do is to put objects into the list because I don't know what the type is - the compiler won't allow it because even if I happen to have an object of the right type, it can't be sure at compile time. So, the collection is, in a sense a read-only collection.

The logic works the other way when you have List<? super MySuper>. Here we're saying the collection is of a definite type which is a supertype of MySuper. This means that you can always add a MySuper object to it. What you can't do, because you don't know the actual type, is retrieve objects from it. So you've now got a kind of write-only collection.

Where you use a bounded wildcard versus the 'standard' generic type parameter is where the value of the differences start to become apparent. Let's say I have 3 classes Person, Student and Teacher, with Person being the base that Student and Teacher extend. In an API you may write a method that takes a collection of Person and does something to every item in the collection. That's fine, but you really only care that the collection is of some type that is compatible with the Person interface - it should work with List<Student> and List<Teacher> equally well. If you define the method like this

public void myMethod(List<Person> people) {
    for (Person p: people) {
        p.doThing();
    }
}

then it can't take List<Student> or List<Teacher>. So, instead, you would define it to take List<? extends Person>...

public void myMethod(List<? extends Person> people){
    for (Person p: people) {
        p.doThing();
    }
}

You can do that because myMethod never needs to add to the list. And now you find that List<Student> and List<Teacher> can both be passed into the method.

Now, let's say that you've got another method which wants to add Students to a list. If the method parameter takes a List<Student> then it can't take a List<People> even though that should be fine. So, you implement it as taking a List<? super Student> e.g.

public void listPopulatingMethod(List<? extends Student> source, List<? super Student> sink) {
    for (Student s: source) {
        sink.add(s);
    }
}

This is the heart of PECS, which you can read about in much greater detail elsewhere... What is PECS (Producer Extends Consumer Super)? http://www.javacodegeeks.com/2011/04/java-generics-quick-tutorial.html

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Extends class with two parameters of super class in Java

From Dev

Why generic type is not applicable for argument extends super class for both?

From Dev

Super() not working on my extends class

From Dev

Super() not working on my extends class

From Dev

super keyword without extends to the super class

From Dev

super keyword without extends to the super class

From Dev

Why does `Class<T> == Boolean.class` cause a compiler error when `T extends Comparable<? super T>`?

From Dev

Why can a super class be initialized as a child class in Java?

From Dev

Calling overloaded super constructor in ScalaJS class that extends a native class

From Dev

Java - extends why the super variable a is 0

From Dev

Scala object that extends Java class

From Dev

Java Class that extends String (or similar)

From Dev

Scala object that extends Java class

From Dev

Why this $class works and $this->class not?

From Dev

Java GC: does it ever make sense to call super.finalize() in a class that only extends Object?

From Dev

Java extends class with inner class type

From Dev

Generic super class in java

From Dev

Why can't we call super class constructor using super keyword from child class method in Java?

From Dev

Is there any way to access a private inner class that is nested in a super class from a derived class in Java?

From Dev

why Java class can extends only one class but implements many interfaces?

From Dev

How to turn a Ceylon class which extends a Java class into the Java class

From Dev

Why does super not refer to the variable in super class?

From Dev

Why is the super class method called?

From Dev

Does java support class Foo<T super X> ,if no,why?

From Dev

Why is anonymous class required in "super type token" pattern in java

From Dev

Cannot resolve method super in class which extends ArrayAdapter

From Dev

Clear memory of parent class instance created by calling super/extends

From Dev

Constructing objects that extends a super class that has its own constructor

From Dev

Cannot resolve method super in class which extends ArrayAdapter

Related Related

  1. 1

    Extends class with two parameters of super class in Java

  2. 2

    Why generic type is not applicable for argument extends super class for both?

  3. 3

    Super() not working on my extends class

  4. 4

    Super() not working on my extends class

  5. 5

    super keyword without extends to the super class

  6. 6

    super keyword without extends to the super class

  7. 7

    Why does `Class<T> == Boolean.class` cause a compiler error when `T extends Comparable<? super T>`?

  8. 8

    Why can a super class be initialized as a child class in Java?

  9. 9

    Calling overloaded super constructor in ScalaJS class that extends a native class

  10. 10

    Java - extends why the super variable a is 0

  11. 11

    Scala object that extends Java class

  12. 12

    Java Class that extends String (or similar)

  13. 13

    Scala object that extends Java class

  14. 14

    Why this $class works and $this->class not?

  15. 15

    Java GC: does it ever make sense to call super.finalize() in a class that only extends Object?

  16. 16

    Java extends class with inner class type

  17. 17

    Generic super class in java

  18. 18

    Why can't we call super class constructor using super keyword from child class method in Java?

  19. 19

    Is there any way to access a private inner class that is nested in a super class from a derived class in Java?

  20. 20

    why Java class can extends only one class but implements many interfaces?

  21. 21

    How to turn a Ceylon class which extends a Java class into the Java class

  22. 22

    Why does super not refer to the variable in super class?

  23. 23

    Why is the super class method called?

  24. 24

    Does java support class Foo<T super X> ,if no,why?

  25. 25

    Why is anonymous class required in "super type token" pattern in java

  26. 26

    Cannot resolve method super in class which extends ArrayAdapter

  27. 27

    Clear memory of parent class instance created by calling super/extends

  28. 28

    Constructing objects that extends a super class that has its own constructor

  29. 29

    Cannot resolve method super in class which extends ArrayAdapter

HotTag

Archive