Gio*_*gos 0 java generics wildcard
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
}
}
Run Code Online (Sandbox Code Playgroud)
Why does this compile normally?
the constructor accepts (for example) a
Stringobject, even though I have declared an instance ofTest<?>.
No. You have declared a variable of type Test<?>. You have created an instance of type Test<X>, for some X that the compiler is obliged to figure out for itself such that the overall statement is valid. That is, here:
Run Code Online (Sandbox Code Playgroud)Test<?> test = new Test<>("Test"); // compiles fine
... 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 expression new Test<>("Test"). That the chosen type parameter must make the type assignable to type Test<?> is one of the constraints that must be satisfied, but that's trivial, because any X will 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 few Xs:
java.lang.Objectjava.lang.Serializablejava.lang.Comparable<String> and a few other variations on Comparablejava.lang.CharSequencejava.lang.constant.Constable (since Java 12)java.lang.constant.ConstantDesc (since Java 12)java.lang.StringString is the most specific of those, so it is the one chosen.
然而,实际上,Java 实际上根本不需要选择特定的类型参数。它只需让自己满意,至少有一个有效。
表达式test.set("Test")是不同的情况。test分配给的对象被推断为具有类型并不重要Test<String>。在这里,与在所有情况下一样,Java 根据所涉及的任何变量的声明类型来分析表达式。 test是用 type 声明的Test<?>。因此,Java 没有任何类型可以确信test.set()会接受作为参数。但是,该值null与每个引用类型兼容,因此无论对象test引用的特定类型参数是什么,null都是可接受的参数test.set()。