The difference is in declaring the type of the return value. List<String> not a subtype of List<T> , but is a subtype of List<?> .
List<?> Makes no assumptions about its type variable, so the following statements are valid:
List<?> l0 = new ArrayList<String>(); List<?> l1 = new ArrayList<Object>(); List<? extends Number> ltemp = null; List<?> l2 = ltemp;
List<T> implies that the type argument will be resolved in the client context (for example, using the type) if you declared it as List<String> or List<Object> . Inside the body of the method, you also cannot make any assumptions about it.
source share