// Exploring the meaning of wildcards.
public class Wildcards {
// Raw argument:
static void rawArgs(Holder holder, Object arg) {
holder.set(arg); // Warning:
// Unchecked call to set(T) as a
// member of the raw type Holder
holder.set(new Wildcards()); // Same warning
// Can't do this; don't have any 'T':
// T t = holder.get();
// OK, but type information has been lost:
Object obj = holder.get();
}
// Similar to rawArgs(), but errors instead of warnings:
static void unboundedArg(Holder<?> holder, Object arg) {
// holder.set(arg); // Error:
// set(capture of ?) in Holder<capture of ?>
// cannot be applied to (Object)
// holder.set(new Wildcards()); // Same error
// Can't do this; don't have any 'T':
// T t = holder.get();
// OK, but type information has been lost:
Object obj = holder.get();
}
static <T> T exact1(Holder<T> holder) {
T t = holder.get();
return t;
}
static <T> T exact2(Holder<T> holder, T arg) {
holder.set(arg);
T t = holder.get();
return t;
}
static <T> T wildSubtype(Holder<? extends T> holder, T arg) {
// holder.set(arg); // Error:
// set(capture of ? extends T) in
// Holder<capture of ? extends T>
// cannot be applied to (T)
T t = holder.get();
return t;
}
static <T> void wildSupertype(Holder<? super T> holder, T arg) {
holder.set(arg);
// T t = holder.get(); // Error:
// Incompatible types: found Object, required T
// OK, but type information has been lost:
Object obj = holder.get();
}
public static void main(String[] args) {
Holder raw = new Holder<Long>();
// Or:
raw = new Holder();
Holder<Long> qualified = new Holder<Long>();
Holder<?> unbounded = new Holder<Long>();
Holder<? extends Long> bounded = new Holder<Long>();
Long lng = 1L;
rawArgs(raw, lng);
rawArgs(qualified, lng);
rawArgs(unbounded, lng);
rawArgs(bounded, lng);
unboundedArg(raw, lng);
unboundedArg(qualified, lng);
unboundedArg(unbounded, lng);
unboundedArg(bounded, lng);
Object r1 = exact1(raw); // Warnings:
// Unchecked conversion from Holder to Holder<T>
// Unchecked method invocation: exact1(Holder<T>)
// is applied to (Holder)
Long r2 = exact1(qualified);
Object r3 = exact1(unbounded); // Must return Object
Long r4 = exact1(bounded);
//Long r5 = exact2(raw, lng); // Warnings:
// Unchecked conversion from Holder to Holder<Long>
// Unchecked method invocation: exact2(Holder<T>,T)
// is applied to (Holder,Long)
Long r6 = exact2(qualified, lng);
// Long r7 = exact2(unbounded, lng); // Error:
// exact2(Holder<T>,T) cannot be applied to
// (Holder<capture of ?>,Long)
//Long r8 = exact2(bounded, lng); // Error:
// exact2(Holder<T>,T) cannot be applied
// to (Holder<capture of ? extends Long>,Long)
//Long r9 = wildSubtype(raw, lng); // Warnings:
// Unchecked conversion from Holder
// to Holder<? extends Long>
// Unchecked method invocation:
// wildSubtype(Holder<? extends T>,T) is
// applied to (Holder,Long)
Long r10 = wildSubtype(qualified, lng);
// OK, but can only return Object:
//Object r11 = wildSubtype(unbounded, lng);
Long r12 = wildSubtype(bounded, lng);
// wildSupertype(raw, lng); // Warnings:
// Unchecked conversion from Holder
// to Holder<? super Long>
// Unchecked method invocation:
// wildSupertype(Holder<? super T>,T)
// is applied to (Holder,Long)
wildSupertype(qualified, lng);
// wildSupertype(unbounded, lng); // Error:
// wildSupertype(Holder<? super T>,T) cannot be
// applied to (Holder<capture of ?>,Long)
// wildSupertype(bounded, lng); // Error:
// wildSupertype(Holder<? super T>,T) cannot be
// applied to (Holder<capture of ? extends Long>,Long)
}
} ///:~
rawArgs,编译器知道Holder是一个泛型,即使在这里被表示成一个原生类型,编译器知道向set传递一个Object是不安全的。由于是原生类型,可以将任何类型的对象传递给set,而这个对象将被向上转型为Object,因此只要使用了原生类型,都会放弃编译期检查?unboundedArg说明Holder和Holder<?>不同,Holder持有任何类型的组合,Holder<?>持有具有某种具体类型的同构集合,因此不能只是传Object。exact1和exact2都使用了确切参数,但是exac2有额外的参数。wildSubtype中,入参是任何扩展至T对象的Holder,若T是Fruit,那么holder可以是Holder<Apple>,为防止将Orange放入Holder<Apple>中,对set调用(或者对任何接受这个类型参数为参数的方法的调用)都是不允许的,但是任何来自Holder<? extends Fruit>的对象至少是Fruit,因此get()(或者任何将产生具有这个类型参数的返回值的方法)都是允许的。wildSupertype展示了超类型通配符:holder可以是持有任何T的基类型的容器。因此set可以接受T,因为任何可以工作于基类的对象都可以多态地作用于导出类(T),但是因为持有类型可能是任意超类,get唯一安全的类型就是Object。向exact1传递一个无界引用,不会有确定返回类型的类型信息。wildSubtype希望从泛型参数中返回类型确定的返回值,wildSupertype希望接受类型确定的参数。
public class CaptureConversion {
static <T> void f1(Holder<T> holder) {
T t = holder.get();
System.out.println(t.getClass().getSimpleName());
}
static void f2(Holder<?> holder) {
f1(holder); // Call with captured type
}
//@SuppressWarnings("unchecked")
public static void main(String[] args) {
Holder raw = new Holder<Integer>(1);
//f1(raw); // Produces warnings
//f2(raw); // No warnings
Holder rawBasic = new Holder();
rawBasic.set(new Object()); // Warning
//f2(rawBasic); // No warnings
f1(rawBasic);
// Upcast to Holder<?>, still figures it out:
Holder<?> wildcarded = new Holder<Double>(1.0);
f2(wildcarded);
}
}
f1中的类型参数都是确切的,没有通配符或边界。f2中,f1被调用,而f1需要确切,参数类型在f2被捕获。在方法内部,需要使用确切类型需要使用捕获转换。不能从f2中返回T,因为T对于f2是未知的。
练习29:
static void f3(Holder<List<?>> holder, List l, List<?> j) {
List<?> t = holder.get();
t.clear();
Object t1 = holder.get();
List list = (List) t1;
//list.
holder.set(l);
List t2 = holder.get();
holder.set(j);
System.out.println(holder.getClass().getSimpleName());
}
static <T> void f4(List<Holder<?>> holder, List l, List<?> j) {
Holder<T> holder1=null;
holder.add(holder1);
Holder<?> holder2=null;
holder.add(holder2);
Holder holder3 = holder.get(0);
Holder<?> holder4 = holder.get(0);
Holder<T> holder5 = holder.get(0);//此处报错
}