Search code examples
javagenericswildcardbounded-wildcard

generics in constructors in Java?


Consider this hypothetical class (which I found in a online video):

public class Contrived<T extends Number> extends ArrayList<T> {
      List <? extends T> values;
      ......
    }

Here the type variables that Contrived can accept is Number or some sub-type of Number. But the class itself inherits from ArrayList, so what-ever type the class gets, will determine the type of ArrayList.

Now there is a field called values, which is List<? extends T values>. so what does this mean here? Does the list can hold anything that extends T (which in turn extend Number).

by PECS (producer extends, consumer super) rule, can I only use this List to read elements but not add to the list.

how will the constructor look like, if I need to pass a list of doubles or some type T?


Solution

  • You can have a constructor that takes a List<T> or a List<? extends T>. Continuing to contrive classes:

    class B extends Number{
       public double doubleValue() { return 0; }
       public float floatValue() { return 0; }
       public long longValue() { return 0; }
       public int intValue() { return 0; }
    }
    class C extends B{}
    

    I add a contrived, legal constructor to the Contrived class, taking a List<? extends T>:

    public Contrived(List<? extends T> values)
    {
       this.values = values;
    }
    

    This allows me to write a main method such as the following:

    public static void main(String[] args)
    {
       List<C> bList = Arrays.asList(new C(), new C(), new C());
       Contrived<B> ci = new Contrived<B>(bList);
    }
    

    I can pass a List<C> into the constructor for a Contrived<B>.

    Another design for the contrived constructor that is legal for Contrived could be, taking a List<T>:

    public Contrived(List<T> values)
    {
       this.values = values;
    }
    

    Such a constructor doesn't allow a List<C> for a Contrived<B>, because now the types must match, as in the following two Contrived examples:

    public static void main(String[] args)
    {
       List<C> cList = Arrays.asList(new C(), new C(), new C());
       Contrived<C> ci = new Contrived<C>(cList);  // must match now
    }
    

    And

    public static void main(String[] args)
    {
       List<B> bList = Arrays.asList(new B(), new B(), new B());
       Contrived<B> ci = new Contrived<B>(bList);  // must match now
    }