Java 泛型
1.1 泛型的格式
- 泛型类定义
[访问权限] class 类名称<泛型类型标识1, 泛型类型标识2,...,泛型类型标识n>{
[访问权限] 泛型类型标识 变量名;
[访问权限] 泛型类型标识 方法名称(){};
[访问权限] 返回值类型声明 方法名称(泛型类型标识 变量名称){};
}
class Point<T>{}
- 泛型对象定义
类名称<具体类> 对象名称 = new 类名称<具体类>();
Point<Integer> p = new Point<Integer>();
只能使用包装类
在泛型的指定中是无法指定基本数据类型的,必须设置成一个类,这样在设置一个数字时就必须使用包装类。
- 构造方法上使用泛型
[访问权限] 构造方法([<泛型类型> 参数名称]){}
//例如:
public Point(T var){
this.var = var;
}
- 指定多个泛型
class Notepad<K, V> {
private K key;
private V value;
...
}
1.2 通配符
Info<String> i = new Info<String>();
...
//Object不匹配 String,所以会报错
public void fun(Info<Object> temp){}
Java 中引入了通配符?
,可以表示接收此类型的任意泛型对象。
public void fun(Info<?> temp){}
1.3 受限泛型
在引用传递中,在泛型操作中可以设置一个泛型对象的范围上限和下限。范围上限使用extends
关键字声明,表示参数化的类型可能是所指定的类型或者是此类型的子类。而范围下限使用super
关键字进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,或者是 Object 类。
- 设置上限
声明对象:类名称<? extends 类> 对象名称
定义类:[访问权限] 类名称<泛型标识 extends 类>
范围上限设置为 Number,所以只能接收数字类型:
public void fun(Info<? extends Number> temp){}
...
//正确的泛型传递
Info<Integer> i1 = new Info<Integer>();
Info<Float> i2 = new Info<Float>();
//错误的泛型传递
Info<String> i1 = new Info<String>();
- 设置下限
声明对象:类名称<? super 类> 对象名称
定义类:[访问权限] 类名称<泛型标识 extends 类>
public void fun(Info<? super String> temp){}
...
//正确的泛型传递
Info<Object> i1 = new Info<Object>();
Info<String> i2 = new Info<String>();
//错误的泛型传递
Info<Integer> i1 = new Info<Integer>();
1.4 泛型不能向上转型
Info<String> i1 = new Info<String>();
Info<Object> i2 = null;
i2 = i1;//编译错误
为什么不能使用使用向上转型?
String 是 Obect 的子类,通过对象的多态性 Object 类可以接收任意引用类型的对象,为什么到了泛型中却无法使用了?
回答:如果将子类泛型变为了父类,则表示扩大了子类的内容。
以商场购物为例,现在假设把以上的两个对象 Info<Object> 和 Info<String> 分别当作商场的全部商品和个人已购买的商品信息。一个人购买的肯定是商场中很少的一部分商品,而如果使用“ Info<Object> = Info<String>”,就相当于在个人已购物的商品中加入了全部的商品,相当于个人把整个商场的商品全部买走了,这基本上是不可能的,所以程序无法编译通过。
1.5 泛型接口
[访问权限] interface 接口名称<泛型标识>{}
为了便于区分可以这样命名:
- 接口:
IMessage
- 抽象类:
AbstractMessage
- 普通类:
Message
接口的两种实现方式
- 在子类的定义上声明泛型类型
interface Info<T>{}
...
class InfoImpl<T> implements Info<T>{}
- 直接在接口中指定具体类型
interface Info<T>{}
...
class InfoImpl implements Info<String>{}
参考:Java 开发实战经典(李兴华) 第10章