Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it necessary to extend in case of read and super in write in generics wildcards?

Tags:

java

generics

I am having a hard time to understand the concept of generics wild cards.

As per my understanding <?> type unknown is introduced to resolve the co-variance not supported in generics and it should fit any type of collection and <?extends T> means that you can have collection of types T or the class which extends T.<?super T> means you can have collection of types T or super(s) of T.

Please correct me, if the above is wrong.

When I try to write it like this:

import java.util.*;

public class Gclass {
    static Gclass t;

    public void write(List< ?super String > lw){
        lw.add("b");
    }

    public void read(List< ? extends String> lr){
        String s=lr.get(2);
        System.out.println(s);
    }

    public static void main(String[] args) {
        t=new Gclass();
        List<String> l=new ArrayList<String>();
        l.add("a");
        l.add("");
        System.out.println(l);
        t.write(l);
        System.out.println(l);
        t.read(l);
        System.out.println(l);
    }
}

It works but my places of doubt are:

  1. As per my understanding both (extends and super) includes the type declared, so in this particular case as my List is of type String. I could interchange the extends and super, but I get compilation error?

  2. In case of write ? super Object is not working? It should work as it is super of String?

  3. I did not check for read as String can not be extended, but I think I'm also missing a concept here.

I've read all answers on SO related to this problem, but am still not able to have a good understanding about it.

like image 403
user3209450 Avatar asked Dec 28 '25 15:12

user3209450


2 Answers

String is indeed a bit of a bad example as it is a final class, but consider something like Number instead.

If a method takes a parameter of type List<? extends Number> then you can pass it a List<Number> or a List<Integer> or a List<BigDecimal> etc. Within the method body it is therefore fine to take things out of the list (as you know they must be instances of Number) but you can't put anything in because you don't know whether or not it's safe (the compiler can't let you risk putting an Integer into a List<Float>, for example).

Conversely if the method takes List<? super Number> then you can pass it a List<Number> or List<Object> - you can't take anything out of this list because you don't know what type it is*, but you do know that it'll definitely be safe to put a Number in.

* technically you can take things out but the only type you can assign them to is Object

like image 130
Ian Roberts Avatar answered Dec 31 '25 18:12

Ian Roberts


As per my understanding both(extends and super) includes the type declared(String here), so in this particular case as my List is of type String... I could interchange the extends and super but i get compilation error?

You're right that both ? extends String and ? super String includes String. But you are missing the point that, ? super String also includes CharSequence, Object, which is not in bounds of ? extends String. You can add a String to a List<? super String>, b'coz whatever type that list is of, it can definitely refer to a String. But, you cannot add say an Integer to a List<? extends Number>, because the list can be a List<Float> actually.

In case of write ? super Object is not working? It should work as it is super of String?

Object is a super class of String will fit in where you have ? super String, and use Object for that. So, ? super String can capture Object, but ? super Object cannot capture String, as String is not a super type of Object. Think of it like this: "Actual type replaces the ?, and it must satisfy the rules attached to that ?.

like image 40
Rohit Jain Avatar answered Dec 31 '25 17:12

Rohit Jain



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!