Java初学笔记20-【泛型、自定义泛型类、自定义泛型接口、自定义泛型方法、泛型的继承和通配符、JUnit】

一、泛型

1. 引入

(1)使用传统方法的问题分析,不能对加入到集合ArrayList中的数据类型进行约束(不安全)。同样是Dog类和Cat类,都可以放入集合中,但是遍历时候会出现问题。
(2)遍历的时候,需要进行类型转换,如果集合中的数据量较大,对不同的数据类型,先判断后再向下转型会大大增加开销,对效率有影响

2. 介绍

(1)使用泛型可以人为增加约束。编译时,检查添加元素的类型,提高了安全性
(2)遍历时候可以不用向下转型,直接将Object用Dog接收,减少了类型转换的次数,提高效率
(3)通俗理解:可以将泛型理解成一个“变量”,可以在使用时指定为Integer、String、自定义类等等引用类型其中的一个;泛型又有点像是调用方法时传入的一个实参。
(4)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
(5)在类声明或实例化时,只要指定好需要的具体的类型即可。
(6)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
(7)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。

3. 语法

(1)interface接口< T >和class类<K,V>{ },其中,T,K,V不代表值,,而是表示类型。
(2)任意字母都可以。常用T表示,是Type的缩写
(3)泛型的实例化:要在类名后面指定类型参数的值(类型)。
(4)

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

【泛型示例】
在这里插入图片描述

4. 细节

(1)给泛型指向数据类型时,要求是引用类型,不能是基本数据类型

List< Integer> list = new ArrayList< Integer>(); //OK
List< int> list2 = new ArrayList< int>();//错误

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

Pig< A> aPig = new Pig< A>(new A());
Pig< A> aPig2 = new Pig< A>(new B()); //正确
class B extends A {
class Pig<E> {
E e;
public Pig(E e) {
this.e = e;
}
public void f() {
System.out.println(e.getClass()); //运行类型
}

(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();

二、自定义泛型类

1. 介绍

自己写一个类或者接口,后面定义一些泛型

2. 细节

(1)普通成员可以使用泛型(属性、方法)
(2)使用泛型的数组,不能初始化,因为该数组不确定要开辟多大的空间。
(3)静态方法中不能使用泛型,因为静态方法与对象无关,与类有关
(4)具体使用那一个泛型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
(5)如果在创建对象时,没有指定类型,默认为Object
例子:

class Tiger<T, R, M> {
            String name;
            R r; //属性使用到泛型
            M m;
            T t;
            //因为数组在 new 不能确定 T 的类型,就无法在内存开空间
            T[] ts;
            public Tiger(String name) {
                this.name = name;
            }
            public Tiger(R r, M m, T t) {//构造器使用泛型
                this.r = r;
                this.m = m;
                this.t = t;
            }
            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;
            }
            @Override
            public String toString() {
                return "Tiger{" +
                        "name='" + name + '\'' +
                        ", r=" + r +
                        ", m=" + m +
                        ", t=" + t +
                        ", ts=" + Arrays.toString(ts) +
                        '}';
            }
        }

三、自定义泛型接口

1. 语法

interface 接口名<T,Ra>{ }

2. 注意细节

(1)接口中,成员是静态性质的,也不能使用泛型(这个和泛型类规定一样)
(2)泛型接口的类型,新的接口在继承接口时,或者新的类在实现接口时要确定
(3)没有指定类型,默认为Object。
(4)接口中,default默认方法也可以使用泛型

四、自定义泛型方法

1. 语法

修饰符 <T,R…> 返回类型 方法名 (参数列表){ }

泛型方法
public <TR>void fly(T t,R r) {
}
使用了泛型的方法
public void run(Q q,R r) {
}

2. 注意细节

(1) 泛型方法,可以定义在普通类中,也可以定义在泛型类中
(2)当泛型方法被调用时,类型会确定
(3)public void eat(E e)( ),修饰符后没有<T,R…> eat方法不是泛型方法,而是使用了泛型

五、泛型的继承和通配符

1. 介绍

(1)泛型不具备继承性
List list = new ArrayList( );//不对
List list = new ArrayList<>( );//对
List list = new ArrayList( );//对(默认Object)

2.<?>

支持任意泛型类型

3. <? extends A>

支持A类以及A类的子类,规定了泛型的上限

4.<? super A>

支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

六、JUnit

  1. 在要测试的方法上添加 @Test
  2. alt+enter快捷键: Add ‘JUnit5.4’to classpath

七、泛型练习题

package exercise.chapter15;

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

/**
 * @Package: exercise.chapter15
 * @ClassName: generic02
 * @Author: 爱吃凉拌辣芒果
 * @CreateTime: 2021/10/24 16:27
 * @Description: 泛型练习题
 * 定义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相同,则按生日日期的先后排序。【即:定制排序】
 */
public class generic02 {
    public static void main(String[] args) {
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("AA",15000,new Mydate(10,24,2021)));
        employees.add(new Employee("CC",25000,new Mydate(9,24,2021)));
        employees.add(new Employee("AA",15000,new Mydate(11,30,2000)));
        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                if(!(o1.getName().equals(o2.getName()))){
                    return o2.getName().compareTo(o1.getName());
                }
                return o1.getBirthday().compareMydate(o2);
            }
        });

        //遍历
        System.out.println(employees);
    }
}
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 "\n员工:" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday;
    }
}

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

    public Mydate(int month, int day, int year) {
        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 "month=" + month +
                ", day=" + day +
                ", year=" + year;
    }

    public int compareMydate(Employee o1){
        int n1 = o1.getBirthday().getYear()-this.getYear();
        if(n1 != 0){
            return n1;
        }
        int n2 = o1.getBirthday().getMonth()-this.getMonth();
        if(n2 != 0) {
            return n2;
        }
        int n3 = o1.getBirthday().getDay()-this.getDay();
        if(n3 != 0 ){
            return n3;
        }
        return 0;
    }
}
package exercise.chapter15;

import org.junit.jupiter.api.Test;

import java.util.*;

/**
 * @Package: exercise.chapter15
 * @ClassName: homework01
 * @Author: 爱吃凉拌辣芒果
 * @CreateTime: 2021/10/24 21:14
 * @Description: 泛型练习题
 * 定义个泛型类 DAO<T>,在其中定义一个Map成员变量,Map的键为String类型,值为T类型
 * 分别创建以下方法:
 * (1) public void save(String id,T entity):保存T类型的对象到Map成员变量中
 * (2) public T get(String id): 从 map中获取id对应的对象
 * (3) public void update(String id,T entity):替换map中key为id的内容,改为entity对象
 * (4) public List<T> list():返回map中存放的所有T对象
 * (5) public void delete(String id):删除指定id对象
 * 定义一个 User类:
 * 该类包含:private成员变量(int类型)id, age;(String类型) name.
 * 创建DAO类的对象,分别调用其 save、get、update、list、delete方法来操作User对象,
 * 使用Junit 单元测试类进行测试。
 */
public class homework01 {
    public static void main(String[] args) {

    }
    @Test
    public void Test(){
        DAO<User> integerDAO = new DAO<>();
        integerDAO.save("1号",new User(1,20,"爱吃凉拌辣芒果"));
        integerDAO.save("2号",new User(2,20,"小梅"));
        integerDAO.save("3号",new User(3,20,"大志"));
        System.out.println(integerDAO.get("2号"));

        integerDAO.update("1号",new User(4,10,"小可爱"));

        List<User> list = integerDAO.list();
        System.out.println(list);

        integerDAO.delete("3号");

    }
}
class DAO<T>{
    private Map<String, T> map = new HashMap<>();
    public void save(String id,T entity){
        map.put(id,entity);
    }
    public T get(String id){
        return map.get(id);
    }
    public void update(String id,T entity){
        map.replace(id,entity);
    }
    public List<T> list(){
        List<T> list = new ArrayList<>();
        Set<String> strings = map.keySet();
        for (String str : strings) {
            T t = map.get(str);
            list.add(t);
        }
        return list;
    }
    public void delete(String id){
        map.remove(id);
    }
}
class User{
    private int id;
    private int age;
    private String name;

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "\nUser{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱吃凉拌辣芒果

不断学习,不断进步,共勉~

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

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

打赏作者

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

抵扣说明:

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

余额充值