1.为什么要有泛型
1.1什么是泛型
- 泛型:标签
举例:中药店,每一个盒子(抽屉)都有一个标签写着中药名,盒子(抽屉)就相当于一个容器,就像java中的集合一样 - 泛型的设计背景
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存储的时什么类型的对象,所以jdk1.5之前只能把元素类型设计为Object,jdk1.5之后是使用泛型来解决,因为这个时候除了元素的类型不确定,其他部分都是确定的,例如关于这个元素如何保存,如何管理是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型,Collection<E>,List<E>这个<E>就是类型参数,即泛型
1.2不加泛型会存在哪些问题
- 类型不安全
- 出现ClassCastException
package com.ruoyi.web.message.test;
import java.util.ArrayList;
/**
* @author chenxiaogao
* @className GenericDemo
* @description 不使用泛型产生的问题
* @date 2020/11/15
**/
public class GenericDemo {
public static void main(String[] args) {
//需求:存放学生成绩
ArrayList scoreList = new ArrayList();
scoreList.add(55);
scoreList.add(66);
scoreList.add(88);
//问题1:类型不安全
scoreList.add("tom");
for (Object score : scoreList) {
//问题2:出现ClassCastException
//ClassCastException
int stuScore = (int)score;
System.out.println("stuScore = " + stuScore);
}
}
}
1.3使用泛型
//2.使用泛型
ArrayList<Integer> scoreList1 = new ArrayList<>();
scoreList1.add(66);
scoreList1.add(67);
scoreList1.add(68);
//编译报错,避免了类型错误
scoreList1.add("jd");
//避免了类型转换,不会发生类型转换异常
for (Integer integer : scoreList1) {
System.out.println("integer = " + integer);
}
1.4总结
- 集合接口或结合类在jdk5.0时都修改为带泛型的结构。
- 在实例化集合类时,可以指明具体的泛型类型
- 指明完以后,在集合类或接口中凡是定义接口或类时,内部结构(方法,构造,属性等)使用到类的泛型的位置,都指定为实例化的泛型类型;例如:add(E e) 实例化后 add(Integer e)
- 泛型的类型必须是一个类,基本数据类型用包装类
+如未指定泛型,则默认为Object
2.自定义泛型结构(泛型类,泛型接口,泛型方法)
- 自定义泛型类
package com.ruoyi.web.message.test;
/**
* @author chenxiaogao
* @className Order
* @description 自定义泛型类
* @date 2020/11/15
**/
public class Order<T> {
String orderName;
T orderT;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
}
- 在实例化Order时就可以动态指定orderT的类型
public class GenericDemo {
public static void main(String[] args) {
Order<String> strOrder = new Order<>();
strOrder.setOrderT("hello");
String orderT = strOrder.getOrderT();
System.out.println("orderT = " + orderT);
Order<Integer> intOrder = new Order<>();
intOrder.setOrderT(1);
Integer orderT1 = intOrder.getOrderT();
System.out.println("orderT1 = " + orderT1);
}
}
- 子类在继承带泛型的父类时,若父类指明了类型,则子类不需要再指定
package com.ruoyi.web.message.test;
/**
* @author chenxiaogao
* @className SubOrder1
* @description TODO
* @date 2020/11/15
**/
public class SubOrder1 extends Order<Integer> {
}
- 子类在继承带泛型的父类时,若父类使用泛型,则子类也需要为泛型
package com.ruoyi.web.message.test;
/**
* @author chenxiaogao
* @className SubOrder
* @description TODO
* @date 2020/11/15
**/
public class SubOrder<T> extends Order<T> {
}
- 泛型类可能有多个参数,此时应将多个参数一起放到<>中
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {}
- 2.泛型类的构造如下
public Order() {
}
而不是
public Order<>() {
}
- 3.实例化后,操作原来泛型位置的结构(方法,构造,属性)必须与指定的类型一致;
- 4.泛型不同的引用不能相互赋值
public static void main(String[] args) {
//这样是不行的
ArrayList<Integer> integers = null;
ArrayList<String> strings = null;
integers = strings;
//这样可以
ArrayList<String> str1 = null;
ArrayList<String> str2 = null;
str1 = str2;
}
- 5.泛型如果不指定,将被擦除,泛型对应的类型均按照Object处理,但不等价与Object
- 6.jdk1.7,泛型简化 ArrayList<String> list = new ArrayList<>();
- 7.泛型的指定不能使用基本数据类型,可以使用包装类型替代
- 8.在类/接口上声明的泛型,不能在静态方法中使用,因为使用泛型是在类的实例化时确定的,而静态方法不需要实例化该类便可调用;
- 9.异常类不能时泛型的
+10.不能使用new E[];
3.自定义泛型方法
- 在方法中出现泛型结构,泛型参数与类的泛型参数没有任何关系,即泛型方法可以存在于泛型类中,也可以存在于非泛型类中
public <E> List<E> copyArrayToList(E[] array) {
List<E> list = new ArrayList<>();
for (E e : array) {
list.add(e);
}
return list;
}
使用
public class GenericDemo {
public static void main(String[] args) {
Order<String> strOrder = new Order<>();
Integer[] array = {1, 2, 3};
List<Integer> list = strOrder.copyArrayToList(array);
String s = list.toString();
System.out.println("s = " + s);
}
}
- 泛型方法可以为静态方法,因为方法的泛型为调用该方法时确定的,并非在实例化时确定的
public static <E> List<E> copyArrayToList(E[] array) {
List<E> list = new ArrayList<>();
for (E e : array) {
list.add(e);
}
return list;
}
4.通配符的使用
package com.ruoyi.web.message.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
/**
* @author chenxiaogao
* @className GenericDemo
* @description 通配符的使用
* @date 2020/11/15
**/
public class GenericDemo {
public static void main(String[] args) {
List<Object> list1= null;
List<String> list2 =null;
List<?> list = null;
list = list1;
list = list2;
}
public static void print(List<?> list) {
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
}
}
- 有限制条件的通配符
public class GenericDemo {
public static void main(String[] args) {
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Person> list3 = null;
List<Student> list4 = null;
List<Object> list5 = null;
list1 = list3;
list1 = list4;
//list5无法赋值给list1
list1 = list5;//报错
list2 = list3;
list2 = list4;//报错
list2 = list5;
}
}
网友评论