泛型
什么是泛型:
泛型就相当于标签
形式:<>
jdk1.5之后,用泛型来解决元素类型不确定的数据保存操作,
例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
没有泛型的集合
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(98);
al.add(18);
al.add(38);
al.add(88);
al.add("丽丽");
for (Object o : al) {
System.out.print(o+" ");
}
}
如果不使用泛型的话,有缺点:
一般我们在使用的时候基本上往集合里随意放值,因为底层是一个obj类型的数组,所以什么都能放,不方便管理。
在jdk1.5以后开始,使用泛型加入泛型的优点:在编译的时候就会对类型进行检查,不是泛型的就无法添加到这个集合
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList();
al.add(98);
al.add(18);
al.add(38);
al.add(88);
for (Integer o : al) {
System.out.print(o+" ");
}
}
总结:
- JDK1.5之后
- 泛型实际就是一个<>引起来的参数类型,这个参数类型具体在使用的时候才会确定类型
- 使用了泛型后,可以确定集合的类型,在编译的时候就可以检查出来
- 使用泛型可能觉得麻烦,实际上使用泛型才会简单,后续的便利操作会简单许多
- 泛型对应的类型都是引用类型不能是基本类型
泛型类和泛型接口
声明泛型类时传入类型实参 创建泛型类对象时,传入类型实参 类型实参为空时,默认为Object类型
继承泛型类:
1.泛型父类不传入类型实参,默认为Object类型 2.泛型父类传入类型实参,子类既可以是泛型类,也可以不是 3.泛型父类传入类型实参,则子类必须是泛型类,且子类的类型形参列表必须包含父类的类型形参列表
泛型类的定义和实例化,如果实例化的时候不明确指定泛型,那么默认为Object类型
package TestGeneric.GenericTest;
public class test01<e> {
/*
* 这是一个普通类
* test01就是一个泛型类
* <>里面就是一个参数类型,但是这个类型是什么?,不确定,相当于一个占位
* 但是现在确定的是这个类型一定是引用类型,而不是基本类型
* */
int age;
String name;
e sex;
public void a(e n){
}
public void b(e[] n){
}
static class Test{
public static void main(String[] args) {
test01 gt1 = new test01();
gt1.a("abc");
gt1.a(17);
gt1.a(9.8);
gt1.b(new String[]{"a","b","A"});
test01<String> gt2 = new test01<>();
gt2.sex ="男";
gt2.a("abc");
gt2.b(new String[]{"a","b","A"});
}
}
}
继承:父类指定泛型接口
当父类指定了泛型类型,子类就不许要再指定了,可以直接使用
static class SubGeneric extends test01<Integer>{
}
static class Demo{
public static void main(String[] args) {
SubGeneric sgt = new SubGeneric();
sgt.a(19);
}
}
继承:父类不指定
如果父类不指定泛型,那么子类在实例化的时候需要指定
static class SubGeneric2<e> extends test01<e>{
}
泛型类可以定义多个参数类型
泛型类的构造器写法:
不同泛型的引用类型不可以互相赋值
泛型如果不指定,就会被擦除,例子就是
泛型类中的静态方法不能使用类的泛型
不能直接使用泛型数组的创建,如果非要创建
泛型方法
- 什么是泛型方法,不是带泛型的方法就是泛型方法,泛型方法有要求:这个方法的泛型参数类型要和当前类的泛型方法的泛型无关
- 换个角度:泛型方法对应的那个泛型参数类型和当前所在的这个类,是否为泛型类,泛型是啥,无关
- 泛型方法定义的时候,前面要加上t,原因如果不加的话,会把t当作一种数据类型,然而代码中没有t类型那么就会报错
- t的类型实在调用方法的时候确定的
- 泛型方法是否是静态方法?可以是
代码类型:
public class test02<e> {
public void a(e e){
}
public static <T> void b(T t){
}
static class Demo{
public static void main(String[] args) {
test02<String> t2 = new test02();
t2.a("1");
t2.b("abc");
}
}
泛型参数存在继承的情况
前面两个引用类型,都可以赋值,为什么list不行?
其实我们用的Arraylist,他的底层是一个Obj类型的数组,我们的泛型负责在编译的时候限制类型,
例子:两个类,a,b两类,a是b的父类,两者是继承关系,但是 G ,G 两者不存在继承关系,应为他们都是引用Arraylist所以是同级关系
通配符
当我想要重载不同泛型的list时,常见的重载无法让我们完成需求,于是我们需要通配符
在没有通配符的情况下,下面a方法,相当于重复定义
通配符是什么?
发现:两个类,a,b两类,a是b的父类,两者是继承关系,但是 G< a> ,G< b>两者不存在继承关系,应为他们都是引用Arraylist所以是同级关系但是使用了通配符后,我们发现G变成了G< a> ,G< b>的父类
使用通配符
无边界通配符( ?),固定上边界通配符(?extends 上界类),固定下边界通配符(?super 下界类)
学习主要就是为了方便查看API文档
使用小细节
public void a(List<?> list){
// 遍历
for (Object o : list) {
System.out.println(o);
}
// 数据的写入操作
// list.add("abc");--》出错,不能随意的写入
// 读取操作
Object s = list.get(0);
}
泛型受限
并列关系,我们如何限制类型,
- 用extends的是本类和类所有的子类:定义上限
- 用super是本类和本类的父类,定义下限
List<Object> a = new ArrayList<>();
List<Person> b = new ArrayList<>();
List<Student> c = new ArrayList<>();
A,B,C三个泛型的类型不相同,Person是Student的父类