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 }