1. 泛型的定义
- 定义类、接口、方法时,同时声明了一个或者多个类型变量(如:)称为泛型、泛型接口、泛型方法,统称为泛型
public class ArrayList<E>{
. . .
}
- **作用:**泛型提供了在编译阶段约束所能操作的数据类型,并自动检查的能力。这样可以避免强制类型转换,及其肯呢个出现的异常
2. 泛型类
修饰符 class 类名<类型变量, 类型变量, ...>{
. . .
}
public class ArrayList<E>{
. . .
}
类型变量建议用大写的英文字母,常用的有:E、T、K、V等
示例
示例代码定义了一个泛型类 MyArrayList,该类封装了一个 ArrayList 对象,并提供了 add 和 remove 方法来添加和移除元素。此外,还重写了 toString 方法,以便返回内部 ArrayList 的字符串表示形式。
- add(E e): 将元素 e 添加到内部 ArrayList 中,并返回 true。
- remove(E e): 从内部ArrayList 中移除元素 e,并返回 true。
- toString(): 返回内部 ArrayList 的字符串表示形式
import java.util.ArrayList;
public class MyArrayList<E> {
private ArrayList list=new ArrayList();
public boolean add(E e){
list.add(e);
return true;
}
public boolean remove(E e){
list.remove(e);
return true;
}
@Override
public String toString() {
return list.toString();
}
}
测试代码
public class GenericityDemo2 {
public static void main(String[] args) {
MyArrayList<String> mlist=new MyArrayList<>();
mlist.add("hello");
mlist.add("world");
mlist.add("java");
System.out.println(mlist);
System.out.println(mlist.remove("hello"));
System.out.println(mlist);
}
}
测试结果
3. 泛型接口
修饰符 interface 接口名<类型变量, 类型变量, ...>{
. . .
}
通过一个场景来说明泛型接口:系统需要对学生数据/老师数据都要进行增删改查操作
在这种业务场景下,如果学生和老师都单独写接口就会编写重复的接口,就可以使用泛型接口通过定义一个泛型接口,可以创建适用于多种类型的实现类,避免为多种类型编写重复的接口。此外,泛型接口使得同一个接口可以处理不同类型的数据,增加了代码的灵活性和扩展性。
首先定义一个泛型接口
public interface Data<T> {
void add(T t);
void remove(T t);
void update(T t);
T query(int index);
}
学生类
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
学生实现类
public class StudentData implements Data<Student>{
private Student[] students = new Student[5];
private int index = 0;
private int size = 0;
private int maxSize = students.length;
@Override
public void add(Student student) {
if(index < maxSize)
{
students[index] = student;
index++;
size++;
}
else
{
System.out.println("数组已满,无法添加");
}
}
@Override
public void remove(Student student) {
for(int i = 0; i < size; i++)
{
if(students[i].equals(student))
{
students[i] = students[i+1];
size--;
}
}
}
@Override
public void update(Student student) {
for(int i = 0; i < size; i++)
{
if(students[i].equals(student))
{
students[i] = student;
}
}
}
@Override
public Student query(int index) {
if(index < size)
{
return students[index];
}
return null;
}
}
教师类
public class Teacher {
private String name;
private int age;
public Teacher(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
}
教师实现类
public class TeacherData implements Data<Teacher>{
private Teacher[] teachers=new Teacher[5];
private int index;
private int size;
private int maxSize = teachers.length;
@Override
public void add(Teacher teacher) {
if(index < maxSize)
{
teachers[index] = teacher;
index++;
size++;
}
else
{
System.out.println("数组已满,无法添加");
}
}
@Override
public void remove(Teacher teacher) {
for(int i = 0; i < size; i++)
{
if(teachers[i].equals(teacher))
{
teachers[i] = teachers[i+1];
size--;
}
}
}
@Override
public void update(Teacher teacher) {
for(int i = 0; i < size; i++)
{
if(teachers[i].equals(teacher))
{
teachers[i] = teacher;
}
}
}
@Override
public Teacher query(int index) {
if(index < size)
{
return teachers[index];
}
return null;
}
}
测试代码
public class GenericDemo3 {
public static void main(String[] args)
{
//测试学生接口
System.out.println("----------学生信息----------");
StudentData studentData=new StudentData();
studentData.add(new Student("张三",20));
studentData.add(new Student("李四",21));
studentData.add(new Student("王五",22));
studentData.remove(new Student("王五",22));
studentData.update(new Student("李四",32));
System.out.println(studentData.query(1));
System.out.println(studentData.query(2));
//测试老师接口
System.out.println("----------老师信息----------");
TeacherData teacherData=new TeacherData();
teacherData.add(new Teacher("张八",30));
teacherData.add(new Teacher("李九",31));
teacherData.add(new Teacher("王十",32));
teacherData.remove(new Teacher("王十",32));
teacherData.update(new Teacher("李九",22));
System.out.println(teacherData.query(1));
System.out.println(teacherData.query(2));
}
}
运行结果
4. 泛型方法
修饰符 <类型变量, 类型变量, ...> 返回值类型 方法名(x形参列表){
通过来两个泛型方法示例进行理解
```java
public static <T> void printArray(T[] names){
for (T name : names) {
System.out.println(name);
}
}
该printArray方法接收一个泛型数组 T[] names,其中 T 可以是任何对象类型。该方法可以接受任何类型的数组(如 String[]、Integer[]等)。
public static <T> T getMax(T[] names){
return null;
}
同样接收一个泛型数组 T[] names,返回值也是一个泛型。这样就可以接收任何类型的参数以及返回任何类型的结果
5. 通配符和泛型的上下限
通配符
就是“?”,可以在“使用泛型”的时候代表一切类型;
E、T、K、V是在定义泛型的时候使用
在一个场景下理解:如果多个品牌的车要进行比赛
首先定义了一个父类Car,三个子类车的品牌“BYD”、“XIAOMI”、“WL”,然后还要定义一个go方法是实际的比赛
import java.util.ArrayList;
public class GenericDemo5 {
public static void main(String[] args) {
ArrayList<XIAOMI> xiaomis= new ArrayList<>();
xiaomis.add(new XIAOMI());
xiaomis.add(new XIAOMI());
xiaomis.add(new XIAOMI());
xiaomis.add(new XIAOMI());
go(xiaomis);
}
public static void go(ArrayList<XIAOMI> cars){
}
}
如果只有XIAOMI进行比赛是没有问题的,但一旦其它车品牌要用到go方法就会报错
因此这里可以用到通配符,使得go方法可以复用
然而,这种方法就会导致对于传入的类型没有限制,如果传入一个动物猫也是可以的,如图:
因此就需要用到泛型的上下限
泛型的上下限
- 泛型的上限: ?extends Car: 表示?能接收的必须是Car或者其子类
- 泛型的下限: ?super Car: 表示?能接收的必须是Car或者其父类
在代码中加了上下限,由于Cat不是Car的子类,所以不能作为参数传入
6. 泛型支持的类型
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)
- 泛型擦除:泛型在编译的时候会被擦除,只保留类型,不保留泛型信息,最后都会变成一个Object
因此引出了包装类
7.包装类
就是把基本数据类型的数据包装成对象的类型
基本数据类型 | 对应的包装类(引用数据类型) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
7.1 手动包装
Integer i1 = Integer.valueOf(10);
Integer i2 = Integer.valueOf(20);
System.out.println(i1 ==i2);
7.2 自动装箱
基本数据类型自动转换为对象类型,不需要额外的包装
Integer i3 = 10;//相当于Integer i1 = Integer.valueOf(10);
Integer i4 = 10;
System.out.println(i3 == i4);
7.3 自动拆箱
对象类型转换为基本数据类型,不需要额外的拆箱
int i5 = i3;
System.out.println(i5);
7.4 包装类具备的其他功能
-
可以把基本类型的数据转换成字符串类型
-
可以把字符串类型的数值转换成数值本身对应的真实数据类型