1、为什么使用泛型?
java5增加泛型是为了能够让java集合类记住其元素的数据类型。没有泛型之前,一个数据加入到集合类中之后就被当做Object类型处理,取出以后还需要进行类型转换。效率不高
增加了泛型支持以后就可以为集合类指定数据类型,这样如果添加了不一致的数据类型,代码的编译就不会通过,提高了代码的健壮性
2、泛型的定义
java泛型的设计原则:只要编译时没有出现警告,则不会出现运行时异常
定义类、接口、方法时使用类型形参。具体什么类型可以在声明变量、创建对象、调用方法时动态指定。
例如:在新建list集合时定义了String类型,则list集合中只能加入String类型数据,如果在list中添加其他类型参数会报异常
List<String> strlist=new ArrayList<String>();
strlist.add("疯狂java讲义")
3、定义泛型
3.1、定义泛型类、接口
//定义接口时指定了一个泛型形参
public interface List<E> {
//在接口内,E可以作为类型使用
void add(E e);
Iterator<E> iterator();
}
public interface Iterator<E>{
E next();
}
普通的类也可以使用泛型,例如
public class Apple<T>{
private T info;
public Apple(T info){
this.info=info;
}
public T getInfo() {
return info;
}
public void setInfo(T info) {
this.info = info;
}
}
3.2、从泛型类派生子类
当创建泛型接口或者泛型类的实现类时不能使用泛型,要么传入实际的参数,要么省略不写
- 传入实际参数时,则父类中所有泛型参数的数据类型都已经指定了,重写时要用指定的数据类型
- 不传入实际参数时,java编译器会发出警告,使用了胃镜检查或者不安全的操作,会把父类中的形参当做Object类型处理
不管为泛型形参传入哪一种类型形参,对于java来说都会当做一个类进行处理,在内存中占用一块内存空间,所以在静态方法、静态初始化块、或者惊天变量初始化中不能使用泛型参数
instanceof在泛型中也不能用
3.3、类型通配符
如果Foo是Bar的一个子类型(子接口),而G是具有泛型声明的类或者接口,G<Foo>并不是G<Bar>的子接口
数组中:Foo[]依然会是Bar[]的子接口,Foo[]自动向上转型为Bar[]的方式称为型变。
使用场景:方法的形参
优点:是方法更加通用
无界通配:?
有上限通配:? extends Object
有下限通配:? super Integer
3.4、泛型方法
格式:
修饰符 <T,S>返回值类型 方法名(形参列表) {
//方法体
}
public static <T> fromArray(T[] a, Collection<T> c){
for(T o:a){
c.add(o);
}
}
类型通配符与泛型方法的区别:
泛型方法可以用来代替类型通配符,例如java中Collection接口
类型通配符形式表示为:
public interface Collection<E>{
boolean containAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
}
使用泛型方法形式表示为:
public interface Collection<E>{
<T> boolean containAll(Collection<T> c);
<T extends E> boolean addAll(Collection<T> c);
}
泛型方法允许泛型形参用来表示方法一个或者多个参数之间的依赖关系,或者方法返回值与参数类型之间的类型依赖关系,如果没有这种依赖关系,就不用使用泛型方法