泛型
## 泛型理解及作用
我们知道,java里面数组可以存储数据,并且只能存储同一种类型的数据,但是他有一个弊端,就是新增和删除元素的时候效率不高,由此出现了list和map等这种和数组具有相同功能的数据结构,我们称其为集合,他们底层的结构或是数组或是链表,总之是减少了数组的弊端。但是,他也有一个缺点,那就是存储的数据类型是任意的,无论是基本数据类型还是引用类型,这样带来的问题是,出现转型错误,例如:
public class Generic1 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add("3");
for (int i = 0; i < list.size(); i++) {
Integer a = (Integer) list.get(i);
}
}
}
在这段代码中,list存储了int和字符串类型数据,后面是把每个元素都转换成integer类型,很显然对应字符串来说会出现类型转换错误,但是这在编译阶段是无法发现的,这就可能使开发人员带来排错的困难和低效率。为了解决这种问题,便出现了泛型,它是jdk1.5有的。
那么什么是泛型呢,其形式如下:
public interface List<E> extends Collection<E> //list接口
List<Integer> list = new ArrayList(); //使用时指定要存储的类型
我们可以看到用一个<>的形式来表示要存储的数据,并且这个数据类型是任意的,在使用时我们只要指定具体类型即可,说白了就是可以给一个集合贴上标签,指定其只能存什么,这就是泛型,它不断克服了存储任意数据类型的缺点,还增加了灵活性,如果在编写代码时不符合要求,那么会直接报错,便于排错。
泛型可以在哪些地方使用
泛型类
泛型类是指泛型定义在类上,用户使用的时候才把具体类型确定下来
public class Generic1 {
public static void main(String[] args) {
//指定具体类型
mygGeneric<String> mygGeneric = new mygGeneric<String>(5,"my is Generic");
System.out.println(mygGeneric.getT());
}
}
class mygGeneric<T>{
int anInt;
T t; //可以这样直接使用
public mygGeneric(int anInt, T t) {
this.anInt = anInt;
this.t = t;
}
public int getAnInt() {
return anInt;
}
public void setAnInt(int anInt) {
this.anInt = anInt;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
泛型之间的继承关系
![image-20201023101453201](https://i-blog.csdnimg.cn/blog_migrate/ebdda1e0370c0d9bedff4559631cecab.png)
![image-20201023101638703](https://i-blog.csdnimg.cn/blog_migrate/26a3e6ad08ba413ff7cca1946180276c.png)
泛型接口
泛型接口用法和类差不多
泛型方法
泛型方法时独立的,与类是否使用了泛型没有关系
public static <U> U testGeneric(U t){
System.out.println(t);
return t;
}
是对于U 的声明,必须显示声明,否则报错
类型通配符
public static void testGeneric2(List<?> t){
System.out.println(t);
for (int i = 0; i < t.size(); i++) {
System.out.println(t.get(i));
}
}
使用?表示可以接受任意类型的参数,都是不能往里面写值,只能读取,因为泛型的存在就是为了确定要写入的数据类型的,?表示任意类型,所以无法写值。
通配符上限
类型通配符上限和下限
List<? extends Student> list1 = null; //上限
List<? super Person> list2 = null; // 下限
List<Student> list3 = null;
List<Person> list4 = null;
list1 = list4; //会报错
list1 = list3;
list2=list3; //会报错
list2=list4;
类型通配符上限
如果是List<? extends Student>这种类型,那么代表存储的元素只能是Student或Student的子类,而Person是Student的父类,所以list1 = list4会报错。
类型通配符下限
如果是ListList<? super Person>这种类型,那么代表存储的元素只能是Person或Person的父类,而Student是Person的子类,所以list2 = list3会报错。
泛型擦除
所谓反应擦除是指泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。也就是在运行时List还是会被解析为List,只不过在编译阶段确定了Object具体类型。