generics unchecked warning conversion - java

I have read in generics that "? extends Object" and "?" are synonymous then why this occurs.
List list=new ArrayList();
List<? extends Object> list2=list; //1
List<?> list3=list; //2
For 1 unchecked conversion warning is thrown but not for 2. So the compiler somewhere is definitely differentiating between the two.
Plz explain the difference between the two with respect to the above code

I have read in generics that "? extends Object" and "?" are synonymous
Not quite. The first wildcard has a lower bound, the second does not. For your two examples it should not make a difference (well, except that you can only add null to list2 and list3!).
This lower bound can make a difference: "erasure signature" (I don't know the exact term).
The best example for this is Collections.max(); you will notice that the parameter type is defined as T extends Object & Comparable<? super T>.
This is because prior to Java 5 this method existed and was defined as:
static Object max(Collection coll)
If the type parameter were defined as T extends Comparable<? super T>, this would have meant that the method in 1.4 would have had to return a Comparable!

Because some type information is erased during compilation, not all types are available at run time. Types that are completely available at run time are known as reifiable types(see http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7).
So according to JLS List<?> is a reifiable type, but List<? extends Object> is not, which means they are not the same from compiler point of view.

Related

What subtyping/supertyping rule in the Java Language Specification allows this assignment?

Suppose I have this (contrived) situation:
public final Comparable<? super Number> frob() {
return x -> 0; // whatever
}
final Comparable<? super Integer> c = frob();
The JLS defines assignability of reference types in terms of supertypes and subtypes only. Fine.
One of the direct supertypes of a parameterized type is an otherwise equivalent parameterized type with an appropriate containing type (a wildcard expression) in one of its type argument slots. A parameterized type with the same raw type and owner type and that containing type argument (among its others) is thus a direct supertype of the original parameterized type. (So by these rules Comparable<?> is a direct supertype of Comparable<Whatever>, as is Comparable<? extends Whatever>, and Comparable<? super Whatever>, and plenty of others that section 4.5.1 lays out.)
The implication of all this is, loosely speaking, if you have a "receiver" reference a bearing type A in your left hand, and a "payload" reference b bearing type B in your right hand, then b is assignable to a if and only if A is a supertype (not just direct) of B. So presumably what the compiler does is calculate B's supertypes, and then see if the resulting collection of types contains A.
I must be wrong in this presumption, though, because analyzing the supertypes of Comparable<? super Number> by itself following these rules will seemingly never yield Comparable<? super Integer>. (That is, looking at just the type arguments, if you "start from" Number and "go up" its supertype hierarchy to calculate its containing types, you'll never "reach" Integer, because as we all know Integer is a subtype of Number, not a supertype of it.)
So in my example above, what rules in the JLS permit Comparable<? super Integer> to be derived as a direct supertype of Comparable<? super Number>? Is it to be found in the section on type inference, even though to my eye there's no inference going on here (i.e. no diamond operator, no var, etc.)?
To make it clear: my problem is not with the assignment, which I know in practice is of course just fine (if the example method above returns a new Comparable<Object> anonymous class, for example, that would work). It's with my understanding of how the JLS allows this.

Java generics lower bound

I understand upper bound clearly, but don't fully understand lower bound. As for example I have this code:
public class Main<T> {
private T t;
public Main(T t) {
this.t = t;
}
private static class Base {}
public static void main(String[] args) {
Main<? super Base> main = new Main<>(new StringBuilder());
System.out.println(main.t.getClass());
}
}
Why there is no error during compile despite of StringBuilder isn't super class of Base. As I thought it would be illegal to provide type which is irrelevant (I know that it's impossible to assign non child class to t after type inference). Also it works with collections, does it means that collection could possibly store no child, no super class of Base? Please do not link me to PECS questions, I have read them a lot.
Edit: I saw it a little late that #markspace's answer is nearly the same and was posted before this. I am only retaining this here due different styles of explanation, that is all.
This should be due to the diamond operator <> due to which automatic inference happens based on the most possible route, in this case the constructor parameter.
I could not locate the official description of the diamond operator, but various sources describe it to the effect - the Java compiler does a type inference when given the diamond operator feature determines the most suitable constructor declaration that matches the invocation.
If you change your declaration to GenericsSuper<? super Base> main = new GenericsSuper<StringBuilder>(new StringBuilder()) you will get your expected error.
Without this explicit declaration, <> leads to <Object> due to the super restriction, and consequently anything is allowed, because:
The code in GenericsSuper has no problem with StringBuilder. It just wants T.
Base has a common super with StringBuilder in Object.
I'm going to add this as an actual answer.
I think <T> here is Object, which is a legal super type of both Base and StringBuilder. The way you are doing this / thinking about this is flawed, basically. Check out the answer to this question (ignore the duplicate text for PECS):
Difference between <? super T> and <? extends T> in Java
Notice the examples that the accepted answer gives, especially the one with <Object>:
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Since you're allowing the diamond operator to "figure out" the type of T, it "figures out" that Object works and uses that. Untested, but check if this also compiles:
Main<? super Base> main = new Main<Object>(new StringBuilder());

Universal qualifier in Java generics?

I understand the <? extends T> in Java is crudely equivalent to the existential qualifier (∃) but is <? super T> related to the universal qualifier (∀)?
Feel free to correct me if I'm wrong about ∃.
It's early and I'm confused, so may well be talking nonsense. I could buy that both are existential, as direction need not negate the logic for a "for some" relationship..?
Partially prompted by the fact that List[_] in Scala is described as existential and that's roughly the same as List<?> in Java.
Wildcard types (both ? extends T and ? super T) form a subset of existential types. Both of these you can read like "there exists some type which (extends|is supertype of) T". The key idea is that you don't know exact type.
Universal types are just type parameters. For example, here:
class List<T> { ... }
T is arbitrary, like it has an implicit universal qualifier.
Its not really related to predicate logic, its related to the type hierachy. I can understand why you might read out loud <? extends T> as "For all T's" but its extended to "For all objects that have a super class of T" rather than "For all T in X" as in predicate logic.
Similarly <? super X> should be read as "For objects that are of a type that is a super class on X"
The main difference between <? super T> and <? extends T> is that the first declaration says that some type is an ancestor of T and the second says that some type is a subclass of T. I don't see any correlation with existential qualifier or universal qualifier here. As someone noticed in the comments, the more likely similarity (if you really must have one) is type floor and ceiling. Nevertheless, it's really an abstract analogy.

Are we allowed to use wildcard during instantiation

why are these declaration invalid in Java?
List<Number> test = new ArrayList<? extends Number>();
List test = new ArrayList<? extends Number>();
are we not allowed to use wildcard during instantiation. and if the wildcards are only useful for passing them to methods?
and List<Object> test = new ArrayList<Integer>(); is illegal because generics are not covariant correct?
The ? wildcard character means "unknown" not "any". It doesn't make any sense to instantiate a new container of unknown contents, what would you put in there? It can't really be used for anything!
So the declaraion new ArrayList<? extends Number>() Means "some specific thing that extends number, but I don't know what." It does not mean "anything that extends number."
The List<Number> you assigned it to would allow both Double and Integer to be added to it, but the actual contents of a List<? extends Number> might be Float! (or whatever else.)
Consider what would happen in this code if the wildcard worked as an "Any":
List<Integer> listInteger = new ArrayList<Integer>();
listInteger.add(Integer.valueOf(1));
List<? extends Number> listWildCard = listInteger;
listWildCard.add(Double.valueOf(1.0)); //This does not compile
Integer integer = listInteger.get(1);//because this would throw a ClassCastException
Footnote regarding your second example:
Declaring a paramaterized type with no type parameter is called using the Raw Type. This is considered a programming error. The syntax is only legal so that code written before java 5 still compiles. Just don't do it if your scenario isn't backward compatability with pre-java 5.
To understand why it is not allowed to create objects of wildcard parameterized types, you must first understand what's the use of wildcard parameterized types.
Why wildcards?
As you already know that Java generics are invariant. So a List<Number> is not a super class of List<Integer>, even though their type arguments are covariant. So, what if you want such a behaviour in generics too, like having the same reference pointing to different objects? That polymorphic thing, as you would name it. What if you want a single List reference to refer to list of Integer, Float, or Double?
Wildcards to the rescue:
With wildcards, you can achieve the above mentioned behaviour. So, a List<? extends Number> can refer to a List<Integer>, List<Double>, etc. So, the following declarations are valid:
List<? extends Number> numbers = new ArrayList<Integer>();
numbers = new ArrayList<Double>();
numbers = new ArrayList<Float>();
numbers = new ArrayList<String>(); // This is still not valid (you know why)
So what did we change here? Just the reference type of the numbers. Note that generics were introduced in Java for enforcing stronger compile time check. So, it's primarily the compiler's job to decide whether the declaration of a parameterized type is conforming to the rule or not. Without wildcard, compiler shows you error for a List<Number> refering to List<Integer>.
So, wildcards are just a way to introduce co-variance like behaviour into generics. By using wildcards, you increase the flexibility, or you can say, reduce the restriction that compiler enforces. A List<? extends Number> reference tells the compiler that the list can refer to a list of Number or any subtype of Number(Of course, there are lower bounded wildcards too. But that's not the point here. The differences between them is already discussed in many other answers on SO only).
Major uses of wildcard parameterized type you would see with method parameters, where you want to pass different instantiation of a generic type for a single method parameter:
// Compiler sees that this method can take List of any subtype of Number
public void print(List<? extends Number> numbers) {
// print numbers
}
But at runtime, for creating an object you have to give a concrete type. A wildcard - bounded, or unbounded, is not a concrete type. ? extends Number could mean anything that is subtype of Number. So what type of List would you expect to be created when you create a List<? extends Number>?
You can consider this case similar to the reason why you can't instantiate an interface. Because they aren't just concrete.
There is a workaround. Really?
Although this is illegal, you would be surprised to know that there is a workaround, as explained in - Java Generics FAQs. But I really don't think you would ever need that.
When you instantiate a parameterized class, the parameter has to be some known, concrete type. It can be parameterized class even with ? but for inference reasons it has to be concrete. E.g. this is a valid declaration: new ArrayList<List<?>>();
The trick here is that the methods that use the type parameter in the arguments of their signature require the type of the argument to be lower bound. That is, any parameter that you pass in can be cast to the parameter type. Example:
public void fillUp(List<? super T> param)
The fillUp method takes a collection and fills it with T type objects. The param list must be able to handle the T objects so it is declared that the list can contain types that are ancestors of T, T can be safely cast to that type. If T was not a concrete type, like ? extends Number, then it would be impossible to exactly define all ancestors of T.
That's not a valid declaration as it's not a known type. You're not specifying a full type here. new ArrayList<Number> can accept anything that extends Number by subtyping so your use of ? extends Foo is not a valid need.
List<Number> can accept Integer, Long, etc. There's no way to do the equivalent of ? super Foo as it would be semantically meaningless beyond List or List<Object> with a strange artificial restriction.
Your current definition is not true, The generic type should be same in both sides or should be have inheritance relation.
Java generics are not covariant. See, for example, the article Java theory and practice: Generics gotchas by Brian Goetz. Your first example has two problems. First, when you instantiate a type it must be fully specified (including any type parameters). Second, the type parameters must exactly match the left side.
Regarding type covariance (or lack thereof), this is also not legal:
List<Number> test = new ArrayList<Integer>();
despite the fact that Integer extends Number. This also explains why the second example is illegal. A raw type is more or less the same as binding the type parameter to Object, so it would be like:
List<Object> test = new ArrayList<Integer>();
which again fails because generics are not covariant.
As to why the type parameters must be fully specified, the Java Language Specification, §8.1.2 explains the concept:
A generic class declaration defines a set of parameterized types (§4.5), one for each possible invocation of the type parameter section by type arguments.
You can only instantiate an actual type. As long as a type parameter of a generic type is unbound, the generic type itself is incomplete. You need to tell the compiler which specific parameterized type (among the set defined by the generic class) is being instantiated.
As to why generics are not covariant, this was intended to prevent the following sorts of errors:
List<Integer> iTest = new ArrayList<Integer>();
List<Number> test = iTest;
test.add(Double.valueOf(2.5));
Integer foo = iTest.get(0); // Oops!
Do not get confused by the Java inheritance concept and wildcard (e.g. ? here) syntex of Java generic concept. Both are not the same and none of the inheritance rule applies to java generic concept.
Hence Number is not same as ? extends Number
Please note that Java Generic wildcard is intended to tell the compiler about the intended object use. At runtime, it does not exist at all!
If you see generic in java just as a tool to prevent you to make mistakes, you should not go wrong in understanding this concept.

why from unbounded wildcard <?> to <? extends Object> does not generate an unchecked conversion warning?

Think i ask this question before but still don't understand to a certain degree.
From raw to <?> - no unchecked conversion warning. Understood since both are reifiable type.
From raw to <? extends Object> - unchecked conversion warning. Understood since <? extends Object> is a non reifiable type.
From <?> to <? extends Object> - no unchecked conversion warning. Why? Since the former is a reifiable type and the latter is not. I see this as similiar to clause 2.
<?> and <? extends Object> are actually the same thing, and should be interchangeable.
Actually, since List<? extends Object> is a super type of List<?> (vice versa), if it's safe to convert List to List<?>, it should also be safe to convert List to List<? extends Object>.
The spec requires unbounded wildcard <?> in some places, while the twin brother <? extends Object> is not mentioned (therefore forbidden). There's no theoretical reason for that; the language designers probably reasoned that <?> is enough for practical use cases.
For example, in 5.1.9 Unchecked Conversion, converting raw G to G<T1..Tn> generates a mandatory compile-time warning unless all Ti=?. This is a little too harsh; a counter example:
class G<N extends Number>{}
G x = ...;
G<? extends Number> y = x; //warning, tho absolutely safe
the conversion from x to y is safe, and the warning is really unnecessary.
It is possible to relax the rule to exempt all safe conversions.
We know it is safe to convert raw G to G<?..?>; furthermore, if G<T1..Tn> is a super type of G<?..?>, converting G to G<T1..Tn> is also safe, and should be allowed without warning. This certainly makes sense.
However, checking that G<?..?> is a subtype of G<T1..Tn> is not a trivial task; the language designer probably said, to hell with it, it's not worth the trouble to do this for unchecked conversion, which is not an important part of the type system anyway.
<?> means it can be any subtype.
Every subtype of that will always extend Object.
I believe you wouldn't have a problem if you went from <? extends Number> to <? extends Object> either.

Categories

Resources