泛型-转韩顺平

本文介绍了Java中的泛型概念,其主要目的是提高代码的安全性和效率,避免类型转换异常。泛型允许在类、接口和方法中指定数据类型,确保在编译时期就能捕获潜在的类型错误。通过使用泛型,可以限制集合中存储的元素类型,减少不必要的类型转换,并消除编译警告。示例代码展示了如何在ArrayList和HashMap中使用泛型,以及自定义泛型类和方法的规则。此外,还提到了泛型的继承、通配符及其用途。

本文内容基于韩顺平java课程所总结的基础笔记

泛型简介

简单的说就是指定具体的数据类型,在不使用泛型之前,可能会在一个ArrayList集合中误存入一个其他对象元素,导致遍历时出现错误的向下转型异常,使用泛型可以限制集合中存入的对象的数据类型。
指定数据类型的一种数据类型

1.减少类型转换 在传统的ArrayList中,遍历时还需要通过类型转换,影响效率

不使用泛型 存入Dog转换为Object,取出将Object转换为Dog
使用泛型 存入Dog 直接存进Dog类型数组 取出也是Dog

通过泛型,可以直接通过增加for循环取得指定的数据类型
2.检查添加时元素类型提升安全性
3.不再提示编译警告

使用泛型

ArrayList<Dog> arraylist = new ArrayList<Dog>();

理论

  1. 泛型称为参数化类型,JDK5.0出现,解决数据类型安全问题
  2. 声明和实例化时 指定 具体数据类型
  3. 泛型可保证 只要编译不出错,运行就不会出现类型转换异常
  4. 可以在类声明时 通过标识表明类中某个属性的类型,或者某个方法返回值类型,或者参数的类型(HashMap中有)

使用场景

  • 接口/类中都可以使用
  • 泛型的实例化要在后面指定类型参数的值
  • 可以在获取迭代器的时候迭代指定数据类型(若与底层的数据类型不同,系统自动帮忙强转)
  • 指定的数据类型的子类也可以存入(父类引用指向子类对象)
import java.util.*;
public class GenericExercise {
    public static void main(String[] args) {
//        HashSet students = new HashSet();
//        students.add(new Student("hmj",18));
//        students.add("ing");
//        Iterator<Student> iterator = students.iterator();
//        while (iterator.hasNext()) {
//            Student next =  iterator.next();
//            System.out.println(next);
//        }

        //获取map可能麻烦些
        HashMap<String, Student> stringStudentHashMap = new HashMap<>();
        stringStudentHashMap.put("no1", new Student("hmj1", 18));
        stringStudentHashMap.put("no2", new Student("hmj2", 18));
        stringStudentHashMap.put("no3", new Student("hmj3", 18));
        Set<Map.Entry<String, Student>> entries = stringStudentHashMap.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().getName());
        }
    }
}
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;
    }
}

注意事项

  • 泛型不能指向基本数据类型
  • 确定泛型后,可以传入该类/该类子类
  • 实际工作中,给引用写泛型即可,对象可以不用写泛型
  • 若不给泛型指定数据类型,默认的泛型是Object
import java.util.ArrayList;
public class GenericDetail {
    public static void main(String[] args) {
        ArrayList<A> as = new ArrayList<>();
        as.add(new B());//可以传入泛型数据类型的子类

        //若不给ArrayList写泛型,则默认是object
        //不是说没有泛型,而是默认泛型是Object
        ArrayList arrayList = new ArrayList();
        arrayList.add("这里添加的是Object任意数据类型");

    }
}
class A{}
class B extends A{}

这里插入题目1 自定义排序

自定义泛型

前面一直都是使用库函数ArrayList这种已经写好泛型的类,现在自己练习写自定义泛型类
基本语法就是在定义类的后面<T,S> 可以有多个泛型

自定义泛型

  • 普通成员可以使用泛型 (类的属性中可以,方法中也可使用,传参返回值等等)
  • 使用泛型的数组不能初始化(因为不知道到底有多长,到底是什么数据类型,只有实例化后才知道)
  • 静态方法中不能使用泛型(因为使用泛型需要实例化对象)
  • 泛型类的类型 是在创建对象时就已经确定的(创建对象时指定泛型的数据类型)
  • 若创建对象时未指定数据类型,则是Object类型
class Tiger<T,R,M>{//这种类称之为自定义泛型类,可以有多个
    String name;
    T t;
    R r;
    M m;//普通成员可以使用泛型
    T ts[] = new T[8];//错误,无法确定类型,不知道要初始化多长的空间
    //必须在实例化对象之后才执行的再去实例化

    public static void r(R i) {}//错误,使用时可能还未创建对象
    static R z;//静态属性不能使用,因为 静态属性使用时没创建对象
    public Tiger(String name, T t, R r, M m) {//方法可以使用泛型
        this.name = name;
        this.t = t;
        this.r = r;
        this.m = m;
    }
}

自定义泛型接口

  • 在接口中,静态成员不能使用泛型
  • 泛型接口类型,在继承接口/实现接口时确定(不指定则是Object)
    在implement时就指定,extends时就指定
  • 若未指定则是object
  • 在接口中,默认成员是静态的

interface IO<T,R>{
    public void Temperature(T t);
    public void hello(R r);
}

class IA implements IO<Double,String>{
    @Override
    public void Temperature(Double aDouble) {//生成时自动填充数据类型!}
    @Override
    public void hello(String s) {}
}
class IB implements IO{
    @Override
    public void Temperature(Object o) {//未指定数据类型,自动使用object}
    @Override
    public void hello(Object o) {}

自定义泛型方法

泛型也可出现在方法中(需要特别注意自定义泛型方法和自定义泛型类)

  • 自定义泛型方法,可以出现在普通类/泛型类中都可以
  • 当泛型方法被调用时,类型会自动被确定
  • 只有在访问修饰符后有泛型定义的才是泛型类,若该方法没有定义泛型类却使用了泛型,则可能只是使用了 泛型接口/泛型类
    在这里插入图片描述
下面是泛型方法和泛型类的区分
public class CustomGeneric_ {
    public static void main(String[] args) {
        Car car = new Car();
        car.run("w",7.8);//此时输出的是String 和 装箱后的Double,是泛型方法!!!
        car.run1("3");//此时是Object引用指向String,因为实例化car时未定义泛型
        Car<Double> doubleCar = new Car<>();
        doubleCar.run1(6.66);//此时就是Double类,是泛型类!!!
    }
}

class Car<T>{
    public void run1(T t){//使用泛型类!!
        System.out.println(t.getClass());
    }
    public<U,M> void run(U u,M m){//使用泛型方法!!!
        System.out.println(u.getClass());
        System.out.println(m.getClass());
    }
}

泛型的继承和通配符

通配符补充泛型不可继承
这个通配符通常用于传参的使用限制类型的范围,以免方法访问到不存在的方法或属性

  1. 泛型不具有继承性,父类的泛型类型引用不能指向子类泛型类型的对象
    List<Object> list = new ArrayLIst<String>();这条语句是错误的
  2. 通配符<?>支持任意泛型类型
  3. <?? extends A> A与A的子类都可以,规定泛型上线
  4. <?? super A> A与A的父类都可以,不限于直接父类,限制泛型的下限
public class GenerticExtends_ {
    public static void main(String[] args) {
        ArrayList<CC> aas = new ArrayList<>();
        printCollection(aas);//合法,是AA的子类
    }
    public static void printCollection(List<? extends AA> c)
    {
        for (Object o :c) {
            System.out.println(o);
        }
    }
}
class AA{}
class BB extends AA{}
class CC extends BB{}//AA的孙子类
临时插入(JUnit测试)

为了方便测试某个方法,有时只需要直接运行某个方法就行,无需经过main方法
在方法前加一个@Test Alt+Enter导入框架,等待片刻旁边就有绿色运行,直接按就可以运行当前方法

完成题目2

练习题库

题目1 自定义排序

在这里插入图片描述

package com.hspedu.Generic_;

import javax.lang.model.element.NestingKind;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;

public class GenericExercise02 {
    public static void main(String[] args) {
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("hmj", 5000.00, new MyDate(2, 4, 2005)));
        employees.add(new Employee("qlx", 5000.00, new MyDate(2, 4, 2004)));
        employees.add(new Employee("qlx", 5000.00, new MyDate(2, 4, 2005)));
        employees.add(new Employee("qlx", 5000.00, new MyDate(2, 4, 2006)));
        employees.add(new Employee("wxh", 5000.00, new MyDate(2, 4, 2004)));
        employees.add(new Employee("abc", 5000.00, new MyDate(2, 3, 2004)));
        employees.sort(new Comparator<>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                int name = o1.getName().compareTo(o2.getName());
                if (name != 0) {
                    return name;
                }
                return o1.getBirthday().compareTo(o2.getBirthday());
            }
        });

        Iterator<Employee> iterator = employees.iterator();
        while (iterator.hasNext()) {
            Employee next = iterator.next();
            System.out.println(next);
        }
    }
}

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;
    }
    @Override
    public String toString() {
        return "员工{" + "name='" + name + '\'' + ", sal=" + sal + ", 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;
    }
}


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


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

    @Override
    public String toString() {
        return year + "年" + month + "月" + day + "日";
    }
    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;
    }
}

题目2 泛型测试 在这里插入图片描述


import org.junit.jupiter.api.Test;

import java.util.*;

public class Homework01 {
    public static void main(String[] args) {

    }
    @Test
    public void testSave() {
        DAO<User> userDAO = new DAO<>();
        userDAO.save("1",new User(1,"hmj",18));
        userDAO.save("2",new User(2,"king",13));
        userDAO.save("3",new User(3,"zing",16));

        System.out.println("ID为2的="+userDAO.get("2"));

        System.out.println("\n升级2为ding");
        userDAO.update("2",new User(2,"ding",16));
        System.out.println("ID为2的="+userDAO.get("2"));
        System.out.println("\n 不存在的id返回");
        System.out.println(userDAO.get("999"));

        System.out.println("返回所有t对象");
        List<User> list = userDAO.list();
        for (User user :list) {
            System.out.println(user);
        }
        System.out.println("删除对象");
        userDAO.delete("3");
        List<User> list2 = userDAO.list();
        for (User user :list2) {
            System.out.println(user);
        }



    }
}

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(){
//        return (List<T>) map.values();(错误)
        List<T> ts = new ArrayList<>();
        Set<String> strings = map.keySet();
        for (String s :strings) {
            ts.add(map.get(s));
        }
        return ts;
    }

    public void delete(String id){
        map.remove(id);
    }
}


class User{
    private int id;
    private String name;
    private int age;

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

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

    public int getId() {
        return id;
    }

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值