什么是泛型
泛型的引出:
集合种是可以任意存储对象的,只要把对象存储到集合中,就会被向上转型成为Object类型,当我们将集合中的对象拿出进行操作时,需要进行对象的向下转型(进行强制转换),这是不安全的,因为你可能将不同类型的对象放入了同一个集合中,取出转型时造成转型的错误
打个比方:你创建了一个集合是用来装狗的,然后你将猫也放进去了,猫和狗都向上转型为Object,然后再取出时将猫和够都进行强转成狗,这显然是不合理的!!!
因此在***jdk5***之后新增了泛型机制,不但保证程序的安全性,也不需要进行手动强转
在不运用泛型机制时,直接对集合中的对象进行转型,编译时会抛出ClassCastException,
泛型
- 概念:
- 泛型的核心概念就是告诉编译器想要使用什么类型,由编译器进行检查,本质上就是参数化类型,使得可以在类或者方法中预知的使用“未知”的类型
- 泛型是一种编译时类型安全的检查机制
- 泛型带来的好处:
- 由于不需要手动的对集合里的对象进行转型,代码变得更加简洁
- 程序更加的健壮,只要编译期没有警告,运行期就不会抛出ClassCastException异常
- 提高了代码的可读性和稳定性
泛型基础
泛型类
- 定义中含有泛型的类:class 类名<泛型参数>{}
- 一般泛型参数可以任意标识,常见的有 T\K\V…等
例如:java api中ArrayList集合的定义
class ArrayList<E>{
public boolean add(E e){ }
public E get(int index){ }
....
}
注意事项
1. 实例化泛型类时必须给定参数的类型,不能是基本类型
2. 构造方法中可以省略类型参数,其省略的参数类型将会从指定的具体类型参数中推断出来(泛型就是将类型明确的工作推迟到创建对象或调用方法的时候去明确的特殊类型)
3. 在类上定义泛型,在类的方法中也可以使用
泛型方法
- 定义中含有泛型的方法:修饰符<泛型参数>返回值类型 方法名(参数){}
泛型结构2
- 定义中含有泛型的接口:修饰符 interface 接口名<泛型参数>{}
泛型通配符
此处用到 [http://www.zuidaima.com/blog/3689434434948096.htm]:java 3y 的例子
此处用到 java 3y 的例子
此处用到 java 3y 的例子
现在有个需求:方法接收一个集合参数,遍历集合并把集合元素打印出来,怎么办?
按照我们没有学习泛型之前,我们可能会这样做:
public void test(List list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
上面的代码是正确的,只不过在编译的时候会出现警告,说没有确定集合元素的类型….这样是不优雅的…
那我们学习了泛型了,现在要怎么做呢??有的人可能会这样做:
public void test(List<Object> list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
这样做语法是没毛病的,但是这里十分值得注意的是:该test()方法只能遍历装载着Object的集合!!!
强调:泛型中的并不是像以前那样有继承关系的,也就是说List和List是毫无关系的!!!!
那现在咋办???我们是不清楚List集合装载的元素是什么类型的,List这样是行不通的………于是Java泛型提供了类型通配符 ?
所以代码应该改成这样:
public void test(List<?> list){
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
}
?号通配符表示可以匹配任意类型,任意的Java类都可以匹配……
现在非常值得注意的是,当我们使用?号通配符的时候:就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
记住,只能调用与对象无关的方法,不能调用对象与类型有关的方法。因为直到外界使用才知道具体的类型是什么。也就是说,在上面的List集合,我是不能使用add()方法的。因为add()方法是把对象丢进集合中,而现在我是不知道对象的类型是什么。
设置通配符限制
-
设置上限
格式: 类型名称 <? extends 类 > 对象名称
意义: 只能接收该类型及其子类 -
泛型的下限:
格式: 类型名称 <? super 类 > 对象名称
意义: 只能接收该类型及其父类型
泛型擦除机制
泛型是提供给编译器使用的,编译器可以确保你放置了一个该泛型参数类型的对象,但是生成的.class文件是不带有泛型信息的。
java泛型是使用擦除来实现的,这意味着当你在使用泛型的时,任何具体的 类型信息 都被擦除了,你唯一知道的就是你在使用一个对象。因此List和List在运行时 事实上是相同的类型的。这两种形式都被擦除成它们的"原生"的类型
- 擦除机制的作用
- 减少潜在的关于擦除的混乱,因为泛型并非是java语言设计之初就存在的,所以在引进的时候就只能折中的引进,即保证现在的代码是合法的,并继续保持之前的含义,使得旧的代码不会影响新的代码(允许泛型代码与非泛型代码互存)
- 擦除的核心动机可以用一句话概括就是非泛化的客户端可以用泛化的类库来使用,反之亦然,这也被称为:“迁移兼容性”
泛型的约束和局限性
- 不能使用基本类型实例化参数
- 运行时类型查询只适用于原始类型(即泛型擦除之前)
- 不能创建参数化的数组
- 不能实例化类型变量
- 泛型类的静态变量或静态方法不能引用泛型变量
- 不能抛出或捕捉泛型类的实例-catch子句不能使用类型参数
文章只是复习知识点时写下来的,其中有借鉴到一些大佬们的表述,因为只是作为知识点的复习,所以文章并没有用很多代码去做案例说明,如果是基础学习的小伙伴们可以移步哦!