泛型的介绍:
首先,明确一下,泛型是为了给集合指定对象类型而设立的,
为了解决:假设当往集合加入元素是String类型,你有没有发现一个奇怪的现象,当你把对象取出时,往往却变成了Object类型,也就是说,当你往集合里添加元素时,他不会记住你加的是什么类型,统一返回时把你当成Object类型,所以为了解决这个类型前后不一致的问题,就出现了泛型。
接下来看一下泛型的实例化举例:
ArrayList<String> List =new ArrayList<>();
<>里边是一些类对象。
此时这个集合指定了往里面添加对象的数据类型(往集合中添加元素时,不能单一的添加基础数据类型:ArrayList<int> List =new ArrayList<>();类似这样),此时,制定了数据类型时,往里面添加的数据类型就有了限制,比如此时,若往里边添加integer类的数据就会报错。
为什么要使用泛型:
拿使用数据库来说,每张表可以看做一个类的对象,每个对象对应的都有自己的类,如果给每个类都定义一个操作该类对象的工具类,太过于麻烦,代码冗余性也较高,所以就出现了泛型类和泛型方法,接下来将在代码中进行详细说明:
public class DAO<T> {
//建立一个DAO工具类,给其定义成泛型类,当操作具体类时可以根据类而改变
//同样的,也可以定义一些泛型方法,不指定其操作的具体类型,
// 使具体类继承该类后这些方法可以通用,降低代码冗余量
public T save(){
return null;
}
public List<T> update(){
return null;
}
}
public class CustomerDAO extends DAO<Customer> {
//此时子类的工具类继承后可以指定该DAO具体操作的类对象
//此时这个工具类操作的就是Customer的类对象
}
@Test
public void test1(){
CustomerDAO dao = new CustomerDAO();
//此时这个save()方法操作的就是Customer对象
dao.save();
}
泛型继承方面的体现:
@Test
public void test1(){
ArrayList<?> a1 = new ArrayList<>();
ArrayList<String> a2 = new ArrayList<>();
ArrayList<Object> a3 = new ArrayList<>();
ArrayList<Integer> a4 = new ArrayList<>();
//此时a2无法赋值给a3,证明泛型中,当A是B的父类时
//F<A>和F<B>没有子父类的关系
/*
可以反证一下:假设a3=a2;
那么当a3.add(123)时,a2中也可以出现123,那么定义泛型貌似就没了意义
*/
a3 = a2;
//此时a2能赋值给a1,证明G<?>是任何G<A>的父类
a1 = a2;
List<String> l = null;
//此时可以赋值,证明当A是B的父类时,A<M>是B<M>的父类
l=a2;
}
泛型中通配符的使用及其限制:
@Test
public void test1(){
//先给通配符的集合赋值为null
List<?> list = null;
//通配符的集合无法进行添加操作
// list.add("aa");
ArrayList<Integer> a4 = new ArrayList<>();
a4.add(4);
//但是其可以进行赋值和读取
list = a4;
System.out.println(list);
}
/**
* <? extends A> 表示该通配符表示的类的最大父类是A,通俗的说就是这个类小于等于A
* <? super B> 表示该通配符表示的类的是B的父类,通俗的说就是这个类大于等于B
*/
List<? extends Customer> m1 = null;
List<? super Customer> m2 =null;