【Java】—— 泛型:泛型的理解及其在集合(List,Set)、比较器(Comparator)中的使用

news2024/11/24 15:55:02

目录

1. 泛型概述

1.1 生活中的例子

1.2 泛型的引入

2. 使用泛型举例

2.1 集合中使用泛型

2.1.1 举例

2.1.2 练习

2.2 比较器中使用泛型

2.2.1 举例

2.2.2 练习


1. 泛型概述

1.1 生活中的例子

  • 举例1:中药店,每个抽屉外面贴着标签

  • 举例2:超市购物架上很多瓶子,每个瓶子装的是什么,有标签

  • 举例3:家庭厨房中:

Java中的泛型,就类似于上述场景中的标签

1.2 泛型的引入

        在Java中,我们在声明方法时,当在完成方法功能时如果有未知的数据需要参与,这些未知的数据需要在调用方法时才能确定,那么我们把这样的数据通过形参表示。在方法体中,用这个形参名来代表那个未知的数据,而调用者在调用时,对应的传入实参就可以了。

        受以上启发,JDK1.5设计了泛型的概念。泛型即为“类型参数”,这个类型参数在声明它的类、接口或方法中,代表未知的某种通用类型。

举例1:

        集合类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK5.0之前只能把元素类型设计为Object,JDK5.0时Java引入了“参数化类型(Parameterized type)”的概念,允许我们在创建集合时指定集合元素的类型。比如List<String>,这表明该List只能保存字符串类型的对象。

        使用集合存储数据时,除了元素的类型不确定,其他部分是确定的(例如关于这个元素如何保存,如何管理等)。

举例2:

  java.lang.Comparable接口和java.util.Comparator接口,是用于比较对象大小的接口。这两个接口只是限定了当一个对象大于另一个对象时返回正整数,小于返回负整数,等于返回0,但是并不确定是什么类型的对象比较大小。JDK5.0之前只能用Object类型表示,使用时既麻烦又不安全,因此 JDK5.0 给它们增加了泛型。

其中<T>就是类型参数,即泛型。

所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值或参数的类型。这个类型参数将在使用时(例如,继承或实现这个接口、创建对象或调用方法时)确定(即传入实际的类型参数,也称为类型实参)。

2. 使用泛型举例

        自从JDK5.0引入泛型的概念之后,对之前核心类库中的API做了很大的修改,例如:JDK5.0改写了集合框架中的全部接口和类、java.lang.Comparable接口、java.util.Comparator接口、Class类等。为这些接口、类增加了泛型支持,从而可以在声明变量、创建对象时传入类型实参。

2.1 集合中使用泛型

2.1.1 举例

集合中没有使用泛型时:

集合中使用泛型时:

Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。即,把不安全的因素在编译期间就排除了,而不是运行期;既然通过了编译,那么类型一定是符合要求的,就避免了类型转换。

同时,代码更加简洁、健壮。

把一个集合中的内容限制为一个特定的数据类型,这就是generic背后的核心思想。

举例:

//泛型在List中的使用
@Test
public void test1(){
    //举例:将学生成绩保存在ArrayList中
    //标准写法:
    //ArrayList<Integer> list = new ArrayList<Integer>();
    //jdk7的新特性:类型推断
    ArrayList<Integer> list = new ArrayList<>();

    list.add(56); //自动装箱
    list.add(76);
    list.add(88);
    list.add(89);
    //当添加非Integer类型数据时,编译不通过
    //list.add("Tom");//编译报错

    Iterator<Integer> iterator = list.iterator();
    while(iterator.hasNext()){
        //不需要强转,直接可以获取添加时的元素的数据类型
        Integer score = iterator.next();
        System.out.println(score);
    }
}

举例:

//泛型在Map中的使用
@Test
public void test2(){
    HashMap<String,Integer> map = new HashMap<>();

    map.put("Tom",67);
    map.put("Jim",56);
    map.put("Rose",88);
    //编译不通过
    //        map.put(67,"Jack");

    //遍历key集
    Set<String> keySet = map.keySet();
    for(String str:keySet){
        System.out.println(str);
    }

    //遍历value集
    Collection<Integer> values = map.values();
    Iterator<Integer> iterator = values.iterator();
    while(iterator.hasNext()){
        Integer value = iterator.next();
        System.out.println(value);
    }

    //遍历entry集
    Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
    Iterator<Map.Entry<String, Integer>> iterator1 = entrySet.iterator();
    while(iterator1.hasNext()){
        Map.Entry<String, Integer> entry = iterator1.next();
        String key = entry.getKey();
        Integer value = entry.getValue();
        System.out.println(key + ":" + value);
    }

}
2.1.2 练习

练习1:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import java.util.function.Predicate;

public class TestNumber {
    public static void main(String[] args) {
        ArrayList<Integer> coll = new ArrayList<Integer>();
        Random random = new Random();
        for (int i = 1; i <= 5 ; i++) {
            coll.add(random.nextInt(100));
        }

        System.out.println("coll中5个随机数是:");
        for (Integer integer : coll) {
            System.out.println(integer);
        }
		
        //方式1:使用集合的removeIf方法删除偶数
        coll.removeIf(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) {
                return integer % 2 == 0;
            }
        });
        //方式2:调用Iterator接口的remove()方法
        //Iterator<Integer> iterator1 = coll.iterator();
        //while(coll.hasNext()){
        //    Integer i = coll.next();
        //   if(i % 2 == 0){
        //       coll.remove();
        //    }
        //}

        System.out.println("coll中删除偶数后:");
        Iterator<Integer> iterator = coll.iterator();
        while(iterator.hasNext()){
            Integer number = iterator.next();
            System.out.println(number);
        }

    }
}

2.2 比较器中使用泛型

2.2.1 举例
public class Circle{
    private double radius;

    public Circle(double radius) {
        super();
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    @Override
    public String toString() {
        return "Circle [radius=" + radius + "]";
    }

}

使用泛型之前:

import java.util.Comparator;

class CircleComparator implements Comparator{
    @Override
    public int compare(Object o1, Object o2) {
        //强制类型转换
        Circle c1 = (Circle) o1;
        Circle c2 = (Circle) o2;
        return Double.compare(c1.getRadius(), c2.getRadius());
    }
}
//测试:
public class TestNoGeneric {
    public static void main(String[] args) {
        CircleComparator com = new CircleComparator();
        System.out.println(com.compare(new Circle(1), new Circle(2)));

        System.out.println(com.compare("圆1", "圆2"));//运行时异常:ClassCastException
    }
}

使用泛型之后:

import java.util.Comparator;

class CircleComparator1 implements Comparator<Circle> {

    @Override
    public int compare(Circle o1, Circle o2) {
        //不再需要强制类型转换,代码更简洁
        return Double.compare(o1.getRadius(), o2.getRadius());
    }
}

//测试类
public class TestHasGeneric {
    public static void main(String[] args) {
        CircleComparator1 com = new CircleComparator1();
        System.out.println(com.compare(new Circle(1), new Circle(2)));

        //System.out.println(com.compare("圆1", "圆2"));
        //编译错误,因为"圆1", "圆2"不是Circle类型,是String类型,编译器提前报错,
        //而不是冒着风险在运行时再报错。
    }
}
2.2.2 练习

MyDate.jave

package exer1;

/**
 * ClassName:IntelliJ IDEA
 * Description:
 *      2、MyDate类包含:
 *      private成员变量year,month,day,并为每一个属性定义getter、setter方法
 * @Author zyjstart
 * @Create:2024/10/5 16:02
 */
public class MyDate {
    private int year;
    private int month;
    private int day;

    public MyDate() {
    }

    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 + "日";
    }
}

Employee.java

package exer1;

/**
 * ClassName:IntelliJ IDEA
 * Description:
 *      1、定义一个Employee类:
 *      该类包含:private成员变量name,age,birthday,其中birthday为MyDate类的对象:
 *      并为每一个属性定义getter,setter方法
 *      并重写toString方法输出name,age,birthday
 * @Author zyjstart
 * @Create:2024/10/5 16:00
 */
public class Employee implements Comparable<Employee>{
    private String name;
    private int age;
    private MyDate birthday;

    public Employee() {
    }

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

    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 MyDate getBirthday() {
        return birthday;
    }

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

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

    //按照name从高到低排序
    @Override
    public int compareTo(Employee o) {
        return this.name.compareTo(o.name);
    }
}

EmployeeTest.java

package exer1;

import org.junit.Test;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

/**
 * ClassName:IntelliJ IDEA
 * Description:
 *      3、创建该类的5个对象,并把这些对象放入TreeSet集合中(TreeSet 需使用泛型来定义)
 *
 *      4、分别按以下两种方式对集合中的元素进行排序,并遍历输出:
 *          1)、使Employee实现Comparable接口,并按name排序
 *          2)、创建TreeSet时传入Comparator对象,按生日日期的先后排序
 * @Author zyjstart
 * @Create:2024/10/5 16:05
 */
public class EmployeeTest {
    //1)、使Employee实现Comparable接口,并按name排序
    @Test
    public void test1(){
        TreeSet<Employee> set = new TreeSet<>();

        Employee e1 = new Employee("Hanmeimei",18,new MyDate(1998,12,16));
        Employee e2 = new Employee("Gaoqiqi",25,new MyDate(2002,11,19));
        Employee e3 = new Employee("Daleiju",34,new MyDate(1944,6,24));
        Employee e4 = new Employee("Zixianxina",17,new MyDate(1999,8,27));
        Employee e5 = new Employee("Yinana",37,new MyDate(2011,1,31));

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e5);

        //遍历
        Iterator<Employee> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }


    //2)、创建TreeSet时传入Comparator对象,按生日日期的先后排序
    @Test
    public void test2() {
        Comparator<Employee> comparator = new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                // 先比较年
                int yearDistince = o1.getBirthday().getYear() - o2.getBirthday().getYear();
                if (yearDistince != 0){ // 如果年份不相等,返回结果,相等,则判断月份
                    return yearDistince;
                }
                // 比较月
                int monthDistince = o1.getBirthday().getMonth() - o2.getBirthday().getMonth();
                if (monthDistince != 0){
                    return monthDistince;
                }

                return o1.getBirthday().getDay() - o2.getBirthday().getDay();

            }
        };
        TreeSet<Employee> set = new TreeSet<>(comparator);

        Employee e1 = new Employee("Hanmeimei",18,new MyDate(1999,12,16));
        Employee e2 = new Employee("Gaoqiqi",25,new MyDate(2002,11,19));
        Employee e3 = new Employee("Daleiju",34,new MyDate(1944,6,24));
        Employee e4 = new Employee("Zixianxina",17,new MyDate(1999,8,27));
        Employee e5 = new Employee("Yinana",37,new MyDate(2011,1,31));

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        set.add(e5);

        //遍历
        Iterator<Employee> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

在EmployeeTest.java中有两个测试方法,分别对应两个目标要求

test1按姓名排序,输出

test2按出生年月排序,输出

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Chromium 添加书签功能浅析c++

1、在点击添加书签时候此UI控制逻辑代码在 chrome\browser\ui\views\bookmarks\bookmark_bar_view.cc chrome\browser\ui\views\bookmarks\bookmark_bar_view.h 可以在此看到完成 移除 按钮逻辑&#xff0c;以及书签监听事件等。。。 // Implementation for BookmarkNodeAdd…

FastAdmin Apache下设置伪静态

FastAdmin Apache下设置伪静态 一、引言 FastAdmin 是一个基于ThinkPHP和Bootstrap框架开发的快速后台开发框架&#xff0c;它以其简洁、高效、易于扩展的特点&#xff0c;广受开发者的喜爱。在部署FastAdmin项目时&#xff0c;为了提高访问速度和用户体验&#xff0c;我们通…

VLAN:虚拟局域网

VLAN:虚拟局域网 交换机和路由器协同工作后&#xff0c;将原先的一个广播域&#xff0c;逻辑上&#xff0c;切分为多个广播域。 第一步:创建VLAN [SW1]dispaly vlan 查询vlan VID&#xff08;VLAN ID&#xff09;:用来区分和标定不同的vlan 由12位二进制构成 范围: 0-4…

[3D打印]拓竹切片软件Bambu Studio使用

Bambu Studio 界面功能 材料 不同材料 一般使用的是PLA, PETG, ABS PLA(57℃), PETG(66℃)的强度以及耐高温的能力比较差, ABS有味道, 不环保但是强度比较高(85℃) TPU: 不支持AMS, 数字小硬度小, 打印出来有亮光 TPE: 和上面一样, 打印出来是哑光的, 但是打印的难度比较…

物联网智能项目(含案例说明)

物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;智能项目是指利用物联网技术将各种物理设备、传感器、软件、网络等连接起来&#xff0c;实现设备之间的互联互通&#xff0c;并通过数据采集、传输、处理和分析&#xff0c;实现智能化管理和控制的项目。以…

Docker_速通_01

Docker Docker笔记连接相关概念如下安装运行命令 命令镜像容器run细节根据容器制作新镜像对正在运行容器的修改,保存为镜像保存成文件加载文件成镜像 分享镜像登录修改名字 docker tag推送镜像 目录挂载卷映射创建卷 容器之间直接访问查看容器细节容器内部互相访问自定义网络创…

[NeurIPS 2022] STaR: Bootstrapping Reasoning With Reasoning

Contents IntroductionMethodExperimentsReferences Introduction CoT 推理可以有效提升 LLM 推理能力&#xff0c;但 few-shot prompting 无法发挥 CoT 的全部潜力&#xff0c;训练能够生成中间推理步骤 (i.e., rationale) 的 LLM 又需要大量人工标注 rationale&#xff0c;为…

Python 从入门到实战35(进程-multiprocessing模块)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;可以熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了turtle库绘制图画操作的相关知识。今天学习一下…

anaconda创建环境无法定位到正确的Python解释器版本

一、概述 因为需要使用到torch其对Python的版本有些限制&#xff0c;我使用anacoda创建了Python版本3.8的环境&#xff0c;出现了一些问题&#xff0c;具体问题在下面进行分析。 二、具体分析 &#xff08;一&#xff09;问题概述 如图所示&#xff0c;在新创建的环境中&…

跟《经济学人》学英文:2024年10月05日这期 Dismantling Google is a terrible idea

Dismantling Google is a terrible idea Despite its appeal as a political rallying cry dismantling: &#xff08;枪支&#xff09;分解&#xff1b;解散&#xff1b;拆除&#xff1b;&#xff08;dismantle的现在分词&#xff09; appeal&#xff1a;吸引力 rallying …

Apollo9.0 Planning2.0决策规划算法代码详细解析 (5): OnLanePlanning::Init()

&#x1f31f; 面向自动驾驶规划算法工程师的专属指南 &#x1f31f; 欢迎来到《Apollo9.0 Planning2.0决策规划算法代码详细解析》专栏&#xff01;本专栏专为自动驾驶规划算法工程师量身打造&#xff0c;旨在通过深入剖析Apollo9.0开源自动驾驶软件栈中的Planning2.0模块&am…

nginx反向代理,负载均衡,HTTP配置简述(说人话)

文章目录 反向代理正向代理反向代理普通反向代理分析解释 四层反向代理 负载均衡HTTPS配置基本配置Nginx 账户认证功能 反向代理 正向代理 所谓的正向代理&#xff0c;通俗来说就是&#xff0c;正向代理是一个位于客户端和目标服务器之间的服务器&#xff0c;它代表客户端向目…

Python 工具库每日推荐 【NumPy】

文章目录 引言Python科学计算库的重要性今日推荐:NumPy工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:图像处理案例分析高级特性广播机制高级索引通用函数(ufunc)性能优化技巧扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeS…

哪个牌子充电宝好用性价比又高?推荐5款2024年性价比充电宝!

在充电宝的世界里&#xff0c;技术的进步日新月异&#xff0c;它们早已超越了简单的便携充电功能&#xff0c;成为了我们日常生活中不可或缺的移动电源。然而&#xff0c;随着市场的繁荣&#xff0c;选择一款可靠、安全的充电宝变得愈发困难。许多品牌为了降低成本&#xff0c;…

【EXCEL数据处理】000017 案例 Match和Index函数。

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000016 案例 Match和Index函数。使用的软件&#xff…

静态路由故障排查

1、开始 静态路由是否能够加入到全局路由表中并成功指导报文正确转发, 取决于其出接口状态与下一跳可达性&#xff0c;以及相关检测联动的状态等方面。因此静态路由定位故障的思路是: 首先查看全局路由表中是否有该静态路由&#xff1b;然后据此相应地检查出接口状态、下一跳可…

融媒体服务中PBO进行多重采样抗锯齿(MSAA)

如果不理解pbo 那先去了解概念&#xff0c;在此不再解释&#xff0c;这是我为了做融合服务器viewpointserver做的一部分工作&#xff0c;融合服务器的功能是将三维和流媒体&#xff0c;AI融合在一起&#xff0c;viewpointserver会直接读取三维工程的文件&#xff0c;同时融合rt…

MySQL基础之约束

MySQL基础之约束 概述 概念&#xff1a;约束是作用在字段的规则&#xff0c;限制表中数据 演示 # 多个约束之间不需要加逗号 # auto_increment 自增 create table user(id int primary key auto_increment comment 主键,name varchar(10) not null unique comment 姓名,age i…

表达式求值(可以计算两位数以上)

此程序可计算两位数以上的表达式 import java.util.Stack;public class ExpressionEvaluator {public int evaluate(String s) {Stack<Integer> numbers new Stack<>();Stack<Character> operators new Stack<>();int i 0;char c s.charAt(i);whil…