The wildcard ? in generics represents an unknown type and accepts only null.
However, in the following example, the constructor accepts (for example) a String object, even though I have declared an instance of Test<?>.
public class Test<T> {
private T object;
public Test(T object) {
this.object = object;
}
public void set(T object) {
this.object = object;
}
public static void main(String[] args) {
Test<?> test = new Test<>("Test"); // compiles fine
//test.set("Test"); // compiler error
}
}
Why does this compile normally?
No. You have declared a variable of type
Test<?>. You have created an instance of typeTest<X>, for someXthat the compiler is obliged to figure out for itself such that the overall statement is valid. That is, here:... the
<>does not mean "copy the type parameter from the type of the variable" or anything much like that.Test<?>is not the type of the expressionnew Test<>("Test"). That the chosen type parameter must make the type assignable to typeTest<?>is one of the constraints that must be satisfied, but that's trivial, because anyXwill do for that.Formally, Java will infer the most specific type parameter that satisfies all the constraints for the statement to be valid.
new Test<X>("Test")is valid only for a relatively fewXs:java.lang.Objectjava.lang.Serializablejava.lang.Comparable<String>and a few other variations onComparablejava.lang.CharSequencejava.lang.constant.Constable(since Java 12)java.lang.constant.ConstantDesc(since Java 12)java.lang.StringStringis the most specific of those, so it is the one chosen.In practice, however, Java doesn't actually have to choose a specific type parameter at all. It just has to satisfy itself that there is at least one that works.
The expression
test.set("Test")is a different case. It doesn't matter that the object assigned totestwas inferred to have typeTest<String>. Here, as under all circumstances, Java analyzes the expression based on the declared types of any variables involved.testis declared with typeTest<?>. There is therefore no type whatever that Java can be confidenttest.set()will accept as an argument. However, the valuenullis compatible with every reference type, so whatever the particular type parameter of the objecttestreferences might be,nullis an acceptable argument totest.set().