6.泛型
1. 泛型的引入
- 什么是泛型(Generic)
我的理解:泛型就相当于标签或者一个过滤器
形式:<>
集合容器类在设计阶段/声明阶段不能确定这个容器到底是存储的是什么类型的对象(因为集合能存很多种类型的数据),所以jdk1.5之前只能把元素类型设计为Object,1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数就叫做泛型。
Collection,List这个就是类型参数,即泛型
- 集合中使用泛型:
@Test
public void genericsTest() {
//不使用泛型
ArrayList arrayList = new ArrayList();
arrayList.add(12);
arrayList.add(33);
arrayList.add(55);
arrayList.add("xxj");
arrayList.add(5.6);
for(Object o : arrayList) {
System.out.println(o);
}
//使用泛型后
ArrayList<Integer> list = new ArrayList<>();
list.add(12);
list.add(33);
list.add(55);
/*list.add("xxj");
list.add(5.6);*/
for(Integer i : list) {
System.out.println(i);
}
}
2. 自定义泛型结构
1. 泛型类,泛型接口
- 泛型类的定义和实例化
class GenericTest01<E> {
int age;
String name;
E sex;
public void a(E n) {
}
public void b(E[] x) {
}
}
@Test
public void genericTest01() {
//GenericTest01进行实例化:
//(1)实例化的时候不指定泛型:如果实例化的时候不明确指定类的泛型,那么认为此泛型为Object类型
GenericTest01 gt1 = new GenericTest01();
gt1.a(23);
gt1.a("xxj");
gt1.b(new String[]{"a","b","c"});
//(2)实例化的时候指定泛型 -》推荐方式
GenericTest01<String> sgt1 = new GenericTest01<>();
sgt1.sex = "男";
sgt1.a("xxj");
// sgt1.a(33);
sgt1.b(new String[]{"a","b","c"});
}
- 继承情况
- 父类指定泛型
//父类指定泛型 class SubGenericTest01 extends GenericTest01<Integer>{ } @Test public void subGenericTest01() { SubGenericTest01 subGenericTest01 = new SubGenericTest01(); subGenericTest01.sex = 1; subGenericTest01.a(11); }
- 父类不指定泛型
- 父类指定泛型
//如果父类不指定泛型,那么子类也会变成一个泛型类,那个这个E类型可以在创建子类对象的时候确定:
class SubGenericTest02<E> extends GenericTest01<E>{
}
@Test
public void subGenericTest02() {
SubGenericTest02<String> stringSubGenericTest02 = new SubGenericTest02<>();
stringSubGenericTest02.sex = "女";
}
- 细节
- 泛型类可以定义多个参数类型
- 泛型类的构造器不能加泛型
- 不同泛型的引用类型不可以相互赋值
- 泛型如果不指定,那么就会被擦除,反应对应的类型为Object类型
2. 泛型方法
- 什么是泛型方法
不是带有泛型的方法就是泛型方法
泛型方法有要求:这个方法的泛型的参数类型要和当前类的泛型无关
换个角度:泛型方法对应的那个泛型参数类型 和 当前所在的这个类 是否是泛型类,泛型是什么 都没有关系
- 泛型方法定义的时候,前面要加上
原因:如果不加的话,会把T当作一种数据类型,然而代码中没有T类型那么就会报错
- T的类型是在调用方法的时候确定的
- 泛型方法可以是静态方法
public class GenericsTest02<E> {
//不是泛型方法
public void a(E e) {
}
//是泛型方法
public <T> void b(T t) {
}
//泛型方法可以作为静态方法
public static <F> void c(C c) {
}
@Test
public void GenericsTest() {
GenericsTest02<String> stringGenericsTest02 = new GenericsTest02<>();
stringGenericsTest02.a("xxj");
stringGenericsTest02.b("fff");
stringGenericsTest02.b(22);
}
}
3. 泛型参数存在继承关系的情况
public class GenericsTest03 {
public static void main(String[] args) {
Object obj = new Object();
String str = new String();
obj = str;//多态的一种表现形式
Object[] objects = new Object[10];
String[] strings = new String[10];
objects = strings;//多态的一种形式
/*List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1 = list2;//总结:A和B是父子关系,但是G<A> G<B>不存在继承关系的 是并列关系。*/
}
}
4. 通配符
- 在没有通配符的时候,下面的a方法想的于重复定义
class TongPeiFu { public void a(List<Object> list) { } public void a(List<String> list) { } public void a(List<Integer> list) { } }
- 引用通配符
发现:A和B是父子关系,但是G<A>G<B>不存在继承关系而是并列关系,加入通配符?后,G<?>就变成了G<A>和G<B>的父类
@Test
public void test () {
ArrayList<Object> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Integer> list3 = new ArrayList<>();
List<?> list = null;
list = list1;
list = list2;
list = list3;
}
- 应用
public void a(List<?> list) {
//1. 遍历
for (Object o : list){
System.out.println(o);
}
//2. 数据的写入操作
//list.add("abc")--->出错,不能添加数据,只能读
//3.数据的读取
list.get(0);
}
5. 泛型受限
泛型可以设置上限和下限
public class Person extends Object{
}
public class Student extends Person{
}
public class Test {
public static void main(String[] args) {
ArrayList<Object> a = new ArrayList<>();
ArrayList<Person> b = new ArrayList<>();
ArrayList<Student> c = new ArrayList<>();
//泛型上限,最高只能到Person(Person及其子类)
List<? extends Person> list1 = null;
//list1 = a;
list1 = b;
list1 = c;
//泛型的下限,最低为Person(Person及其父类)
List<? super Person> list2 = null;
list2 = a;
list2 = b;
//list2 = c;
}
}