JavaSE——泛型编程
一、为什么要引入泛型编程
看这段代码:
//传统方法:
ArrayList list = new ArrayList();
list.add(new Dog("小黄",5));
list.add(new Dog("小黑",1));
list.add(new Dog("小财",10));
//编译器发现不了这种问题,它是不安全的
list.add(new Cat("招财猫",8));
for(Object o:list){
//向下转型
Dog d = (Dog)o;
System.out.println(d.getName() + "-" + d.getAge());
}
传统方法的问题分析:
- 不能对加入到集合中的数据类型进行约束,这里编译器发现不了,但是实际会抛出异常。
- 遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响。
泛型解决上面这个问题:
//ArrayList<Dog>表示存放到ArrayList集合中的元素是Dog类型
//如果编译器发现添加的类型不满足要求就会报错
//遍历时可以直接取出Dog类型而不是Object
ArrayList<Dog> list = new ArrayList<Dog>();
list.add(new Dog("小黄",5));
list.add(new Dog("小黑",1));
list.add(new Dog("小财",10));
//现在编译器可以发现这种问题,它是不安全的
//list.add(new Cat("招财猫",8));
//可以直接取出Dog,不需要向下转型
for(Dog o:list){
System.out.println(o.getName() + "-" + o.getAge());
}
二、什么是泛型
- 泛型又称参数化类型,解决数据类型的安全性问题。
- 在类声明或者实例化只要指定化需要的具体的类型即可。
- Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。
- 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者某个方法的返回值的类型,或者是参数类型。
class persop<E> {
//E表示 s的数据类型,该数据类型在定义person对象的时候确定,
// 即在编译期间,就确定E是什么类型
E s;
//也可以是参数类型
public persop(E s) {
this.s = s;
}
//做返回类型
public E f(){
return s;
}
}
三、泛型的使用细节
- 泛型必须是引用类型。
- 在给泛型指定具体类型后,可以传入子类型。
- 泛型使用形式:
List<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
List<Integer> list3 = new ArratList<>();
ArrayList<Integer> list4 = new ArrayList<>();
//这样写,泛型默认是Object
ArrayList arraylist = new ArrayList();
四、自定义泛型
4.1自定义泛型类
基本语法:
class 类名<T,R...>{//...表示可以有多个泛型
成员
}
- 普通成员可以使用泛型。
- 使用泛型的数组不可以初始化。
- 静态方法中,不能使用类的泛型。
- 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定类型)。
- 如果在创建对象时没有指定类型,默认为Object 。
class Tiger<T,R,M>{
String name;
//属性使用泛型
R r;
M m;
T t;
//数组在new时不能确定T的类型,不能直接实例化
//T[] ts = new T[8];
public Tiger(String name, R r, M m, T t){//构造器使用泛型
this.name = name;
this.r = r;
this.m = m;
this.t = t;
}
//静态方法不能使用泛型
//静态是和类相关的,在类加载时,对象还没有初始化
//此时如果静态方法和静态属性使用了泛型,JVM就无法完成初始化。
//public static void fun(M m){}
}
4.2自定义泛型接口
基本语法:
interface 接口名<T,R...>{
}
- 接口中,静态成员不能使用泛型。
- 泛型接口的类型在继承接口或者实现接口时确定。
- 没有指定类型则默认为Object。
interface IUsb<U,R>{}
//实现时指定
class c implements IUsb<String,Interger>
//继承时指定
interface MyInterface extends IUsb<String,Integer>{}、
//这时会自动替换
class D implements MyInterface{}
4.3自定义泛型方法
修饰符<T,R...>返回类型 方法名(参数列表){}
- 泛型方法可以定义在普通类中,也可以定义在泛型类中。
- 当泛型方法被调用时,类型会确定。
4.4泛型的继承
- 泛型不具备继承性
//错误,泛型是不存在继承的 List<Object> list = new ArrayList<String>();
- <?>表示支持任意泛型。
- <? extends A>表示支持A类以及A类的子类,规定了泛型的上限。
- <? super A>表示A类以及A类的父类,不限于直接父类,规定了泛型的下限。
public static void printColleaction1(List<?> a) {}
//表示可以接收AA类或者AA类的子类
public static void printColleaction2(List<? extends AA> a) {}
//表示可以接收AA类以及AA类的父类
public static void printColleaction3(List<? super AA> a) {}
class AA{}
class BB extends AA{}
class CC extends BB{}