泛型,即参数化类型,调用者需要传入一个或数个数据类型参数。
一、分类
1、泛型类
2、泛型方法
3、泛型接口
二、泛型的声明周期
泛型只作用于编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型相关信息擦除。编译后的字节码文件不含泛型信息,即不能进入运行时阶段。
三、泛型的一些限制、特性
1、传入的参数:必须是类或接口,不支持对象或基本数据类型;
2、泛型类中的泛型成员或方法不能是静态的;泛型方法可以为静态;
3、泛型存入和取出自动进行类型转换;
4、不能使用泛型父类或接口的引用,指向泛型子类或接口
四、泛型类
1、普通泛型类
public class GenericClass<K,V,S> {
K k;
V v;
S s;
//传入多个类实例
public GenericClass(K k,V v,S s){
this.k =k;
this.v = v;
this.s = s;
}
void display(){
System.out.println("实际类型是:"+k.getClass().getName());
System.out.println("实际类型是:"+v.getClass().getName());
System.out.println("实际类型是:"+s.getClass().getName());
}
public static void main(String[] args) {
//初始化泛型类
GenericClass<String,Integer,Character> st = new GenericClass<String,Integer,Character>("s",89,'4');
st.display();
}
}
2、限制泛型类
语法结构:
1) 上界限制 --T是FatherClass或其子类,且实现接口1、接口2
<T extends FatherClass & Interface1,Interface2>
2) 下界限制 --T必须是SonClass或其父类
<T super SonClass>
public class RestrictGenericClass<T extends FatherClass & Serializable> {
T t;
public RestrictGenericClass(T t){
this.t = t;
}
public void display(){
System.out.println("实际类型为:"+t.getClass().getName());
}
public static void main(String[] args) {
// TODO Auto-generated method stub
RestrictGenericClass<FatherClass> st = new RestrictGenericClass<FatherClass>(new FatherClass());
st.display();
}
}
3、原生态的不安全性-使用原生类型声明变量,应指明参数类型
//1、使用原生类型未指定参数带来的隐患
List li = new ArrayList<String>(); //未指明参数类型,默认为Object
li.add(1);
//2、直到运行阶段-取出使用时,才报类型转换错误
String s = (String)li.get(0);
System.out.println(s);
//3、正确用法,若要使用原生类型,应指明参数
List<String> li2 = new ArrayList<String>();
li2.add("s"); //编译报错只能增加add(String)
li2.remove("s");
System.out.println(li2.size());
4、通配符--用于未知类型
应用场景一:
GenericClass<String,Number>并不是GenericClass<Object,Object>的子类型,应用GenericClass<?,?>代替,注意不能添加或修改数据(除了添加null),只能查询;
应用场景二:
GenericClass<? extends Number> c1 = new GenericClass<Integer>(new Integer[]{1,2,3});
即一个父类或接口引用指向子类或接口实例(参数上为父子关系)。