For a generic interface:
public interface Foo<T> {
void f(T t);
}
The difference between the two fields:
public class Bar {
Foo foo1;
Foo<?> foo2;
}
Is that foo2
is a generic Type and foo
is not. Since ?
is a wildcard (which I think means any type) and every type is a sub-type of Object, then I wold expect Foo<?>
and Foo<Object>
to semantically and syntactically equivalent.
However, check out the following:
public class Puzzler {
void f() {
Integer i = null;
Foo<?> foo1 = null;
foo1.foo(i); // ERROR
Foo foo2 = null;
foo2.foo(i); // OKAY
Foo<Integer> foo3 = null;
foo3.foo(i); // OKAY
Foo<Object> foo4 = null;
foo4.foo(i); // OKAY
}
private interface Foo<T> {
void foo(T t);
}
}
So Foo<?>
and Foo<Object>
are not the same syntactically.
What's going on here? I'm pretty stuck in trying to understand this.
The difference is that if you have a type parameter U, you can use that type inside the method; if you use a wildcard, you don't have access to the actual type inside the method (you only know that it is some unknown type that extends Number).
In the Java programming language, the wildcard ? is a special kind of type argument that controls the type safety of the use of generic (parameterized) types. It can be used in variable declarations and instantiations as well as in method definitions, but not in the definition of a generic type.
The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.
Well there's no difference between the first two - they're just using different names for the type parameter ( E or T ).
Foo<?>
is semantically the same as Foo<? extends Object>
: it is a Foo
with type parameter of something specific, but the only thing known about "something" is that it is some subclass of Object
(which isn't saying too much, since all classes are subclasses of Object
). Foo<Object>
, on the other hand, is a Foo
with type parameter specifically Object
. While everything is assignment-compatible with Object
, not everything will be assignment-compatible with ?
where ?
extends Object
.
Here's an example of why Foo<?>
should generate an error:
public class StringFoo implements Foo<String> {
void foo(String t) { . . . }
}
Now change your example to this:
Foo<?> foo1 = new StringFoo();
Since i
is an Integer
, there's no way that the compiler should allow foo1.foo(i)
to compile.
Note that
Foo<Object> foo4 = new StringFoo();
will also not compile according to the rules for matching parameterized types since Object
and String
are provably distinct types.
Foo
(without type parameter at all—a raw type) should usually be considered a programming error. According to the Java Language Specification (§4.8), however, the compiler accepts such code in order to not break non-generic, legacy code.
Because of type erasure, none of this makes any difference to generated the byte code. That is, the only differences between these are at compile time.
Consider these types:
List<Object>
List<CharSequence>
List<String>
Even though String
is a subtype of CharSequence
which is a subtype of Object
, these List types do not have any subtype-supertype relationships. (Curiously, String[]
is a subtype of CharSequence[]
which is a subtype of Object[]
, but that's for historical reasons.)
Suppose we want to write a method which prints a List. If we do
void print(List<Object> list) {...}
this will not be able to print a List<String>
(without hacks), since a List<String>
is not a List<Object>
. But with wildcards, we can write
void print(List<?> list) {...}
and pass it any List.
Wildcards can have upper and lower bounds for added flexibility. Say we want to print a list which contains only CharSequence
s. If we do
void print(List<CharSequence> list) {...}
then we encounter the same problem -- we can only pass it a List<CharSequence>
, and our List<String>
is not a List<CharSequence>
. But if we instead do
void print(List<? extends CharSequence> list) {...}
Then we can pass this a List<String>
, and a List<StringBuilder>
, and so forth.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With