Java么么么——泛型
泛型是什么?
泛型就是将类型作为参数进行传递,当创建对象或者调用方法时才确定下具体的数据类型。并且泛型只能传递引用数据类型
为什么需要泛型?
在JDK5之前,对象是用Object来表示的,当要获取具体的对象时,就得进行强制类型转化,非常的麻烦。
比如要往一个集合Collection或者Map 中存放一个对象,存的是Object类型,例如往集合中存放了一个狗Dog对象,然后又往集合中存放了一个猫Cat类型的对象,当要从集合中get一个猫Cat对象时,就得进行类型的转化,比较麻烦,而当用泛型之后,可以将对象的类型作为参数进行传递,这样在具体要用什么对象时,就不用再进行类型转化了。
因此总结起来,使用泛型的好处是:可以让代码更加简洁,因为不用进行强制类型转换;
让程序更加稳健,因为使用泛型在编译阶段没有报错的话,在运行阶段也不会报ClassCastException异常;
怎么使用泛型?
1.定义在类上的泛型 – 泛型类
将泛型定义在类上,这样类的方法也可以使用,当具体要new对象时,用户想要指定哪种类型,该泛型类就可以自动转化为对应的对象类型
2.派生类的泛型
2.1子类有明确泛型的类型
子类有明确泛型的类型,在实现接口时,实现类不用定义出泛型类型
2.2.子类没有明确泛型类型
子类没有明确泛型的类型,在实现接口时,实现类需要定义泛型类型
3.定义在方法上的泛型 – 泛型方法
当只需要在某个方法上应用泛型时,就不用直接定义在类上,直接在方法上定义就可以了。
4.泛型类型通配符
当一个方法中要接收一个集合作为参数时,想要遍历集合并把集合打印出来时,要想明确集合中的对象类型,
如果传的的话,这个在集合遍历时与这些是没有关系的,所以Java泛型提供了类型通配符
类型通配符?可以匹配任何的Java类型。当我们使用?号通配符的时候:就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
4.1通配符上限
如果接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,如果直接使用通配符,那么该集合就不只能匹配数字了,而是任意的Java类型,因此可以设定泛型的通配符上限
例如
List<? extends Number>
4.2通配符下限
类似于通配符上限,下限传递的类型限定只能是某种数据类型及其它的父类。
例如:
//传递进来的只能是Type或Type的父类
<? super Type>
注:大多数时候可以用泛型方法来代替泛型通配符
题目例子:
List< ? extends T > 和 List < ? super T > 之间有什么区别 ? ------ 这两个 List 的声明都是限定通配符的例子,List< ? extends T > 可以接受任何继承自 T 的类型的 List,而List < ? super T > 可以接受任何 T 的父类构成的 List。
5.泛型的类型擦除
类型擦除:泛型只作用在编译阶段,用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。当编译器编译完带有泛型的程序后,生成的class字节码文件是不带有泛型的,也就是说在运行阶段不存在任何类型相关的信息。这样使得程序运行的效率不会受影响,是确保能和 Java 5 之前的版本开发二进制类库进行兼容。这个过程称为类型擦除。
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 < T > 则会被转译成普通的 Object 类型,如果指定了上限如 < T extends String > 则类型参数就被替换成类型上限。
List<String> list = new ArrayList<>();
//类型被擦除了,保留的是类型的上限,String的上限就是Object
List list1 = list;
泛型可以用在哪里?-- 泛型的应用
比如在做项目时,对于Dao层,我们有很多的Dao接口类要编写,而这些Dao接口类都有 一个共同的点就是对数据进行增删改查,因此我们就可以定义一个抽象的Dao泛型类,在里面编写增删改查的方法,这样当有具体的Dao接口去继承它时,再去传递具体的数据类型即可。
例如:
抽象的Dao泛型类
public abstract class BaseDao<T> {
//模拟hibernate....
private Session session;
private Class clazz;
//哪个子类调的这个方法,得到的class就是子类处理的类型(非常重要)
public BaseDao(){
Class clazz = this.getClass(); //拿到的是子类
ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass(); //BaseDao<Category>
clazz = (Class) pt.getActualTypeArguments()[0];
System.out.println(clazz);
}
public void add(T t){
session.save(t);
}
public T find(String id){
return (T) session.get(clazz, id);
}
public void update(T t){
session.update(t);
}
public void delete(String id){
T t = (T) session.get(clazz, id);
session.delete(t);
}
}
其他的具体类型的Dao接口类只要继承这个BaseDao接口,就有进行对应类型的增删改查操作
例如:
public class BookDao extends BaseDao<Book> {
//这个类型就可以进行Book的增删改查操作
}