一、为什么要有泛型
【1】解决元素存储的安全性问题。
【2】解决获取数据元素时,需要类型强转的问题。
【3】可以统一数据类型,便于操作。
【4】将运行时的异常提前到了编译时,提高了效率。
【5】实现代码的模板化,把数据类型当作参数传递,提高了可重用性。
【6】只要在编译时期没有出现警告,那么运行时期就不会出现 ClassCastException 异常。
public class Demo {
//泛型在使用时必须左右一致,不存在继承;
public static void main(String[] args) {
ArrayList<?> list1 ;
ArrayList<String> list2 = new ArrayList<String>();
ArrayList<Integer> list3 = new ArrayList<Integer>();
ArrayList<Object> list4 = new ArrayList<String>();//泛型在使用时必须左右一致,不存在继承;
list1 = list2;
list1 = list3;//不会报错,使用了通配符,通配符表示任意类型,这是在使用,把?当成任何一种类型,
//?就是任何类型。
list2 = list3; //会报错 因为两者在定义时使用泛型,一旦确定了类型就不能够改变类型,
//只能是给定的一种泛型类型。
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
二、泛型类
定义在类上的泛型是在创建对象时确定:
public class MyClass1<E> {
/** 定义具有泛型的类
* 修饰符 class 类名 <范型变量>{
* 范型变量一般用E,K,V,T;
* }
*/
//......
}
1
2
3
4
5
6
7
8
三、泛型接口
由实现类对象确定
/*
泛型接口(接口上含有泛型)
格式:
public abstract interface 接口名<泛型变量> {}
*/
public interface MyInter<T> {
//......
}
1
2
3
4
5
6
7
8
四、泛型方法
创建在放方法上的泛型是在真正调用方法时确定,一般都由传入的参数确定,包含这个方法的类创建对象时,并不会确定方法上的类型,一定在调用方法时确定。
/*
泛型方法(方法上含有泛型)
格式:
修饰符 <泛型变量> 返回值类型 方法名称(参数列表...) {
//...
}
*/
public class MyClass02<T> {
//泛型方法: 泛型E是在方法上自己定义的
public <E> E getE(E e){
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
五、通配符<?>
统配符的使用如下:先说说T和?的区别:基本泛型T是用于定义,将数据类型参数化,不能用于实例化。而 ? 则是在实例化对象时不确定泛型具体参数类型的时候泛指 Object的所有子类型。 但?不能和 Object等效,?是类型实参而不是类型形参,它用于泛指各种类型实参,当具体类型不确定的时候就可以使用?示例如下: