Java笔记之泛型(二十二)

一、泛型

1.案例引入

要求:
请编写程序,在 ArrayList 中,添加 3 个 Dog 对象 Dog 对象含有 name 和 age, 并输出 name 和 age (要求使用 getXxx())

import java.util.ArrayList;

class test1{
    @SuppressWarnings({"all"})
    public static void main(String[] args){
        ArrayList list = new ArrayList();
        list.add(new Dog("小黄",2));
        list.add(new Dog("小白",1));
        list.add(new Dog("小黑",5));

        //假如不小心,添加了一直猫
        list.add(new Cat("小花",2));

        //遍历
        for (Object o: list) {
            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{
    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;
    }
}

以上代码就会出现ClassCastException: com.test.Cat cannot be cast to com.test.Dog
在这里插入图片描述
使用传统方法缺点

  1. 不能对加入到集合ArrayList中的数据类型进行约束(不安全)
  2. 遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响

2.泛型引入

使用泛型解决上面的问题

import java.util.ArrayList;

class test1{
    @SuppressWarnings({"all"})
    public static void main(String[] args){
        ArrayList<Dog> list = new ArrayList<Dog>();
        list.add(new Dog("小黄",2));
        list.add(new Dog("小白",1));
        list.add(new Dog("小黑",5));

        //假如不小心,添加了一直猫,代码会提示Required type 必须是Dog类型的数据,但是你给它一个Cat数据类型
//        list.add(new Cat("小花",2));

        //遍历
        for (Object o: list) {
            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{
    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;
    }
}

泛型的好处

  1. 编译时,检查添加元素的类型,提高了安全性
  2. 减少了类型转换的次数,提高效率

不适用泛型:Dog放入到ArrayList会先转成Object,在取出时,还需要转换成Dog
使用泛型:Dog放入ArrayList时和取出时,不需要类型转换,提高效率

二、泛型介绍

1.基本介绍

泛型其实就是一种表示数据类型的数据类型

  1. 泛型又称参数化类型,是jdk5出现的新特性,解决了数据类型的安全性问题
  2. 在类声明或实例化时,只要指定好需要的具体类型即可
  3. java泛型可以保证如果程序在编译时没有发出警告,进行时就不会产生异常。同时代码更加简洁、健壮
  4. 泛型的作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型

加深泛型的理解

class test1{
    @SuppressWarnings({"all"})
    public static void main(String[] args){
        //E 具体的数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
        test<String> stringtest = new test<String>("String类型");
        System.out.println(stringtest.demo());
        stringtest.getClass1();

        test<Integer> integertest = new test<Integer>(1000);
        System.out.println(integertest.demo());
        integertest.getClass1();
    }
}
/*
泛型的作用:
可以在类声明时通过一个标识表示类中某个属性的类型,
或者是某个方法的返回值的类型,或者是参数类型。
 */
//泛型类
class test<E>{
    E unknown;  //不确定是什么类型

    //E可以是方法参数类型
    public test(E unknown) {
        this.unknown = unknown;
    }

    //E可以是方法返回类型
    public E demo(){
        return unknown;
    }

    //获取它的运行类型
    public void getClass1(){
        System.out.println(unknown.getClass());
    }
}

2.基本语法

泛型声明
接口:interface 接口{ }
类:class 类<K,V>{ }

其中T、K、V不代表值,而是表示类型,任意字母都可以,常用T表示,是Type的缩写

泛型实例化

要在类的后面指定类型参数
比如:
List<String>stringtest = new ArrayList<String>();

案例练习

要求:
1.创建3个学生对象
2.放入到HashSet中学生对象使用
3.放入到HashMap中,要求Key是String name,Value就是 学生的对象
4.使用两种遍历方式

import java.util.*;

class test1{
    @SuppressWarnings({"all"})
    public static void main(String[] args){
        //HashSet
        HashSet<Student> students = new HashSet<>();
        students.add(new Student("张三",18));
        students.add(new Student("李四",20));
        students.add(new Student("小明",17));

        //HashMap
        HashMap<String, Student> hashMap = new HashMap<>();
        hashMap.put("张三",new Student("张三",18));
        hashMap.put("李四",new Student("李四",20));
        hashMap.put("小明",new Student("小明",17));

        //增强for遍历HashSet
        for (Object o : students) {
            Student student = (Student) o;
            System.out.println(student.getName()+" "+student.getAge());
        }
        System.out.println("=======");
        //迭代器遍历HashMap
        Set<String> keySet = hashMap.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            System.out.println(key+" "+hashMap.get(key).getAge());
        }
        System.out.println("=======");
        //EntrySet方式遍历HashMap
        Set<Map.Entry<String, Student>> entries = hashMap.entrySet();
        Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            Map.Entry<String, Student> entry  = iterator1.next();
            System.out.println(entry.getKey()+" "+entry.getValue().getAge());
        }

    }
}

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

3.泛型使用细节

  1. interface 接口{ } 或 class 类<K,V>{ },其中T、K、V必须是引用数据类型
  2. 泛型指定具体类型后,可以传入该类型或者其子类类型
  3. 泛型使用形式
    ①List< String > list1 = new ArrayList< String >();
    ②List< String > list1 = new ArrayList<>(); 简写形式,比较推荐
  4. 如果我们这样写 List list = new ArrayList(); 默认给它的泛型是[< E > E就是 Object ]
import java.util.ArrayList;

class test1{
    @SuppressWarnings({"all"})
    public static void main(String[] args){
        //细节一
        ArrayList<String> strings = new ArrayList<>();
//        ArrayList<int> ints = new ArrayList<int>();   //错误的

        //细节二
        C<A> A = new C<A>(new A());
        C<A> A1 = new C<A>(new B());

        //细节三
        ArrayList<String> strings1 = new ArrayList<>(); //这里编译器会自动推断
        ArrayList<String> strings2 = new ArrayList<String>();

        //细节四
        ArrayList list = new ArrayList();
        ArrayList<Object> list1 = new ArrayList<Object>();  //跟上面等价
    }
}

class A{}
class B extends A{}
class C<E>{
    E s;

    public C(E s) {
        this.s = s;
    }
}

细节四
在这里插入图片描述
Object e其实就是ArrayList默认的泛型

综合案例练习
要求:

  1. 定义 Employee 类,该类包含:private 成员变量 name,sal,birthday,其中 birthday 为 MyDate 类的对象
  2. 为每一个属性定义 getter, setter 方法
  3. 重写 toString 方法输出 name, sal, birthday
  4. MyDate 类包含: private 成员变量 month,day,year;并为每一个属性定义 getter, setter 方法;
  5. 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),对集合中的元素进 行排序,并遍历
  6. 调用 ArrayList 的 sort 方法 排序, 传入Comparator 对象[使用泛型],先按照 name 排序,如果 name 相同,则按生日日期的先后排序
import java.util.ArrayList;
import java.util.Comparator;

class test1{
    @SuppressWarnings({"all"})
    public static void main(String[] args){
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("tom",5000,new MyDate(2022,8,15)));
        employees.add(new Employee("juck",6000,new MyDate(2022,2,19)));
        employees.add(new Employee("juck",10000,new MyDate(2022,4,20)));

        employees.sort(new Comparator<Employee>(){
            @Override
            public int compare(Employee o1, Employee o2) {
                //判断是否为Employee类型的数据;如果不是就不进行比较
                if (!(o1 instanceof Employee && o2 instanceof Employee)){
                    return 0;
                }
                //判断name是否相同,compareTo字符串的比较
                int i = o1.getName().compareTo(o2.getName());
                if (i != 0 ){
                    return i;
                }

                //如果name相同,判断year
                int i1 = o1.getBirthday().getYear() - o2.getBirthday().getYear();
                if (i1 != 0){
                    return i1;
                }

                //如果name相同,判断month
                int i2 = o1.getBirthday().getMonth() - o2.getBirthday().getMonth();
                if (i2 != 0){
                    return i2;
                }

                //如果name相同,判断day
                int i3 = o1.getBirthday().getDay() - o2.getBirthday().getDay();
                if (i3 != 0){
                    return i3;
                }

                return 0;
            }
        });

        for (Object o: employees) {
            System.out.println(o);
        }
    }
}

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

    public Employee(String name, int 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 int getSal() {
        return sal;
    }

    public void setSal(int 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.getYear() +
                ", birthday=" + birthday.getMonth() +
                ", birthday=" + birthday.getDay() +
                '}';
    }
}

class MyDate{
    private int year;
    private int month;
    private int day;

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

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王博1999

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值