I know my question may seem like a duplicated one but i have read many of the similar questions and answers yet I am confused specifically with lower bounds (? super) . Please consider this code .
import java.util.*;
public class Main {
// just adds numbers to the List nums
static void myadd(List<? super Number> nums){
nums.add(1);
nums.add(1.0f);
nums.add(1.1);
nums.add(3l);
}
public static void main(String[] args) {
List empty= new ArrayList<>();
myadd(empty);
System.out.println(empty);
}
}
Here is the Link to execute it .
According to oracle docs
a lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type
Number class is the superclass of classes Double, Float, Integer, Long, and Short then why this method executes perfectly fine ? This method (myadd) should only work for objects which are direct instances of Number class or it's super type , not for it's sub classes.
I have read following answers still my doubt is not clear .
If anyone can explain I will be obliged.
List<? super Number>means that onlyList<Number>(or some superclass ofNumber, which isObject) can be assigned to that variable (nums, in your example).Because any
Long,Double, etc. is-aNumberinstance, it can be contained in aList<Number>—or, for that matter, aList<Object>. However, if you were to assign an element from the list to another variable, the variable would have to be of typeObject, since the actual type of the list could beList<Object>.List<? extends Number>would mean thatList<Number>orList<Long>orList<Double>or any other subclass ofNumbermay be assigned to that variable.Because such a list is permitted to contain only a certain subclass of
Number—likeLongorDouble—but the particular subclass is unknown, nothing can be safely added to the list. Any of its elements can be assigned to a variable of typeNumber, however.Consider the following examples:
No, this is wrong. As I said, "Because such a list is permitted to contain only a certain subclass of
Number—likeLongorDouble—but the particular subclass is unknown, nothing can be safely added to the list." You can't safely add a subclass ofNumber(or anything) to aList<? extends Number>. The?doesn't mean "any subclass"; it means "unknown subclass". It's a list of some subclass ofNumberthat you don't know.I used some jargon there, "is-a", with which you may be unfamiliar. When one class is a subclass of another, it should be fully substitutable for the superclass. A
Longor aDoublecan perform any operation aNumbercan; we say that aDouble"is-a"Number. An assignment likeNumber x = Integer.valueOf(1)is perfectly fine becauseIntegeris-aNumber. And of course,nums.add(x)would be perfectly fine, because the type ofxisNumber. Would a (widening) cast from typeChildto typeParentsucceed? ThenChildis-aParent.A variable of type
List<?>means that the list has some type, but we don't know what it is. Nothing can be safely added to it, and if we take an element from it, all we know about the type is that it is anObjector any subclass, thus we can only safely assign it toObject. Don't think ofList<?>as "a list of any type", but as "a list of unknown type."A variable of type
List<Object>contains anything that "is-a"Object. Since any type ultimately extendsObject, any type can be added to this list.A
List<Number>contains anything that "is-a"Number.Long,Double, etc. have that "is-a" (subtype) relationship withNumber, so they can be added to the list. I can define my own customNumbertype and add it to the list.A variable of type
List<? extends Number>means that the list has some type, but we only know that the type isNumberor a subclass. We still can't add anything to it safely, because we don't know if it's an alias for aList<Long>,List<Double>, or what have you. But, if we take an element from it, we can assign it toNumberinstead ofObject, because we know at least that it is-aNumber.A variable of type
List<? super Number>means that the list has some type, but we only know that the type isNumberor a superclass. We can add anything that "is-a"Number(which includes subclasses). But, if we take an element from it, we don't know it is aNumber; the alias could point to aList<Object>, so it might contain objects of any class. We can only safely assign its elements to variables of typeObject.You can't use wildcards when you instantiate a generic type. That is, you can't write
new ArrayList<? extends Number>. Wildcards are only used like an alias. A value with no wildcard is only aliased under a type with a wildcard, whether during assignment to a variable, passing as a parameter, or returning as a method result.I keep using the word "safely", because Java generics are about type-safety. If you don't suppress or ignore any type-safety warnings, you won't have any class-cast exceptions at runtime unless there is a corresponding explicit cast in your code. If you suppress or ignore type-safety warnings, you might encounter a class cast exception from a point in your source code where no cast is visible. The compiler inserts these implicit casts for you in order to support generic types.
Back to your original example, let me rewrite it and ask you where your question lies.
Do you not understand that a
Integer,Float,Double, andLongcan be assigned to aNumber? Or do you not understand that aNumbercan be added to aList<? super Number>?