[豪の学习笔记] JavaReStudy#13

跟学视频:韩顺平Java课程

泛型

1 - 对泛型的理解

​ 使用传统方法存在两个问题:①不能对加入到集合ArrayList中的数据类型进行约束(不安全) ②遍历的时候,需要进行类型转换,如果集合中的数据量较大则会对效率有影响

​ 使用泛型:①编译时检查添加元素的类型,提高了安全性 ②减少了类型转换的次数,提高效率

基本介绍

​ 泛型又称参数化类型,是JDK5.0出现的新特性,解决数据类型的安全性问题

​ 在类声明或实例化时只要指定好需要的具体的类型即可

​ Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常,同时代码也会更加简洁、健壮

​ 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型

class Person<E> {
    E s; //E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
    public Person(E s){ //E也可以是参数类型
        this.s = s;
    }
    public E f(){ //返回类型使用E
        return s;
    }
}

2 - 泛型的语法

泛型的声明

interface<T>{}
class<K,V>{}
// public interface List<E> extends Collection<E>

​ 其中,T、K、V不代表值,而是表示类型

​ 任意字母都可以,常用T(Type)表示

泛型的实例化

​ 要在类名后面指定类型参数的值(类型)

List<String> strList = new ArrayList<String>();
Iterator<Customer> iterator = customers.iterators();

泛型的使用

@SuppressWarnings({"all"})
public class GenericExercise {
    public static void main(String[] args){
        HashSet<Student> students = new HashSet<Student>();
        students.add(new Student("A",18));
        students.add(new Student("B",19));
        students.add(new Student("C",20));

        for(Student s : students){
            System.out.println(s);
        }

        HashMap<String, Student> hm = new HashMap<String, Student>();
        hm.put("a", new Student("A",18));
        hm.put("b", new Student("B",19));
        hm.put("c", new Student("C",20));

        Set<Map.Entry<String, Student>> entries = hm.entrySet();
        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());
        }
    }
}

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 int getAge(){
        return age;
    }

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

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

注意事项和使用细节

​ 1)这里的T、E只能是引用数据类型:

interface List<T>{}		public class HashSet<E>{}

​ 2)在给泛型指定具体类型后,可以传入该类型或者其子类类型

​ 3)泛型的使用形式:

ArrayList<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
//在实际开发中,我们往往简写,编译器会进行类型推断
ArrayList<Integer> list3 = new ArrayList<>();
List<Integer> list4 = new ArrayList<>();

​ 4)这样写泛型默认是0bject:

ArrayList arrayList = new ArrayList();
//等价 ArrayList<Object> arrayList = new ArrayList<>();

3 - 泛型使用案例

​ 定义Employee类
​ 1)该类包含: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需使用泛型来定义),对集合中的元素进行排序,并遍历输出
​ 排序方式:调用ArrayList的sort方法,传入Comparator对象[使用泛型],先按照name排序,如果name相同,则按生日日期的先后排序。【即:定制排序】

package com.magicshushu;

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

@SuppressWarnings({"all"})
public class GenericExercise {
    public static void main(String[] args){
        Employee e1 = new Employee("Jackey", 8000, new MyDate(2000,1,2));
        Employee e2 = new Employee("Smith", 9000, new MyDate(1999,5,1));
        Employee e3 = new Employee("Lorder", 10000, new MyDate(1987,12,22));

        ArrayList<Employee> es = new ArrayList<Employee>();
        es.add(e1);
        es.add(e2);
        es.add(e3);

        for(Employee e: es){
            System.out.println(e);
        }

        es.sort(new Comparator<Employee>(){
            @Override
            public int compare(Employee e1, Employee e2){
                if(!(e1 instanceof Employee && e2 instanceof Employee)){
                    System.out.println("类型不正确");
                    return 0;
                }

                int i = e1.getName().compareTo(e2.getName());
                if (i != 0){
                    return i;
                }

                return e1.getBirthday().compareTo(e2.getBirthday());
            }
        });

        for(Employee e: es){
            System.out.println(e);
        }
    }
}

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

    Employee(){}

    Employee(String name, int salary, MyDate birthday){
        this.name = name;
        this.salary = salary;
        this.birthday = birthday;
    }

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

    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }

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

    @Override
    public String toString() {
        return "[name=" + name + ", salary=" + salary + ", birthday=" + birthday + "]";
    }
}

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

    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(MyDate o) {
        int yearMunus = year - o.getYear();
        if (yearMunus != 0){
            return yearMunus;
        }

        int monthMunus = month - o.getMonth();
        if (monthMunus != 0){
            return monthMunus;
        }

        return day - o.getDay();
    }
}

4 - 自定义泛型类

基本语法

class 类名<T, R...>{
	成员
}

注意细节

​ 普通成员(属性、方法)可以使用泛型

​ 使用泛型的数组,不能初始化(不能实例化),因为无法确定开辟空间

​ 静态方法中不能使用类的泛型,因为静态是和类相关的,在类加载时对象还没有创建,所以如果静态方法和静态属性使用了泛型,JVM就无法完成初始化

​ 泛型类的类型是在创建对象时确定的,因为创建对象时需要指定类型

​ 如果在创建对象时没有指定类型,默认为Object

5 - 自定义泛型接口

基本语法

interface 接口名<T, R...>{}

注意细节

​ 接口中,静态成员不能使用泛型

​ 泛型接口的类型在继承接口或者实现接口时确定

​ 没有指定类型则默认为Object

interface IUsb<U, R> {
	//普通方法中,可以使用接口泛型
	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;
    }
}

interface IA extends IUsb<String, Double>{ }

//当我们去实现IA接口时,因为IA在继承IUsu接口时,指定了U为String, R为Double,所以在实现IUsu接口的方法时,使用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) {}
}

6 - 自定义泛型方法

基本语法

修饰符 <T,R...> 返回类型 方法名(参数列表){ }
// public <T, R> void fly(T t, R r){ }

注意细节

​ 泛型方法可以定义在普通类中,也可以定义在泛型类中

​ 当泛型方法被调用时,传入参数,编译器就会确定类型

​ public void eat(E e){ },修饰符后没有<T,R...>,故不是泛型方法,而是使用了泛型

​ 泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型

7 - 泛型的继承和通配符

​ 泛型不具备继承性

​ <?>表示支持任意泛型类型

​ <? extends A>表示支持A类以及A类的子类,规定了泛型的上限

​ <? super A>表示支持A类以及A类的父类,不限于直接父类,规定了泛型下限

public class GenericExtends {
	public static void main(String[] args) {
		List<Object> list1 = new ArrayList<>();
		List<String> list2 = new ArrayList<>();
		List<AA> list3 = new ArrayList<>();
		List<BB> list4 = new ArrayList<>();
		List<CC> list5 = new ArrayList<>();

        //如果是 List<?> c ,可以接受任意的泛型类型
		printCollection1(list1);
		printCollection1(list2);
		printCollection1(list3);
		printCollection1(list4);
		printCollection1(list5);
        
		//List<? extends AA> c 表示上限,可以支持AA及AA类的子类
		//printCollection2(list1);//×
		//printCollection2(list2);//×
		printCollection2(list3);//√
		printCollection2(list4);//√
		printCollection2(list5);//√

        //List<? super AA> c 支持AA类及AA类的父类(不限于直接父类
		printCollection3(list1);//√
		//printCollection3(list2);//×
		printCollection3(list3);//√
		//printCollection3(list4);//×
		//printCollection3(list5);//×
    }
    
	//List<?> 表示 任意的泛型类型都可以接受
	public static void printCollection1(List<?> c) {
		for (Object object : c) { //通配符,取出时就是Object
			System.out.println(object);
		}
	}
	
    // ? extends AA 表示上限,可以支持AA及AA类的子类
	public static void printCollection2(List<? extends AA> c) {
		for (Object object : c) {
			System.out.println(object);
		}
	}
    
    // ? super AA 表示下限,可以支持AA类及AA类的父类
	public static void printCollection3(List<? super AA> c) {
		for (Object object : c) {
			System.out.println(object);
		}
	}
}

class AA {}
class BB extends AA {}
class CC extends BB {}
posted @ 2025-05-26 19:50  SchwarzShu  阅读(10)  评论(0)    收藏  举报