一天一个java知识点----泛型

认识泛型

定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>)称为泛型类、泛型接口,泛型方法、它们统称为泛型。

泛型的本质:把具体的数据类型作为参数传给类型变量。

泛型的作用:统一数据类型。

Java
public static void main(String[] args) {
    // 目标:认识泛型,搞清楚使用泛型的好处。
    //        ArrayList<String> list = new ArrayList<String>();
    ArrayList<String> list = new ArrayList<>(); // jdk1.7后,泛型后面的类型变量可以省略不写。
    list.add("hello");
    // list.add(555);
    // list.add(555);
    // list.add(true);
    System.out.println(list); // [hello, 555, true]

    // 泛型的作用:统一数据类型。

    // 泛型可以约束集合中存储的数据类型! 固定了集合可以操作的数据类型
    ArrayList<Student> students = new ArrayList<>();
}
class Student{
}

泛型类

语法:

Java
修饰符 class 类名<类型变量,类型变量,…> {

}

Java
public class ArrayList<E>{
    . . .
}

注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V 等

由于原理过于复杂,这里我们暂时用装饰设计模式。

java
import java.util.ArrayList;

public class MyArrayList<E> {
    private ArrayList alist = new ArrayList();
    public void add(E e){
        alist.add(e);
    }

    public void remove(E e){
        alist.remove(e);
    }
}

javascript
// 需求:请您模拟ArrayList集合自定义一个集合MyArrayList.
MyArrayList<String> list = new MyArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.remove("bbb");
System.out.println(list);

泛型接口

问:什么是泛型接口?

答:泛型接口是指使用 “ 类型参数(如 <T>)” 定义的接口,使其能够适用于多种数据类型,提高代码的复用性和类型安全性。例如 List<T> 或 Comparator<T>,实现类可以指定具体类型(如 String)或保持泛型。这种方式避免了强制类型转换,并在编译时进行更严格的类型检查,适用于集合、数据处理等通用场景。

打个比方来讲:泛型接口就像一种“万能模板”,比如你设计一个盒子接口,盒子里能装任何东西(数字、文字、自定义对象等),但具体装什么类型不用提前写死。用的时候你告诉它“我要装苹果”或者“我要装书”,它就会自动适配成专门装苹果或装书的盒子。这样做的好处是既能重复使用同一套设计(比如装东西、取东西的方法),又能避免装错类型,编译器会提前帮你检查类型是否匹配。就像快递盒贴了类型标签,既灵活又安全。

例子:

我们现在有一个需求,需求:需要对学生 和 老师的数据都进行增删改查操作。

Java
//先定义两个实体类:
public class Student {
}
public class Teacher {
}

java
//定义一个对数据进行操作的泛型接口
public interface Data<T> {
    void add(T t);
    void update(T t);
    T getById(int id);
    void delete(int id);
}

typescript
//处理学生数据的实现类
public class StudentData implements Data<Student>{

    @Override
    public void add(Student student) {

    }

    @Override
    public void update(Student student) {

    }

    @Override
    public Student getById(int id) {
        return null;
    }

    @Override
    public void delete(int id) {

    }
}

//处理老师数据的实现类
public class TeacherData implements Data<Teacher>{
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public void update(Teacher teacher) {

    }

    @Override
    public Teacher getById(int id) {
        return null;
    }

    @Override
    public void delete(int id) {

    }
}

java
public class Test {
    public static void main(String[] args) {
        //目标:认识泛型接口。
        //需求:需要对学生 和 老师的数据都进行增删改查操作
        StudentData studentData = new StudentData();
        TeacherData teacherData = new TeacherData();
    }
}

泛型接口在这个示例中展现了三大核心优势:

  1. 一接口多用,代码精简

就像设计了一个万能模具(Data<T>),既能生产学生专用的"盒子"(StudentData),又能生产老师专用的"盒子"(TeacherData)。原本需要写两套接口,现在一套搞定,避免重复造轮子。

  1. 类型自动匹配,安全省心
  • 学生实现类里,所有方法自动识别Student类型(add(Student)/getById返回Student)
  • 老师实现类里,所有方法自动适配Teacher类型

编译器会严格检查,防止把老师数据误塞进学生系统,彻底告别ClassCastException异常。

  1. 扩展无忧,随加随用

未来如果要新增课程管理:

Java
public class CourseData implements Data<Course>{...}

现有代码零修改,新功能直接套用现有规范,系统扩展像搭积木一样简单。

这种设计既保持了严格的数据类型约束,又提供了灵活的架构扩展能力,是企业级开发中"高内聚低耦合"的典范实践。

总之,泛型接口的好处:使用泛型接口可以简化代码开发,不用开发多个处理类接口。

泛型方法、通配符、上下限

泛型方法:(T可以接一切类型

typescript
public class GenericityDemo {
    public static void main(String[] args) {
        //目标:认识泛型方法的作用
        //需求:接受任意类型的数组并进行操作
        Student[] students = new Student[10];
        printArray(students);

        Movie[] movies = new Movie[6];
        printArray(movies);

        String[] strings = new String[20];
        printArray(strings);
    }


    //T可以接一切类型
    //<T> 代表是泛型方法
    //(T[] arr) 这里的T代表传入的类型
    public static <T> void printArray(T[] arr){

    }
}
class Student{}

class Movie{}

通配符 ?

java
public class GenericityDemo2 {
    public static void main(String[] args) {
        //目标:认识通配符   ?
        //需求: 要求所有的汽车都可以一起参加比赛
        ArrayList<BWM> bmws = new ArrayList<>();
        bmws.add(new BWM());
        bmws.add(new BWM());
        bmws.add(new BWM());
        go(bmws);

        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        go(benzs);

        ArrayList<Dog> dog = new ArrayList<>();
        dog.add(new Dog());
        dog.add(new Dog());
        dog.add(new Dog());
        dog.add(new Dog());
        go(dog);//因为?代表一切类型,所以dog也可以进去。因此引入上下限概念
    }

    //虽然BWM和BENZ是Car的子类,但是ArrayList<BENZ>和ArrayList<BWM>与ArrayList<Car>没有任何关系
    // public static void go(ArrayList<Car> car){
    //
    // }
    //就是 “?” ,可以在“使用泛型”的时候代表一切类型;  E T K V 是在定义泛型的时候使用。
    public static void go(ArrayList<?> car){

    }
}

class Car{}

class BWM extends Car{}
class BENZ extends Car{}
class Audi extends Car{}

class Dog{}

上下限

java
public class GenericityDemo2 {
    public static void main(String[] args) {
        //目标:认识通配符   ?
        //需求: 要求所有的汽车都可以一起参加比赛
        ArrayList<BWM> bmws = new ArrayList<>();
        bmws.add(new BWM());
        bmws.add(new BWM());
        bmws.add(new BWM());
        go(bmws);

        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        go(benzs);

        ArrayList<Dog> dog = new ArrayList<>();
        dog.add(new Dog());
        dog.add(new Dog());
        dog.add(new Dog());
        dog.add(new Dog());
        //go(dog);//因为?代表一切类型,所以dog也可以进去。因此引入上下限概念
    }

    //虽然BWM和BENZ是Car的子类,但是ArrayList<BENZ>和ArrayList<BWM>与ArrayList<Car>没有任何关系
    // public static void go(ArrayList<Car> car){
    //
    // }
    //就是 “?” ,可以在“使用泛型”的时候代表一切类型;  E T K V 是在定义泛型的时候使用。
    //上下限: ?extends Car  :?必须是Car或者Car的子类。  上限!
    //        ?super Car  :  ?必须是Car或者Car的父类。  下限!
    public static void go(ArrayList<? extends Car> car){

    }
}

class Car{}

class BWM extends Car{}
class BENZ extends Car{}
class Audi extends Car{}

class Dog{}

泛型支持的类型

注意:泛型不支持基本数据类型,只能支持对象类型(引用数据类型)

typescript
public class GenericDemo6 {
    public static void main(String[] args) {
        //目标:搞清楚泛型不支持基本数据类型,只能支持对象类型(引用数据类型)
        ArrayList<int> list = new ArrayList<>();//报错,泛型和集合都不支持基本数据类型
    }
}

包装类

问:为什么要包装类?包装类有哪些?

答:为了万物皆对象,并且泛型和集合都不支持基本类型,支持包装类

8种,int -> Integer ,   char -> Character,其他的都是首字母大写

包装类就是把基本类型的数据包装成对象的类型

1.把基本数据类型变成包装类对象

java
int a = 10;
//Integer a1 = new Integer(10);//不推荐,jdk9以后就很少使用了
//System.out.println(a1);
Integer a2 = Integer.valueOf(a);//把基本数据类型变成包装类对象  -128 ~ 127之间的对象是同一个。

//不需要手动装箱成对象
//java支持自动装箱:基本类型的数据可以直接变成包装类对象。
Integer a3 = 10;
Integer a4 = 10;
System.out.println(a3 == a4); //true

Integer a5 = 222;
Integer a6 = 222;
System.out.println(a5 == a6); //false

这里有一道面试题:

对于-128~127之间整数,jdk会从缓存池获取,不会分配新的存储空间地址。

在引用数据类型中“==”比较的是内存地址。

java
Integer a3 = 10;
Integer a4 = 10;
System.out.println(a3 == a4); //true,10没有分配新的内存空间,直接从缓存池获取地址一样

Integer a5 = 222;
Integer a6 = 222;
System.out.println(a5 == a6); //false,false,200每次都分配新的内存空间地址,内存地址不一样

2.把包装对象变成基本数据类型

java
//java支持自动拆箱:包装对象可以直接变成基本数据类型
int a7 = a3;
System.out.println(a7);

3.集合和泛型都只能支持包装类

java
ArrayList<Integer> list = new ArrayList<>();
list.add(13);//自动装箱
list.add(14);//自动装箱
list.add(15);//自动装箱
list.add(16);//自动装箱

注意:以后推荐使用包装类型,因为包装类型可以接收值为null和有成员数据(成员变量和成员方法)

sql
int c = null; //报错,基本类型不可以赋值为null
Integer i9 = null; //包装类型可以赋值为null,非常符合前端传递数据给后端,可能没有传递导致后端接收为null

4.包装类新增的功能(重点)

java
// - 把基本数据类型变成字符串。
int age = 23;
String rs = Integer.toString(age);
System.out.println(rs + 1);//231

Integer age2 = 23;
String rs2 = age2.toString();
System.out.println(rs2 + 1);//231

int age3 = 23;
String rs3 = age + "";
System.out.println(rs3 + 1);//231


// - 把字符串的数值变成基本数据类型
String str = "123";
// int i1 = Integer.parseInt(str);
int i1 = Integer.valueOf(str);
System.out.println(i1 + 1);//124

String str2 = "23.5";
//double d1 = Double.parseDouble(str2);
double d1 = Double.valueOf(str2);
System.out.println(d1+1);//24.5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值