2

Could you explain why the first one does not work?

import java.util.ArrayList;
import java.util.List;

public class MyClass {

    private <T extends Object> List<Class<T>> getList1() {
        return new ArrayList<>();
    }

    private <T extends Object> List<Class<T>> getList2(Class<T> cls) {
        List<Class<T>> list = new ArrayList<>();
        list.add(cls);
        return list;
    }

    private List<Class<? extends Object>> getList3() {
        return new ArrayList<>();
    }

    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        // 1. Not OK - The method add(Class<Object>) in the type List<Class<Object>> is not applicable for the arguments (Class<String>)
        myClass.getList1().add(String.class);
        // 2. OK
        myClass.getList2(String.class);
        // 3. OK
        myClass.getList3().add(String.class);
    }

}

I thought getList1() is returning a List of classes those extend from Object, and String is one of those?

And no this is not a duplicated question (at least not to the one being linked). If I really defined a List of Object, of course I don't want it to take a List of String. But here I am accepting a List of Object plus those extending from Object, so the question is why didn't it accept String in the first case.

user1589188
  • 5,316
  • 17
  • 67
  • 130

1 Answers1

5

You can call the method like this:

myClass.<String>getList1().add(String.class);

Somehow the compiler needs to know what your T should be (the <String> is called a type witness).


  • Using your method getList2(String.class) you specify this by passing in the parameter.
  • Using your method getList3() the declaration itself uses a wildcard (?) so you do not have to specify T, but your list will not be strongly typed (it will accept every class extending Object).
JDC
  • 4,247
  • 5
  • 31
  • 74
  • Wow, never seen this before. What is this `` coming from? And I thought the compiler can tell from my last `add(String.class)`? – user1589188 Jul 24 '17 at 07:44
  • 2
    Have a look here (especially the part about the type witness): http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html – JDC Jul 24 '17 at 07:51
  • Thanks. I looked at the page you suggested but still am not sure why the first method didn't compile. Especially at the very bottom of the page it said type witness is no longer needed in J8, in which the compile can infer the type from the parameter. So `.add(String.class)` should infer `T` as `String`, and hence the same `T = String` be used in `getList1()`, no? – user1589188 Jul 25 '17 at 01:56
  • I understand what you mean and I have to honestly confess I do not exactly know the answer. Out of personal interest I posted a follow up question: https://stackoverflow.com/questions/45294380/generic-type-resolution-compiler-steps – JDC Jul 25 '17 at 05:10