一、泛型的概念
1.定义:
允许在定义类和接口时,通过一个标识表示①类中某个属性或者是②某个方法的返回值及③参数类型。
这个类型参数将在使用时(例如①继承或实现这个类或接口,②用这个类型申明变量、③创建对象时)确定(即传入实际的类型参数,也称为类型实参)
2.注意:如果实例化时,没有指定泛型的类型,默认类型为Object。
二、自定义泛型结构
1.泛型结构:泛型类、泛型接口、泛型方法
2.代码实现
2.1 泛型类/接口
public class Order<T> {
String orderName;
int orderId;
T orderT;
//类的内部就可以使用泛型
public Order(){
}
public Order(String orderName,int orderId,T orderT){
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
public T getOrderT(){
return orderT;
}
public void setOrderT(T orderT){
this.orderT = orderT;
}
}
泛型类的继承
1.在继承时就指明了父类泛型类型
如:public class SubOrder extend Order<Intger>{ }
在子类实例化时就不需要再指明泛型类型,子类也不再是泛型类。
2.在继承时保留父类泛型类型
如: public class SubOrder<E> extend Order<E>{ }
子类就还是泛型类,实例化时可以选择指定泛型类型。
泛型类的补充
(1)静态方法中不能使用类的泛型,因为泛型在对象实例化时才会被指定,而静态方法早于类对象就实例了,所以不可以使用。
(2)不能使用new E[],但可以使用 E[] elements = (E[]) new Object[10];
(3)父类有泛型,子类可以选择保留泛型也可以选择指定泛型。
- 子类不保留父类的泛型:按需实现
没有类型 擦除
具体类型 - 子类保留父类的泛型:泛型子类
全部保留
部分保留
2.2 泛型方法
1.定义:在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。
泛型方法所属的类是不是泛型类都没有关系。
2.使用:
public <E> List<E> copyFromArrayToList(E[] array){
ArrayList<E> arrayList = new ArrayList<>;
for(E e : array){
arrayList.add(e);
}
return arrayList;
}
为了防止编译时误认为E是类名,所以泛型方法前要加上<泛型类型名>来标记此方法为泛型方法。
泛型方法可以是静态方法,原因是泛型方法是在调用方法时才会指定泛型类。
三、泛型在继承方面的体现
3.1场景引入
类A是类B的父类,G<A>和G<B>不具备父子类关系,二者是并列关系。
所以public void function(List<Object> list){},此类方法的可拓展性就较差。
3.2 通配符
1.通配符的使用:
类A是类B的父类,G<A>和G<B>不具备父子类关系,他们共同的父类是G<?>
2.添加(写入)对于List<?>,不能向其中添加数据。只能通过=赋值。
3.获取(读取):允许读取数据,读取的数据类型为Object。
4.有限制条件的通配符的使用
(1)? extends(≤) :G<? extends A>可以作为G<A>和G<B>的父类,其中B是A的子类
(2)? super(≥):G<? super A>可以作为G<A>和G<B>的父类,其中B是A的父类