泛型的学习

1.泛型的引入

java 复制代码
package com.hspedu.generic;

import java.util.ArrayList;

@SuppressWarnings({"all"})
public class Generic01 {
    public static void main(String[] args) {
        // 使用传统方法来解决
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog("旺财", 10));
        arrayList.add(new Dog("发财", 1));
        arrayList.add(new Dog("小黄", 5));

        // 假如不小心,添加了一只猫
        arrayList.add(new Cat("招财猫", 8));

        // 遍历
        for (Object o : arrayList) {
            // 向下转型 Object -> Dog
            Dog dog = (Dog) o;
            System.out.println(dog.getName() + "-" + dog.getAge());
        }
    }
}

class Dog {
    private String name;
    private int age;

    public Dog(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;
    }
}

class Cat { // Cat 类
    private String name;
    private int age;

    public Cat(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;
    }
}

2.泛型的入门

java 复制代码
package com.hspedu.generic.imporve;

import java.util.ArrayList;

//@SuppressWarnings({"all"})
public class Generic02 {
    public static void main(String[] args) {
        // 使用传统方法来解决 ===> 使用泛型
        //解读
        //1.当我们 ArrayList<Dog> 表示存放到 ArrayList 集合中的元素是 Dog 类型(细节后面说...)
        //2.如果编译器发现添加的类型,不满足要求,就会报错
        //3.在遍历的时候,可以直接取出 Dog 类型而不是 Object
        //4. public class ArrayList<E> {} E称为泛型,那么 Dog -> E
        ArrayList<Dog> arrayList = new ArrayList<Dog>();
        arrayList.add(new Dog("旺财", 10));
        arrayList.add(new Dog("发财", 1));
        arrayList.add(new Dog("小黄", 5));

        // 假如不小心,添加了一只猫
        //arrayList.add(new Cat("招财猫", 8));

        // 遍历
        for (Object o : arrayList) {
            // 向下转型 Object -> Dog
            Dog dog = (Dog) o;
            System.out.println(dog.getName() + "-" + dog.getAge());
        }
        System.out.println("===使用泛型后进行遍历===");
        // 遍历
        for (Dog dog : arrayList) {
            System.out.println(dog.getName() + "-" + dog.getAge());
        }
    }
}

/*
1.请编写程序,在 ArrayList 中,添加 3 个 Dog 对象
2.Dog 对象含有 name 和 age , 并输出 name 和 age (要求使用 getXXX())
3.使用泛型来完成代码
 */

/*
旺财-10
发财-1
小黄-5
===使用泛型后进行遍历===
旺财-10
发财-1
小黄-5
 */

class Dog {
    private String name;
    private int age;

    public Dog(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;
    }
}

class Cat { // Cat 类
    private String name;
    private int age;

    public Cat(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;
    }
}

3.泛型说明

对 4 的说明

java 复制代码
package com.hspedu.generic;

public class Generic03 {
    public static void main(String[] args) {
        //注意,特别强调: E 具体的数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
        Person<String> stringPerson = new Person<String>("我是地球的");
        stringPerson.show(); // class java.lang.String
        /*
        可以这样理解,上面的 Person 类
        class Person {
            String s; // E 表示 s 的数据类型,该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型

            public Person(String s) { // E 也可以是在参数类型
                this.s = s;
            }

            public String f() { // 返回类型使用 E
                return s;
            }
        }
         */


        Person<Integer> person2 = new Person<Integer>(100);
        person2.show(); // class java.lang.Integer
        /*
                class Person {
                    Integer s; // E 表示 s 的数据类型,该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型

                    public Person(Integer s) { // E 也可以是在参数类型
                        this.s = s;
                    }

                    public Integer f() { // 返回类型使用 E
                        return s;
                    }
                }
         */
    }
}

class Person<E> {
    E s; // E 表示 s 的数据类型,该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型

    public Person(E s) { // E 也可以是在参数类型
        this.s = s;
    }

    public E f() { // 返回类型使用 E
        return s;
    }

    public void show() {
        System.out.println(s.getClass()); // 显示 s 的运行类型
    }
}

4.泛型应用实例

java 复制代码
package com.hspedu.generic;

import java.util.*;

@SuppressWarnings({"all"})
public class GenericExercise {
    public static void main(String[] args) {
        // 使用泛型方式给 HashSet 放入 3 个学生对象
        HashSet<Student> students = new HashSet<Student>();

        students.add(new Student("jack", 18));
        students.add(new Student("tom", 28));
        students.add(new Student("mary", 19));

        // 遍历
        for (Student student : students) {
            System.out.println(student);
        }

        // 使用泛型给 HashMap 放入 3 个学生对象
        // k -> String     v -> Student
        HashMap<String, Student> hm = new HashMap<String, Student>();
        /*
            public class HashMap<K,V> {}
         */
        hm.put("milan", new Student("milan", 38));
        hm.put("smith", new Student("smith", 48));
        hm.put("swk", new Student("swk", 10000));
        System.out.println("======");
        //迭代器 EntrySet
        /*
        public Set<Map.Entry<K,V>> entrySet() {
            Set<Map.Entry<K,V>> es;
            return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
        }
         */
        Set<Map.Entry<String, Student>> entries = hm.entrySet();
        /*
                public final Iterator<Map.Entry<K,V>> iterator() {
                    return new EntryIterator();
                }
         */
        Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Student> next =  iterator.next();
            System.out.println(next.getKey() + next.getValue());

        }
    }
}

/*
Student{name='tom', age=28}
Student{name='jack', age=18}
Student{name='mary', age=19}
======
smithStudent{name='smith', age=48}
swkStudent{name='swk', age=10000}
milanStudent{name='milan', age=38}
 */

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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

5.泛型使用细节1

java 复制代码
package com.hspedu.generic;

import java.util.List;
import java.util.ArrayList;

public class GenericDetail {
    public static void main(String[] args) {
        //1.给泛型指定数据类型时,要求是引用类型,不能是基本数据类型
        List<Integer> list = new ArrayList<Integer>(); // ok
//        List<int> list2 = new ArrayList<int> (); // 错误

        //2.说明
        // 因为 E 指定了 A 类型,构造器传入了 new A()
        // 在给泛型指定具体类型后,可以传入该类型或者其子类型
        Pig<A> aPig = new Pig<A>(new A());
        aPig.f(); // class com.hspedu.generic.A
        Pig<A> aPig2 = new Pig<A>(new B());
        aPig2.f(); // class com.hspedu.generic.B

        //3.泛型的使用形式
        ArrayList<Integer> list1 = new ArrayList<Integer>();
        List<Integer> list2 = new ArrayList<Integer>();
        //在实际开发中,往往简写
        //编译器会进行类型推断,推荐使用下面写法
        ArrayList<Integer> list3 = new ArrayList<>();
        List<Integer> list4 = new ArrayList<>();
        ArrayList<Pig> pigs = new ArrayList<>();

    }
}

class A {}
class B extends A{}

class Pig<E> {
    E e;

    public Pig(E e) {
        this.e = e;
    }

    public void f() {
        System.out.println(e.getClass());
    }
}

6.泛型使用细节2

java 复制代码
package com.hspedu.generic;

import java.util.List;
import java.util.ArrayList;

@SuppressWarnings({"all"})
public class GenericDetail {
    public static void main(String[] args) {
        //1.给泛型指定数据类型时,要求是引用类型,不能是基本数据类型
        List<Integer> list = new ArrayList<Integer>(); // ok
//        List<int> list2 = new ArrayList<int> (); // 错误

        //2.说明
        // 因为 E 指定了 A 类型,构造器传入了 new A()
        // 在给泛型指定具体类型后,可以传入该类型或者其子类型
        Pig<A> aPig = new Pig<A>(new A());
        aPig.f(); // class com.hspedu.generic.A
        Pig<A> aPig2 = new Pig<A>(new B());
        aPig2.f(); // class com.hspedu.generic.B

        //3.泛型的使用形式
        ArrayList<Integer> list1 = new ArrayList<Integer>();
        List<Integer> list2 = new ArrayList<Integer>();
        //在实际开发中,往往简写
        //编译器会进行类型推断,推荐使用下面写法
        ArrayList<Integer> list3 = new ArrayList<>();
        List<Integer> list4 = new ArrayList<>();
        ArrayList<Pig> pigs = new ArrayList<>();

        //4.如果是这样写 泛型默认是 Object
        ArrayList arrayList = new ArrayList(); // 等价 ArrayList<Object> arrayList = new ArrayList();
        arrayList.add("xx");
        /*
           public boolean add(Object e) {
                modCount++;
                add(e, elementData, size);
                return true;
            }
         */

        Tiger tiger = new Tiger();
        /*
        class Tiger { // 类
            Object e;

            public Tiger() {}
            public Tiger(Object e) {
                this.e = e;
            }
        }
         */
    }
}

class Tiger<E> { // 类
    E e;

    public Tiger() {}
    public Tiger(E e) {
        this.e = e;
    }
}

class A {}
class B extends A{}

class Pig<E> {
    E e;

    public Pig(E e) {
        this.e = e;
    }

    public void f() {
        System.out.println(e.getClass());
    }
}

7.泛型课堂练习

java 复制代码
package com.hspedu.generic;


import java.util.ArrayList;
import java.util.Comparator;
@SuppressWarnings({"all"})
public class GenericExercise02 {
    public static void main(String[] args) {
        Employee employee1 = new Employee("tom", 500, new MyDate(1999, 1, 1));
        Employee employee = new Employee("jack", 1000, new MyDate(2000, 1, 1));
        Employee employee2 = new Employee("tom", 2000, new MyDate(1000, 2, 2));

        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(employee);
        employees.add(employee1);
        employees.add(employee2);

        for (Employee employee_ : employees) {
            System.out.println(employee_);
        }

        System.out.println("===对雇员进行排序===");
        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee emp1, Employee emp2) {
                // 先对传入的参数进行验证
                if (!(emp1 instanceof Employee && emp2 instanceof Employee)) {
                    System.out.println("类型不正确..");
                    return 0;
                }
                //比较 name
                int i = emp1.getName().compareTo(emp2.getName());
                if (i != 0) {
                    return i;
                }
                //下面对 birthday 的比较,因此,我们最好把这个比较,放在 MyDate 类完成
                //封装后,将来可维护性和复用性,就大大增强
                return emp1.getBirthday().compareTo(emp2.getBirthday());
            }
        });

        System.out.println("===排序后的结果===");
        for (Employee employee_ : employees) {
            System.out.println(employee_);
        }
    }
}

/*
Employee{name='jack', sal=1000.0, birthday=MyDate{month=1, day=1, year=2000}}
Employee{name='tom', sal=500.0, birthday=MyDate{month=1, day=1, year=1999}}
Employee{name='tom', sal=2000.0, birthday=MyDate{month=2, day=2, year=1000}}
===对雇员进行排序===
===排序后的结果===
Employee{name='jack', sal=1000.0, birthday=MyDate{month=1, day=1, year=2000}}
Employee{name='tom', sal=2000.0, birthday=MyDate{month=2, day=2, year=1000}}
Employee{name='tom', sal=500.0, birthday=MyDate{month=1, day=1, year=1999}}

 */

class Employee {
    private String name;
    private double sal;
    private MyDate birthday;

    public Employee(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }
}

class MyDate implements Comparable<MyDate>{
    private int month;
    private int day;
    private int year;

    public MyDate(int year, int month, int day) {
        this.month = month;
        this.day = day;
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    @Override
    public String toString() {
        return "MyDate{" +
                "month=" + month +
                ", day=" + day +
                ", year=" + year +
                '}';
    }

    @Override
    public int compareTo(MyDate o) { // 把对 year - month - day 比较放在这里
        int yearMinus = year - o.getYear();
        if (yearMinus != 0) {
            return yearMinus;
        }
        //如果 year 相同 就比较 month
        int monthMinus = month - o.getMonth();
        if (monthMinus != 0) {
            return monthMinus;
        }
        //如果 year 和 month 相同
        return day - o.getDay();
    }
}

8.自定义泛型类

java 复制代码
package com.hspedu.customgeneric;

public class CustomGeneric_ {
    public static void main(String[] args) {

    }
}

//解读
//1.Tiger 后面泛型,所以我们把 Tiger 就称为自定义泛型
//2.T R M 泛型的标识符,一般是单个大写字母
//3.泛型标识符可以有多个
//4.普通成员可以使用泛型(属性、方法)
//5.使用泛型数组不能初始化
//6.静态方法中不能使用类的泛型
class Tiger<T, R, M> {
    String name;
    R r; // 属性使用到泛型
    M m;
    T t;
    // 因为数组在 new 不能确定 T 的类型,就无法在内存开空间
    T arr[];

    public Tiger(String name, R r, M m, T t) { // 构造器使用泛型
        this.name = name;
        this.r = r;
        this.m = m;
        this.t = t;
    }

    // 因为静态是和类相关的,在类加载时,对象还没有创建
    // 所以,如果静态方法和静态属性使用了泛型, JVM 就无法完成初始化
//    static R r2;
//    public static void m1(M m) {
//
//    }
    
    // 方法使用泛型

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public R getR() { // 返回类型使用到泛型
        return r;
    }

    public void setR(R r) {  // 方法使用到泛型
        this.r = r;
    }

    public M getM() {
        return m;
    }

    public void setM(M m) {
        this.m = m;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}
java 复制代码
package com.hspedu.customgeneric;

@SuppressWarnings({"all"})
public class CustomGeneric_ {
    public static void main(String[] args) {
        //T = Double R = String M = Integer
        Tiger<Double, String, Integer> g = new Tiger<>("john");
        g.setT(10.9); // OK
//        g.setT("yy");// 错误,类型不对
        System.out.println(g);

        Tiger g2 = new Tiger("john~~"); // OK T = Object R = Object M = Object
        g2.setT("yy"); // OK 因为 T = Object "yy" 是 String 是 Object 的子类
        System.out.println("g2 = " + g2);
    }
}

//解读
//1.Tiger 后面泛型,所以我们把 Tiger 就称为自定义泛型
//2.T R M 泛型的标识符,一般是单个大写字母
//3.泛型标识符可以有多个
//4.普通成员可以使用泛型(属性、方法)
//5.使用泛型数组不能初始化
//6.静态方法中不能使用类的泛型
class Tiger<T, R, M> {
    String name;
    R r; // 属性使用到泛型
    M m;
    T t;
    // 因为数组在 new 不能确定 T 的类型,就无法在内存开空间
    T arr[];

    public Tiger(String name) {
        this.name = name;
    }

    public Tiger(R r, M m, T t) { // 构造器使用泛型
        this.r = r;
        this.m = m;
        this.t = t;
    }

    // 因为静态是和类相关的,在类加载时,对象还没有创建
    // 所以,如果静态方法和静态属性使用了泛型, JVM 就无法完成初始化
//    static R r2;
//    public static void m1(M m) {
//
//    }

    // 方法使用泛型

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public R getR() { // 返回类型使用到泛型
        return r;
    }

    public void setR(R r) {  // 方法使用到泛型
        this.r = r;
    }

    public M getM() {
        return m;
    }

    public void setM(M m) {
        this.m = m;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

9.自定义泛型接口

java 复制代码
package com.hspedu.customgeneric;

public class CustomInterfaceGeneric {
    public static void main(String[] args) {

    }
}

/*
泛型接口使用说明
1.接口中,静态成员也不能使用泛型
2.泛型接口的类型,在继承接口或者实现接口时确定
 */

//在继承接口 指定泛型接口的类型
interface IA extends IUsb<String, Double> {

}
//当我们去实现 IA 接口时,因为 IA 在继承 IUsb 接口时,指定了 U 为 String R 为 Double
//在实现 IUsb 接口的方法时,使用 String 替换 U, 使用 Double 替换 R
class AA implements IA {

    @Override
    public Double get(String s) {
        return null;
    }

    @Override
    public void hi(Double aDouble) {

    }

    @Override
    public void run(Double r1, Double r2, String u1, String u2) {

    }
}

//实现接口时,直接指定泛型接口的类型
//给 U 指定 Integer 给 R 指定了 Float
//所以当实现 IUsb 方法时,会使用 Integer 替换 U , 使用 Float 替换 R
class BB implements IUsb<Integer, Float> {
    @Override
    public Float get(Integer integer) {
        return null;
    }

    @Override
    public void hi(Float aFloat) {

    }

    @Override
    public void run(Float r1, Float r2, Integer u1, Integer u2) {

    }
}
//没有指定类型,默认为 Object
//建议直接写成 IUsb<Object, Object>
class CC implements IUsb { // 等价于 class CC implements IUsb<Object, Object> {}

    @Override
    public Object get(Object o) {
        return null;
    }

    @Override
    public void hi(Object o) {

    }

    @Override
    public void run(Object r1, Object r2, Object u1, Object u2) {

    }
}

interface IUsb<U, R> {
    int n = 10;
//    U name; 不能这样使用

    // 普通方法中,可以使用接口泛型
    R get(U u);

    void hi(R r);

    void run(R r1, R r2, U u1, U u2);

    // 在 jdk8 中, 可以在接口中,使用默认方法,也是可以使用泛型
    default R method(U u) {
        return null;
    }
}
相关推荐
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 天前
2026.2.25监控学习
学习
im_AMBER3 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J3 天前
从“Hello World“ 开始 C++
c语言·c++·学习