Java泛型(7):无界通配符<?>

无界通配符<?>很容易和原生类型混淆。

以List为例:

List表示持有任何Object类型的原生List,其实就等价于List<Object>

List<?>表示某种具有特定类型的非原生List(同构集合),只是我们不知道它的具体类型是什么,所以我们就不允许往里set数据

看下面例子:

 1 public class Wildcards {
 2 
 3     // 这里Holder等价于Holder<Object>,Holder<Object>没警告但下面的方法调用时除第一个都会报ERROR,Holder会有警告
 4     static void saveData(Holder holder, Object arg) {
 5         holder.set(arg); // [Warning] Type safety: The method set(Object) belongs to the raw type Holder. References to generic type Holder<T> should be parameterized
 6         Object obj = holder.get();
 7         System.out.println(obj.getClass().getSimpleName() + ": " + obj.toString());
 8     }
 9 
10     // 因为不知道Holder<?>的具体类型是什么,所以我们就不允许往里set数据
11     static void saveDataError(Holder<?> holder, Object arg) {
12         // holder.set(arg); // [Compile Error] The method set(capture#1-of ?) in the type Holder<capture#1-of ?> is not applicable for the arguments (Object)
13         // holder.set(new Wildcards()); // Same Compile Error
14         Object obj = holder.get();
15         System.out.println(obj.getClass().getSimpleName() + ": " + obj.toString());
16     }
17 
18     public static void main(String[] args) {
19         Holder h1 = new Holder<Long>();
20         Holder<Long> h2 = new Holder<Long>();
21         Holder<?> h3 = new Holder<Long>();
22         Holder<? extends Long> h4 = new Holder<Long>();
23 
24         saveData(h1, 1L); // Long: 1
25         saveData(h2, 2L); // Long: 2
26         saveData(h3, 3L); // Long: 3
27         saveData(h4, 4L); // Long: 4
28 
29         saveDataError(h1, 5L); // Long: 1
30         saveDataError(h2, 6L); // Long: 2
31         saveDataError(h3, 7L); // Long: 3
32         saveDataError(h4, 8L); // Long: 4
33     }
34 }
35 
36 class Holder<T> {
37     private T value;
38     public Holder() { }
39     public Holder(T val) { value = val; }
40     public void set(T val) { value = val; }
41     public T get() { return value; }
42     @Override public boolean equals(Object obj) { return value.equals(obj); }
43 }

捕获转换技术

如果向一个使用<?>的方法传递原生类型,那么对于编辑器来说,可能会推断出实际的类型参数,使得这个方法可以调用另一个使用确切类型的的方法。下面是一个例子:

 1 public class CaptureConversion {
 2 
 3     static <T> void getData(Holder<T> holder) {
 4         T t = holder.get();
 5         System.out.println(t.getClass().getSimpleName() + ": " + t);
 6     }
 7 
 8     static void chapterGet(Holder<?> holder) {
 9         getData(holder);
10     }
11 
12     public static void main(String[] args) {
13         Holder h1 = new Holder<Long>(1L);
14         chapterGet(h1); // Long: 1
15     }
16 }
原文地址:https://www.cnblogs.com/storml/p/8005804.html