Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
202 views
in Technique[技术] by (71.8m points)

java - Generics <? super A> doesn't allow superTypes of A to be added to the list

I am using wildcard and lower bound generics on list and yet compiler is throwing error.

Code:

int intStart = 0;       
Number num = new Integer(2);                
List<? super Integer> listOfNumbers = new ArrayList<>();
listOfNumbers.add(intStart);
listOfNumbers.add(num); //throws compiler error

Error :

The method add(capture#8-of ? super Integer) in the type List is not applicable for the arguments (Number)

With List<? super Integer>, I should have been allowed to add any objects of type Integer or its superTypes e.g. Number or Object. I've gone through some SO discussions, but couldn't find why I should be getting above error.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

With List<? super Integer>, I should have been allowed to add any objects of type Integer or its superTypes e.g. Number or Object.

That's incorrect. List<? super Integer> doesn't mean a list that can hold any supertype of Integer. It means a list whose generic type may be some specific supertype of Integer. So it might actually be List<Object>, List<Number> or List<Integer>. All of those list types may contain an Integer, but the same can't be said for Number. A Number might be a Double or a Long, which isn't allowed in a List<Integer>.

To make it a little more concrete, consider this snippet:

Long longValue = 2L;
List<Integer> listOfIntegers = new ArrayList<>();
// listOfIntegers.add(longValue);

The commented line obviously shouldn't compile, and doesn't. But what if we added this:

Number longAsNumber = longValue;
List<? super Integer> listOfSuper = listOfIntegers;
listOfSuper.add(longAsNumber);

This is equivalent to the snippet in your question. Should the final line compile? If it would, it would violate the generic invariant of List<Integer>.


In response to your comment, List<? super Integer> is indeed unnecessary in your example. A more common case would be to add flexibility to a method parameter. For example, a method

void addInt(List<Integer> list) {
    list.add(1);
}

would only be able to accept List<Integer>, which would be unnecessarily restrictive. Changing the parameter type to List<? super Integer> would allow the method to accept List<Integer> as well as List<Number>, either of which can contain an Integer value.

This only works if the list is consuming the generic type in question. If the method tried to produce values from the list, it would be forced to assume they're of type Object, since we don't have a definite supertype. For more information, see What is PECS (Producer Extends Consumer Super)?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...