JAVA泛型

泛型

  • 使用传统方法的问题分析

    1. 不能对加入到集合ArraysList中的数据类型进行约束(不安全);
    2. 遍历的时候需要进行类型转换,如果集合中数据量较大,对效率有影响
public class Generic01 {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //使用传统的方法
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog("旺财",12));
        arrayList.add(new Dog("小兰",13));
        arrayList.add(new Dog("小天",14));
        //对数据类型没有约束,可以添加Cat类
        arrayList.add(new Cat("招财",8));


        for (Object o: arrayList) {
            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;
    }
}

使用泛型的好处

  1. 编译时,检查添加元素的类型,提高了安全性
  2. 减少了类型转换的次数,提高效率
public class Generic02 {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //使用泛型
        //当我们  ArrayList<Dog>  表示存放到ArrayList集合中的元素是Dog类型
        //如果编译器发现添加的类型不满足要求就会报错
        ArrayList<Dog> arrayList = new ArrayList<Dog>();
        arrayList.add(new Dog("旺财",12));
        arrayList.add(new Dog("小兰",13));
        arrayList.add(new Dog("小天",14));
//        arrayList.add(new Cat("招财",8));

        //可以直接取出Dog类型而不需要向下转型
        for (Dog dog: arrayList) {
            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. 泛型又称参数化类型,是jdk5.0出现的新特性,解决数据类型的安全性问题
  2. 在类声明或实例化时只要指定好需要的具体的类型即可
  3. java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生
    ClassCastException异常
  4. 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或是某个方法的返回值的类型或是参数类型。
public class Generic03 {
    public static void main(String[] args) {
        Person<String> person = new Person<String>("程冠希");
        System.out.println(person.getClass());
    }
}
//泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,
// 或是某个方法的返回值的类型或是参数类型。
class Person<E>{
    E s;//E表示 s 的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间就确定E是什么类型

    public Person(E s) {//E
        this.s = s;
    }
    public E f(){
        return s;
    }
}

泛型的应用实例

  • 泛型的声明

    interface接口{}和class类<K,V>{}

    比如List,ArrayList

    说明:

    1. 其中,T,K,V不代表值,而是表示类型
    2. 任意字母都可以,常用T表示,是Type的缩写
  • 泛型的实例化

    要在类名后面指定类型参数的值(类型)。如:

    1. List strList = new ArrayList();
    2. Iterator iterator = customers.iterator();
public class GenericExercise01 {
    public static void main(String[] args) {
        //1.HashSet
        Set<Student> set = new HashSet<Student>();
        set.add(new Student("jack",12));
        set.add(new Student("jay",12));
        set.add(new Student("july",12));
        //使用迭代器遍历
        Iterator<Student> iterator = set.iterator();
        while(iterator.hasNext()){
            Student student = iterator.next();
            System.out.println(student);
        }
        HashMap<String,Student> hashMap = new HashMap<String, Student>();
        hashMap.put("1",new Student("小红",12));
        hashMap.put("2",new Student("小绿",12));
        hashMap.put("3",new Student("小蓝",12));

        System.out.println(hashMap);

        Set<Map.Entry<String, Student>> entries = hashMap.entrySet();
        Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();
        while(iterator1.hasNext()){
            Map.Entry<String, Student> next = iterator1.next();
            System.out.println(next);
        }
    }
}
class Student{
    private String name;
    private int age;

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

    public Student(String name, int age){
        super();
        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;
    }
}

一个小案例来实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wPKJy9EL-1665759655760)(E:\学习笔记\图片\Snipaste_2022-06-22_21-01-55.jpg)]

public class GenericExercise02 {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        ArrayList<Employee> employees = new ArrayList<>();

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        employees.add(new Employee("tom",1243,new MyDate(2002,02,13)));
        employees.add(new Employee("jack",1224,new MyDate(2002,03,14)));
        employees.add(new Employee("tim",1234,new MyDate(2002,04,15)));
        employees.add(new Employee("sam",1254,new MyDate(2002,05,17)));
        employees.add(new Employee("sam",1254,new MyDate(2002,05,16)));

        System.out.println(employees);
        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;
                }
                int i = emp1.getName().compareTo(emp2.getName());
                if(i!=0){
                    return i;
                }

                //下面是对birthday的比较,因此我们最好吧这个比较放在MyDate类完成
                return emp1.getBirthday().compareTo(emp2.getBirthday());
            }
        });
        System.out.println(employees);
    }
}
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 "\n 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.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{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }

    @Override
    public int compareTo(MyDate o) {
        int yearMinus = year-o.getYear();
        if (yearMinus!=0){
            return yearMinus;
        }
        int monthMinus =month-o.getMonth();
        if (monthMinus!=0){
            return monthMinus;
        }
        int dateMinus =day-o.getDay();
        if (dateMinus!=0){
            return dateMinus;
        }
        return 0;
    }
}

自定义泛型

class 类名<T,R…>{//…表示可以有多个泛型

}

注意细节

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

  2. 使用泛型的数组,不能初始化

    //因为数组在new时 不能确定T的类型,就无法在内存开空间
    //java在编译期间所有的泛型信息都会被擦除掉,泛型附加的类型信息对JVM来说是不可见的,而数组是在运行时
    //解决方法:使用一个泛型数组包装器,维护一个原始类型的数组,
    // 通过数组入口方法进行元素编译期的类型安全检测(对应返回值)和强制类型转换(对于运行时不重要),从而保证类型安全。
    //T[] ts=new T[3];
    
  3. 静态方法中不能使用类的泛型

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

  5. 如果再创建对象时,没有指定类型,默认为Object

自定义泛型接口

  • 基本语法

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

  • 注意细节

    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) {
    
        }
    }
    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.没有指定类型,默认为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) {

    }
}

自定义泛型方法

  • 基本语法

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

    }

  • 注意细节

    1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中
    2. 当泛型方法被调用时,类型会确定
    3. public void eat(E e){},修饰符后没有<T,R>,eat方法不是泛型方法,而是使用了泛型
public class CustomMethodGeneric {
    public static void main(String[] args) {
        Car car = new Car();
        car.fly("宝马",100);//当调用方法时,传入参数,编译器就会确定类型
        car.fly(300,300.1);

        Fish<String, ArrayList> stringArrayListFish = new Fish<>();
        stringArrayListFish.hello(new ArrayList<>(),11.2f);
    }
}
//泛型方法,可以定义在普通类中,也可以定义在泛型类中
class Car{
    public void run(){//普通方法
    }
    //1.<T,R>就是泛型
    //2.是提供给fly用的
    public <T,R> void fly(T t,R r){//泛型方法
        System.out.println(t.getClass());
        System.out.println(r.getClass());
    }
}
class Fish<T,R>{//泛型类
    public void run(){//普通方法
    }
    public <U,M> void eat(U u,M m){//泛型方法
    }
    //下面的hi方法不是泛型方法
    //是hi方法使用了类声明的泛型

    public void hi(T t){

    }
    //泛型方法,可以使用类声明的泛型,也可以使用自己声明的泛型
    public <K> void hello(R r,K k){
        System.out.println(r.getClass());
        System.out.println(k.getClass());
    }
}

泛型的继承和通配符

  1. 泛型不具备继承性
    List list = new ArrayList ();//错误
  2. <?>:支持任意泛型类型
  3. <? extends A>:支持A类以及A类的子类,规定了泛型的上限
  4. <? 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<>();
        
        //<?>:支持任意泛型类型
        printCollection1(list1);
        printCollection1(list2);
        printCollection1(list3);
        printCollection1(list4);
        printCollection1(list5);

        // <? extends A>:表示上限可以接受AA和AA的子类
        //printCollection2(list1);
        //printCollection2(list2);
        printCollection2(list3);
        printCollection2(list4);
        printCollection2(list5);
        
        //<? super A>:表示下限可以接受AA,接收AA和AA类的父类
        printCollection3(list1);
        //printCollection3(list2);没关系
        printCollection3(list3);
       // printCollection3(list4);子类
        //printCollection3(list5);子类
    }
    //<?>:支持任意泛型类型
    public static void printCollection1(List<?>c) {
        for (Object object : c) {
            System.out.println(object);
        }
    }
    // <? extends A>:支持A类以及A类的子类,规定了泛型的上限
    public  static void printCollection2(List<? extends AA>c) {
            for (Object object : c) {
                System.out.println(object);
            }
        }
    //<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
    public static void printCollection3(List<? super AA >c) {
        for (Object object : c) {
            System.out.println(object);
        }
    }
    }

JUnit

  1. 一个类有很多功能代码需要测试,为了测试,就需要写入到main方法中
  2. 如果有多个功能代码测试,就需要来回注销,切换很麻烦
  3. 如果可以直接运行一个方法就方便很多,并且可以给出相关信息,就好了
  • JUnit是java语言的单元测试框架

  • 多数java的开发环境已经集成了JUnit作为单元测试的工具

     }
    

    }
    // <? extends A>:支持A类以及A类的子类,规定了泛型的上限
    public static void printCollection2(List<? extends AA>c) {
    for (Object object : c) {
    System.out.println(object);
    }
    }
    //<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
    public static void printCollection3(List<? super AA >c) {
    for (Object object : c) {
    System.out.println(object);
    }
    }
    }




## JUnit

1. 一个类有很多功能代码需要测试,为了测试,就需要写入到main方法中
2. 如果有多个功能代码测试,就需要来回注销,切换很麻烦
3. 如果可以直接运行一个方法就方便很多,并且可以给出相关信息,就好了



- JUnit是java语言的单元测试框架
- 多数java的开发环境已经集成了JUnit作为单元测试的工具

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

网代慎平

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

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

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

打赏作者

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

抵扣说明:

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

余额充值