Java拾贝第十天——通配符与泛型
Java拾贝不建议作为0基础学习,都是本人想到什么写什么
现有如下栗子:
public class Test10 {
public static void main(String[] args) {
Gen<String> gen = new Gen<>();
tell(gen);
}
public static void tell(Gen<Object> gen) {//普通方法使用泛型作为传参,并指定泛型类型位Object
System.out.println("泛型使用Object,理论上接收所有类型的gen");
}
}
class Gen<T> {}//泛型类
程序运行结果:
java: 不兼容的类型: moudle1.Gen<java.lang.String>
无法转换为moudle1.Gen<java.lang.Object>
尽管String是Object的子类,但泛型指定了类型后,编译器会严格检查传参的合法性。
想要上述栗子得以编译通过可以修改:
public static void tell(Gen gen) {//即不指定泛型的数据类型
System.out.println("不指定泛型类型,但会导致泛型擦除");
}
至此编译确实可以通过,但这不是好的解决办法。
为此Java提供了通配符
通配符
通配符表示可以接收任意泛型对象。通配符表示为<?>
栗子:
public class Test10 {
public static void main(String[] args) {
Gen<String> gen1 = new Gen<>();
tell(gen1);
Gen<Integer> gen2 = new Gen<>();
tell(gen2);
Gen<Boolean> gen3 = new Gen<>();
tell(gen3);
}
public static void tell(Gen<?> gen) {//使用通配符
System.out.println("使用通配符,可以传入任意类型"+gen);
}
}
class Gen<T> {}
程序运行结果:
使用通配符,可以传入任意类型moudle1.Gen@1b6d3586
使用通配符,可以传入任意类型moudle1.Gen@4554617c
使用通配符,可以传入任意类型moudle1.Gen@74a14482
//因为没有重写Gen类的toString()方法所以默认打印对象地址值
通配符不可作为泛型类的指定类型
栗子:
public class Test10 {
public static void main(String[] args) {
Gen<?> gen = new Gen<?>();//编译错误
}
}
class Gen<T> {}
上述写法JVM无法完成初始化。
下述写法也是错误
class Gen<?> {
private ? name;
}
因为JVM碰到<?>只会把它当作通配符,不能作为泛型使用。
受限泛型
泛型是任意数据类型,有时候想人为的限制泛型类型可以使用受限泛型。
受限泛型基于通配符,有以下两种:
<? extends 类名>
<? super 类名>
<? extends 类名>
当希望指定的数据类型只能是某类和其子类,可以使用此受限泛型。
栗子:
public class Test10 {
public static void main(String[] args) {
Gen<AA> gen1 = new Gen<>();
Gen<BB> gen2 = new Gen<>();
Gen<CC> gen3 = new Gen<>();
Gen<DD> gen4 = new Gen<>();
say(gen1);
say(gen2);
say(gen3);
say(gen4);//编译错误 DD不是AA子类
}
public static void say(Gen<? extends AA> temp) {//extends
System.out.println("受限泛型为AA和其子类" + temp);
}
}
class Gen<T>{}
class AA { }
class BB extends AA { }
class CC extends AA{ }
class DD {}
当希望指定的数据类型只能是某接口和其实现类,使用受限泛型<? extends 类名>。
栗子:
public class Test10 {
public static void main(String[] args) {
Gen<AA> gen1 = new Gen<>();
Gen<BB> gen2 = new Gen<>();
Gen<CC> gen3 = new Gen<>();
Gen<DD> gen4 = new Gen<>();
say(gen1);
say(gen2);
say(gen3);
say(gen4);//编译错误 DD不是AA实现类
}
public static void say(Gen<? extends AA> temp) {//extends
System.out.println("受限泛型为AA和其实现类" + temp);
}
}
class Gen<T>{}
interface AA { }
class BB implements AA { }
class CC implements AA{ }
class DD {}
<? super 类名>
当希望指定的数据类型只能是某类和其父类,可以使用此受限泛型。
public class Test10 {
public static void main(String[] args) {
Gen<AA> gen1 = new Gen<>();
Gen<BB> gen2 = new Gen<>();
Gen<CC> gen3 = new Gen<>();
Gen<DD> gen4 = new Gen<>();
Gen<Object> gen5 = new Gen<>();//任何类都继承Object
say(gen1);
say(gen2);//编译错误
say(gen3);//编译错误
say(gen4);//编译错误
say(gen5);
}
public static void say(Gen<? super AA> temp) {//super
System.out.println("受限泛型为AA和其父类" + temp);
}
}
class Gen<T>{}
class AA { }
class BB extends AA { }
class CC extends AA{ }
class DD {}
受限泛型可以作用于泛型类
和泛型类一样。
栗子:
class Gen<T extends AA> {//泛型T只能是AA和其子类
private T name;
//...
}
class AA { }
class BB extends AA { }
class CC extends AA { }
class DD { }
受限泛型可以作用于泛型方法
和泛型方法一样
栗子:
class Gen<T extends AA> {
private T name;
public <K extends BB> void Tb(){//泛型方法中自己定义了一个泛型K
}
//...
}
嵌套泛型
泛型即广泛的类型,当然可以接收泛型类。
栗子:
public class Test10 {
public static void main(String[] args) {
U< P<String, Integer> > pu = new U<>();
}
}
class U<T> {}//泛型类U 有一个泛型
class P<K,V>{}//泛型类P 有两个泛型