泛型

泛型

泛型概述

泛型是JDK5引入的特性,可以在编译节点约束操作的数据类型,并进行检查

格式:<数据类型>

注意:泛型只能支持引用数据类型

如果没有给泛型定义数据类型,默认的是Object类型,此时可以添加任意类型的数据,在获取出来的时候,是不能使用子类的特有行为的(多态的弊端是不能访问子类的特有功能),如果进行强转,不知道强转成什么类型

泛型的好处

  • 统一数据类型
  • 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。

泛型的细节

  • 泛型中不能写基本数据类型(因为基本数据类型不能转换成Object)
  • 指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
  • 如果不写泛型,类型默认是Object
  • 泛型只是在添加的时候加入了数据类型的校验,其实底层还是会变成Object去存储,在获取的时候在通过Object转成对应的类型。(可以去看编译后的class文件,里面的泛型都是转成了Object类型)

泛型类

​ 使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类,创建该类对象的时候,确定泛型

格式

修饰符 class 类名<类型>{}

1
2
3
4
//创建该类对象时,E就确定类型
public class ArrayList<E>{

}

此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T、E、K、V等

泛型方法

方法中形参类型不确定时,

  1. 可以使用类名后面定义的泛型(类中所有方法都能用)
  2. 在方法申明上定义自己的泛型(只有本方法能用)
1
2
3
4
5
6
7
public class MyArrayList<E>{
public boolean add(E e){
obj[size] =e;
size++;
return true;
}
}

格式

在修饰符后面定义方法,调用该方法的时候确定类型

修饰符<类型> 返回值类型 方法名(类型 变量名){}

1
public <T> void show(T t){}

此处T可以理解为变量,但是不是用来记录数据的,而是记录数据的类型,可以写成:T、E、K、V等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
类中定义一个静态方法addAll,用来添加多个集合的元素
*/
//参数1:集合 参数2:最后要添加的元素
public class ListUtil{
private ListUtil(){}
public static<E> void addAll(ArrayList<E> list,E e1,E e2){
list.add(e1);
list.add(e2);
}
//添加个数不确定
public static<E> void addAll(ArrayList<E> list,E...e){
for(E e1:e){
list.add(e1);
}
}
}

public class Demo{
public static void main(String[] args){
ArrayList<String> list1 = new ArrayList<>();
ListUtil.addAll(list1,"aaa","bbb");
}
}

泛型接口

  • 实现类给出具体类型
  • 实现类延续泛型,创建对象时再确定

格式

在接口名后面定义泛型,实现类确定类型,实现类延续泛型

修饰符 interface 接口名<类型>{}

1
public interface List<E>{}
1
2
3
4
5
6
//实现类给出具体类型
public class MyArrayList implement List<String>{}
MyArrayList list = new MyArrayList();
//实现类延续泛型,创建对象时再确定
public class MyArrayList2<E> implement List<E>{}
MyArrayList2<String> list2 = new MyArrayList2<>();

泛型的继承和通配符

  • 泛型不具备继承性,但是数据具备继承性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.zhuixun.demo;

import java.util.ArrayList;

/**
* @Author: zhuixun
* @Date: 2023/1/12 20:27
* @Version 1.0
*/
public class fxDemo {
public static void main(String[] args) {
/**
* 泛型不具备继承性,但是数据具备继承性
*/
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();

//调用method方法
method(list1);
//method(list2);//报错
//method(list3);//报错

}

/**
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
* @param list
*/
public static void method(ArrayList<Ye> list){

}

//如果改为这样则不会报错
public static <E> void method(ArrayList<E> list){
}
}


class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}


泛型的通配符

关键点:可以限定类型的范围

  • ?: 也可以表示不确定的类型,它可以进行类型的限定
  • ? extends E: 表示可以传递E或者E所有的子类类型
  • ? super E: 表示可以传递E或者E所有的父类类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.zhuixun.demo;

import java.util.ArrayList;

/**
* @Author: zhuixun
* @Date: 2023/1/12 20:33
* @Version 1.0
*/
public class GenericsDemo {
/**
* 需求:
* 定义一个方法,形参是一个集合,但是集合中的数据类型不确定
*
*/
public static void main(String[] args) {
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();

//调用method方法
method(list1);
method(list2);
method(list3);
}

/**
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
* 弊端:
* 利用泛型方法有一个小弊端,此时他何以接收任意的数据类型
* 希望:本方法虽然不确定类型,但是以后我希望只能传递Ye Fu Zi
* 此时我们可以使用泛型的通配符:
* ?:也可以表示不确定的类型
* 它可以进行类型的限定
* ? extends E:表示可以传递E或者E所有的子类类型
* ? super E:表示可以传递E或者E所有的父类类型
* @param list
*
*/
public static void method(ArrayList<? extends Ye> list){}
}

应用场景

  1. 如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口
  2. 如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用我们泛型的通配符

泛型
http://example.com/2023/01/29/Java基础/泛型/generic-paradigm/
作者
zhuixun
发布于
2023年1月29日
许可协议