主要总结的内容通配符、受限泛型、泛型与子类继承的限制
一.通配符“?”
一.通配符“?”
在开发中对象的引用传递是最常见的,如果在泛型类的操作中,在进行引用传递的时候泛型类型必须匹配才可以传递,否则无法传递
我们看如下程序:
class Info<T>{
private T var; //var的类型由T指定,即:由外部指定
public T getVar(){ //返回值类型由外部决定
return var;
}
public void setVar(T var){ //设置类型也由外部决定
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericDemo01{
public static void main(String[] args){
Info<String> i = new Info<String>(); //设置String泛型
i.setVar("Jack");
fun(i);
}
public static void fun(<Info<Object> temp){ //接收Object泛型类型数据
System.out.println("内容:"+ temp);
}
}
可见泛型对象进行引用传递的时候,类型必须一致;在创建泛型类对象时引用类型与实例化类型泛型也必须一致。
如果例一非要传递,可以将方法参数中的泛型取消掉,这样能得出结果
public class GenericDemo01{
public static void main(String[] args){
Info<String> i = new Info<String>(); //设置String泛型
i.setVar("Jack");
fun(i);
}
public static void fun(Info temp></strong>){ //接收Object泛型类型数据
System.out.println("内容:"+ temp);
}
}
这样做虽然执行没问题,但有些不合适,因为之前已经定义了泛型了,所以我们可以使用"Info<?> temp"代码形式。表示可以接收任意泛型类型对象
class Info<T>{
private T var; //var的类型由T指定,即:由外部指定
public T getVar(){ //返回值类型由外部决定
return var;
}
public void setVar(T var){ //设置类型也由外部决定
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericDemo04{
public static void main(String[] args){
Info<String> i = new Info<String>();
i.setVar("Jack");
fun(i);
}
public static void fun(Info<?> temp){
System.out.println("内容:"+ temp);
}
}
注意:使用"?"意味着可以接收任意的内容,但是此内容不能使用<?>修饰的泛型对象进行修改
class Info<T>{
private T var; //var的类型由T指定,即:由外部指定
public T getVar(){ //返回值类型由外部决定
return var;
}
public void setVar(T var){ //设置类型也由外部决定
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericDemo05{
public static void main(String[] args){
Info<?> i = new Info<String>();
i.setVar("Jack");
}
}
i.setVar("Jack")对Info<?>修饰的对象进行修改,所以出现错误
所以在使用<?>只能接收,不能修改。
二.受限泛型
在引用传递中,泛型操作中也可以设置一个泛型对象的范围上限和范围下限。上限使用extends关键字声明,表示参数化类型可能是所指定的类型,或者是此类型的子类 ,而范围下限使用super进行声明,表示参数化类型可能是所指定的类型或者此类型的父类型,直至Object类。
设置上限:
声明对象:类名称<? extends 类> 对象名称
定义类:[访问权限]类名称<泛型标识 extends 类>{}
class Info<T>{
private T var; //var的类型由T指定,即:由外部指定
public T getVar(){ //返回值类型由外部决定
return var;
}
public void setVar(T var){ //设置类型也由外部决定
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericDemo06{
public static void main(String[] args){
Info<Integer> i1 = new Info<Integer>(); //声明Integer的泛型对象
Info<Float> i2 = new Info<Float>(); //声明Float的泛型对象
i1.setVar(30);
i2.setVar(30.1f);
fun(i1);
fun(i2);
}
public static void fun(Info<? extends Number> temp){ //只能接收Number类及其子类
System.out.println("内容:"+temp);
}
}
class Info<T extends Number>{
private T var; //var的类型由T指定,即:由外部指定
public T getVar(){ //返回值类型由外部决定
return var;
}
public void setVar(T var){ //设置类型也由外部决定
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericDemo06{
public static void main(String[] args){
Info<Integer> i1 = new Info<Integer>(); //声明Integer的泛型对象,Integer是Number类的子类
}
}
在类中声明了泛型上限是Number类,所以创建泛型对象时如果生命的泛型类型不是Number的子类则会出错
设置下限:
声明对象:类名称<? super类> 对象名称
定义类:[访问权限]类名称<泛型标识 extends 类>{}
class Info<T>{
private T var; //var的类型由T指定,即:由外部指定
public T getVar(){ //返回值类型由外部决定
return var;
}
public void setVar(T var){ //设置类型也由外部决定
this.var = var;
}
public String toString(){
return this.var.toString();
}
}
public class GenericDemo08{
public static void main(String[] args){
Info<String> i1 = new Info<String>();
Info<Object> i1 = new Info<Object>();
i1.setVar("Jack");
i2.setVar(new Object());
fun(i1);
fun(i2);
}
public static void fun(Info<? super String> temp){ //只能接收String或Object类型对象
System.out.println("内容:"+temp);
}
}
三.泛型与子类继承的限制
一个类的子类可以通过对象多态性,为其父类实例化,但是在泛型操作中,子类的泛型是无法使用父类的泛型类型接收的。例如:Info<String> 不能使用Info<Object>接收
注意:Info<Object> i = new Info<String>();是错误的,这不代表“不能把String类型对象赋值给一个Object”,而是说“不能将涉及String的泛型赋给涉及Object的泛型”,即这里根本不是向上转型。Java编程思想中讲解到:“ ArrayList<Fruit> flist = new ArrayList<Apple>();Apple的List不是Fruit的List,Apple的List会持有Apple和Apple的子类型,Fruit的List会持有任意类型的Fruit,Apple的Lsit在类型上不等价于Fruit的List,即使Apple是一种 Fruit类型”
参考资料:
java核心技术卷一
李兴华老师java视频讲解
java编程思想