韩顺平Java33——泛型

泛型(generic)

一言以蔽之——泛型就是可以接受数据类型的数据类型

1.泛型的引出

  • 传统方法: 
package test;

import java.util.ArrayList;

/**
 * @author 紫英
 * @version 1.0
 */
public class Test {
    public static void main(String[] args) {

        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog_("旺财",5));
        arrayList.add(new Dog_("大黄",3));//遍历
        for (Object o : arrayList) {
            //先向下转型
            Dog_ d=(Dog_) o;
            System.out.println("名字" + d.getName() + "年龄:" + d.getAge());
        }
    }
}

class Dog_ {
    String name;
    int age;

    @Override
    public String toString() {
        return "Dog_{" +
                "name='" + name + '\'' +
                ", 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 Dog_(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
class Cat{
    String name;
    int 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 Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

这时在遍历时我们必须向下转型而不能够直接写成Dog类型:

 

这个时候假如我们不小心添加了一只猫,编译时并不会报错,而是会在运行遍历时报以下异常:

//这时如果程序员不小心添加了一只猫
        arrayList.add(new Cat("咪咪",2));

 

 

因为刚才在这里我们进行了向下转型,而Cat无法强转为Dog类型:

 

总结我们遇到的问题:

 如果数据量大的话每次遍历都需要进行向下转型很麻烦,这时就可以引出泛型。

我们使用泛型再进行刚才的操作:

ArrayList<Dog_> arrayList = new ArrayList<>();

可以看到完美解决了之前的两个痛点,添加Cat实例时编译报错而且无需向下转型可以直接遍历(nice!)

2.泛型的好处

3.泛型介绍

比如这里Dog并不是泛型,而是泛型的类型(泛型可以理解为数据类型的类型),这个Dog会传递给那个E

 

 

注特别强调:E具体的数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型

4.泛型语法

  • 练习1:

package generic;

import java.util.*;

/**
 * @author 紫英
 * @version 1.0
 * @discription
 */
public class Generic02 {
    public static void main(String[] args) {
        Student jack = new Student("jack", 15);
        Student marry = new Student("marry", 14);
        Student tom = new Student("tom", 11);
        HashSet<Student> students = new HashSet<Student>();
        /*
        public class HashMap<K,V>
         */
        students.add(jack);
        students.add(marry);
        students.add(tom);
        for (Student student : students) {
            System.out.println(student);
        }
        HashMap<String, Student> stuMap = new HashMap<String, Student>();
        stuMap.put("jack",jack);
        stuMap.put("marry",marry);
        stuMap.put("tom",tom);
        Set<String> keySet = stuMap.keySet();
        for (String s : keySet) {
            System.out.println("name:" + s +" "+ "age:" + stuMap.get(s));
        }

        System.out.println("=======迭代器遍历=======");
        Set<Map.Entry<String, Student>> entries = stuMap.entrySet();
        /*
        public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es;
        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
    }
         */
        Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
        /*
        public final Iterator<Map.Entry<K,V>> iterator() {
            return new EntryIterator();
        }
         */
        while (iterator.hasNext()) {
            Map.Entry<String, Student> m =  iterator.next();
            System.out.println("name:"+m.getKey()+" "+ "age:" + m.getValue());
        }
    }
}
class Student{
    public String name;
    public int age;

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

 

5.注意事项和使用细节

示例:

public class Generic03 {
    public static void main(String[] args) {
        HashSet<Animal> animals = new HashSet<>();
        //在给泛型制定具体类型后可以传入该类型或其子类型
        animals.add(new Pig<String>("pig"));
        HashSet<Pig> pigs = new HashSet<>();
        //右边可以省略
    }
}
class Animal{}
class Pig <E>extends Animal{
    E e;

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

 

  • 练习2

package generic;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Comparator;

/**
 * @author 紫英
 * @version 1.0
 * @discription
 */
public class Generic04 {
    public static void main(String[] args) {
        Employee jack = new Employee("jack", 15000, new MyDate(2000, 12, 26));
        Employee jack1 = new Employee("jack", 14000, new MyDate(2000, 12, 26));
        Employee jack2 = new Employee("jack", 14000, new MyDate(1998, 11, 25));
//        Employee jack3 = new Employee("jack", 14000, new MyDate(2010, 11, 26));
        Employee marry = new Employee("marry", 16000, new MyDate(1999, 1, 4));
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(jack);
        employees.add(jack1);
        employees.add(jack2);

        employees.add(marry);
        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                if (!(o1.getName().equals(o2.getName()))) {
                    return o1.getName().compareTo(o2.getName());
                } else {
                    return o1.getBirthday().compareTo(o2.getBirthday());
                }
            }
        });
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
}

class Employee {
    private String name;
    private double sal;
    private MyDate 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;
    }

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

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

class MyDate implements Comparable<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;
    }

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


    @Override
    public int compareTo(@NotNull MyDate date) {
        //中间变量存储传入的数据
        int year1 = (date).getYear();
        int yearMin = year - year1;
        int month1 = (date).getMonth();
        int monthMin = month - month1;
        int day1 = (date).getDay();
        int dayMin = day - day1;
        if (yearMin != 0) {
            return yearMin;
        } else if (monthMin != 0) {
            return monthMin;
        } else return dayMin;
    }
}

6.自定义泛型

  • 6.1自定义泛型类

 说明:T、R等为泛型的标识符,一般为一个大写字母

泛型数组不能初始化是因为不知道要开辟多少空间的内存

静态方法和属性不能使用泛型是因为static是在类加载的时候就需要确定的,而泛型是在创建对象时才确定,先后顺序不一致(static先于泛型)

练习:这里Tiger类后面加了泛型我们称之为自定义泛型类

  • 6.2自定义泛型接口

这里注意:接口中的方法和属性都是抽象,属性是public static final的,方法是public abstract的,所以不能定义泛型类型的属性。 

  • 6.3自定义泛型方法

 

  • 小练习:

 

7.泛型的继承和通配符

 1)错误,泛型之间不具有继承性(虽然String是Object的子类)

写法:

 

posted @ 2022-01-23 16:01  紫英626  阅读(39)  评论(0编辑  收藏  举报

紫英