Java进阶-集合(3)与泛型

news2025/2/24 12:37:21

这次介绍集合中的Iterator迭代器,以及泛型。简单来说,泛型对集合的元素类型进行了限制,使用泛型可以在编译时检查类型安全,提高代码的重用率。内容如下
在这里插入图片描述

一、Iterator迭代器

1、概念

Iterator迭代器是一个接口,作用是遍历容器的所有元素,也是 Java 集合框架的成员。

注:与 Collection 和 Map 系列的集合不同,Collection 和 Map 系列集合主要用于盛装其他对象,而 Iterator 则主要用于遍历Collection 集合中的元素。

2、Iterator接口定义的方法

可通过在IDEA中选中Iterator,ctrl+B查看源码的方式查看对应方法。

boolean hasNext():如果被迭代的集合元素还没有被遍历完,则返回 true。

next():返回集合里的下一个元素。返回类型为Object(可能涉及强转)

void remove():删除集合里上一次 next 方法返回的元素。

void forEachRemaining(Consumer action):这是 Java 8 为 Iterator 新增的默认方法,该方法可使用 Lambda 表达式来遍历集合元素。

3、案例

3.1 Iterator遍历集合
import java.util.Collection; //导包
import java.util.HashSet;
import java.util.Iterator;

public class IteratorTest {
    public static void main(String[] args){
        Collection col=new HashSet(); //向上转型,把子类对象直接赋给父类引用(不用强转)
        col.add("zhangsan"); //添加元素
        col.add("lishi");
        col.add("wangwu");
        for(Object i:col){ //使用forEach()方法遍历集合
            System.out.println(i);
        }
        System.out.println("--------");
        Iterator it=col.iterator(); //获取迭代器遍历集合
        while (it.hasNext()){ //it.next()方法返回的数据类型是Object类型(需要强转)
            String coll=(String) it.next();
            //不强转直接用it.next()也能遍历出结果,但不能进行下一步的比较移除操作,规范类型,养成好的习惯很重要
            System.out.println(coll);
            if (coll.equals("zhangsan")){ //字符串比较
                it.remove(); //从集合中删除上一次next()方法返回的元素
            }
            coll="zhaoliu"; //对coll变量赋值,不会改变集合元素本身
        }
        System.out.println(col); //打印集合
    }
}

运行结果

lishi
zhangsan
wangwu
--------
lishi
zhangsan
wangwu
[lishi, wangwu]

注:上面程序中对迭代变量 coll赋值,但当再次输岀 col 集合时,集合里的元素不变。所以当使用 Iterator 对集合元素进行迭代时,Iterator 并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量的值对集合元素本身没有任何影响

3.2 要点总结

1)Iterator 仅用于遍历集合,如果需要创建 Iterator 对象,则必须有一个被迭代的集合,否则Iterator 没有存在的价值。
2)Iterator 必须依附于 Collection 对象,若有一个 Iterator 对象,则必然有一个与之关联的 Collection 对象。(与上同理)
3)Iterator 提供了两个方法来迭代访问 Collection 集合里的元素,Collection 集合里的元素不能被改变,只有通过 Iterator 的 remove() 方法删除上一次 next() 方法返回的集合元素才可以,否则将会引发“java.util.ConcurrentModificationException”异常。

3.3 示例
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class IteratorTest {
    public static void main(String[] args){
        Collection col=new HashSet(); //向上转型,把子类对象直接赋给父类引用(不用强转)
        col.add("zhangsan"); //添加元素
        col.add("lishi");
        col.add("wangwu");
        Iterator it=col.iterator(); //获取迭代器遍历集合
        while (it.hasNext()){ //it.next()方法返回的数据类型是Object类型(需要强转)
            String coll=(String) it.next();
            //不强转直接用it.next()也能遍历出结果,但不能进行下一步的比较移除操作,规范类型,养成好的习惯很重要
            System.out.println(coll);
            if (coll.equals("zhangsan")){ //字符串比较
                //使用Iterator迭代过程中,不可修改集合元素,下面代码引发异常
                col.remove(coll);
            }
        }
    }
}

运行结果

lishi
zhangsan
Exception in thread "main" java.util.ConcurrentModificationException
    at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1510)
    at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1533)
    at test3.IteratorTest.main(IteratorTest.java:15)

4、Iterator错误检查机制

4.1 概述

Iterator 迭代器采用的是快速失败(fail-fast)机制一旦在迭代过程中检测到该集合已经被修改(通常是程序中的其他线程修改),程序立即引发 ConcurrentModificationException 异常,而不是显示修改后的结果,这样可以避免共享资源而引发的潜在问题

注:快速失败(fail-fast)机制,是 Java Collection 集合中的一种错误检测机制。

用户可以自行验证,当3.3 示例中改为删除“wangwu”字符串即将上面的coll.equals(“zhangsan”)改为coll.equals(“wangwu”)时,则不会引发异常,因为王五是最后添加的,相当于所有都迭代完成后才删除,故不会引发ConcurrentModificationException 异常。

总结:所以说尽量不要在迭代时删除集合元素,防止引发异常。

二、泛型

1、集合的设计角度

把集合看成容器,将对象“丢进”集合,集合不会记住对象的数据类型(即丢失了对象的状态信息),再次取出时,对象的编译类型变为Object(运行时类型不变)

1.1 优点

具有很好的通用性,能保存任何类型的对象(因为Object类是所有类的父类,即创建对象时都能向上转型,不用强转)

1.2 问题(若无泛型)

1)集合对元素类型没有任何限制,如想创建一个只保存 Dog 对象的集合,但程序也可以轻易地将 Cat 对象“丢”进去,可能引发异常。
2)把对象“丢进”集合时,集合丢失了对象的状态信息,只知道它盛装的是 Object,因此取出集合元素后通常还需要进行强制类型转换。(这样既增加了编程的复杂度,也可能引发 ClassCastException即类型转换异常)

1.3 解决

为了解决上述问题,从 Java 1.5 开始提供了泛型。

2、泛型

2.1 几点注意

1)抽象地说,泛型是一种“代码模板”,可以用一套代码套用各种类型(泛型编程)
2)具体而言,泛型本质上是提供类型的“类型参数”(参数化类型)。可以为类、接口或方法指定一个类型参数,通过这个参数限制操作的数据类型,从而保证类型转换的绝对安全。

泛型可以在编译时检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。

3、泛型集合

示例:结合泛型与集合编写一个案例实现图书信息输出
1)创建一个Book类(图书编号、图书名称、价格)

public class Book { // 定义Book类 (完整javabean)
    private  int id; // 封装成员变量
    private String name;
    private int price;

    public Book(){ // 无参构造方法
    }
    public Book(int id,String name,int price){ // 带全部参数的构造方法
        this.id=id;  // this指向当前变量
        this.name=name;
        this.price=price;
    }
    public String toString(){ //重写父类(Object类)的toString()方法,返回对象的字符串表示
        return this.id+" "+this.name+" "+this.price;
    }
    public int getId() { // 提供get和set方法,习惯,虽然这里用不到
        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 getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
}

2)使用 Book 作为类型创建 Map 和 List 两个泛型集合,然后向集合中添加图书元素,最后输出集合中的内容

import java.util.ArrayList; //导包
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BookTest { // 创建集合测试类
    public static void main(String[] args){
        Book book1=new Book(1,"唐诗三百首",18); // 创建对象并实例化
        Book book2 = new Book(2, "小星星", 12);
        Book book3 = new Book(3, "成语大全", 22);
        Map<Integer,Book> books=new HashMap<>(); // 创建泛型的Map集合
        //定义Interger类型的键,Book类型对象整体作为值,通过get()方法得到键对应的值打印输出即为全部图书信息
        books.put(1001,book1);  // 将Book对象存储到Map中
        books.put(1002, book2);
        books.put(1003, book3);
        System.out.println("泛型Map存储的图书信息如下:");
        for (Integer id : books.keySet()) {  // for-each循环 遍历键
            System.out.print(id + "——"); //获取键
            System.out.println(books.get(id)); //获取值(Book对象整体,即为全部图书信息)
            //不需要将books.get(id)获取的值强制转换为Book类型,程序会隐式转换(泛型功能)
        }
        List<Book> bookList = new ArrayList<>(); // 定义泛型的List集合
        bookList.add(book1); //添加book对象元素
        bookList.add(book2);
        bookList.add(book3);
        System.out.println("泛型List存储的图书信息如下:");
        for (int i = 0; i < bookList.size(); i++) { //for循环遍历输出
            System.out.println(bookList.get(i)); //get()方法得到索引对应的元素
            //不需要将bookList.get(i)强制转换为Book类型,程序会隐式转换(泛型功能)
        }
    }
}

运行结果

泛型Map存储的图书信息如下:
1001——1 唐诗三百首 18
1002——2 小星星 12
1003——3 成语大全 22
泛型List存储的图书信息如下:
1 唐诗三百首 18
2 小星星 12
3 成语大全 22

4、泛型类

4.1 几点注意

public class class_name<data_type1,data_type2,…>{}:data_type为类型参数(Java 泛型支持声明一个以上的类型参数,逗号隔开)。属性声明:如private data_type1 property_name1;

一般用于类中的属性类型不确定的情况下

在实例化泛型类时,需要指明泛型类中的类型参数,并赋予泛型类属性相应类型的值。

4.2 示例

创建一个学生的泛型类,包含姓名、年龄和性别3个属性
1)创建一个学生的泛型类

public class Stu<N,A,S> { //定义学生泛型类
    private N name; //封装成员变量
    private A age;
    private S sex;
    public Stu(){ //无参构造方法
    }
    public Stu(N name,A age,S sex){ //带全部参数的构造方法
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    public String toString(){ //toString()方法返回对象的字符串表示
        return this.name+" "+this.age+" "+this.sex;
    }
    public N getName() { //提供整套get和set方法
        return name;
    }
    public void setName(N name) {
        this.name = name;
    }
    public A getAge() {
        return age;
    }
    public void setAge(A age) {
        this.age = age;
    }
    public S getSex() {
        return sex;
    }
    public void setSex(S sex) {
        this.sex = sex;
    }
}

2)创建测试类

public class StuTest { // 创建学生泛型类的测试类
    public static void main(String[] args){
        // 实例化泛型对象,直接在类后面加上限定泛型类的类型参数
        Stu<String,Integer,Character> s=new Stu<>("zhangsan",20,'男');
        String name=s.getName(); //调用get方法
        Integer age=s.getAge();
        Character sex=s.getSex();
        //以上获取时不用类型转换,程序隐式地将Object类型的数据转换为相应的数据类型
        System.out.println("----------学生信息----------");
        System.out.println("学生姓名:"+name+" 年龄:"+age+" 性别:"+sex);
    }
}

5、泛型方法

5.1 注意与说明

泛型可以在类中包含参数化的方法,而方法所在的类可以是泛型类,也可以不是泛型类(即是否拥有泛型方法,与其所在的类是不是泛型没有关系)。

泛型方法使得该方法能够独立于类而产生变化。如果使用泛型方法可以取代类泛型化,那么就应该只使用泛型方法。

一个 static 方法无法访问泛型类的类型参数。因此,如果 static 方法需要使用泛型能力,就必须使其成为泛型方法。

格式:[访问权限修饰符] [static] [final] <类型参数列表> 返回值类型 方法名([形式参数列表]),如

如:public static <T> List find(Class<T> cs,int userId){}

一般来说编写 Java 泛型方法,其返回值类型至少有一个参数类型是泛型,且类型应该是一致的,如果只有返回值类型或参数类型之一使用了泛型,那么这个泛型方法的使用就被限制了。

5.2 示例

使用泛型方法打印图书信息。定义泛型方法,参数类型使用“T”来代替。

// 1) 定义一个Book类,代码同3、泛型集合示例第一个
// 2) 定义Book泛型方法的测试类
public class BookDemo { //创建book泛型方法的实现类
    public static <T> void List(T book){ //定义泛型方法,T为参数类型
        if(book!=null){ //若不为空,输出图书信息
            System.out.println(book);
        }
    }
    public static void main(String[] args){
        //实例化Book对象
        Book b=new Book(1,"java编程",20);
        List(b); //调用List泛型方法
    }
}
//result
//1 java编程 20

6、泛型高级用法

除在集合、类和方法中使用,泛型还有如下高级用法

6.1 限制泛型可用类型

语法:class 类名称,anyClass指某个接口或类,使用泛型限制后,泛型类的类型必须实现或继承 anyClass 这个接口或类,且在进行泛型限制时必须使用 extends 关键字(否则默认是Object类型,即其所有子类都可以实例化泛型类对象,这样就没有意义了)

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
// 限制ListClass的泛型类型必须实现List接口
public class ListClass <T extends List>{
    public static void main(String[] args) {
        // 实例化使用ArrayList的泛型类ListClass,正确
        ListClass<ArrayList> lc1 = new ListClass<ArrayList>();
        // 实例化使用LinkedList的泛型类LlstClass,正确
        ListClass<LinkedList> lc2 = new ListClass<LinkedList>();
        // 实例化使用HashMap的泛型类ListClass,错误,因为HasMap没有实现List接口
        // ListClass<HashMap> lc3=new ListClass<HashMap>();
    }
}
6.2 使用类型通配符<?>

类型通配符作用

在创建一个泛型类对象时限制这个泛型类的类型必须实现或继承某个接口或类。

list<?>

表示元素类型未知的list,其元素可以匹配任何的类型。表示它是各种泛型list的父类,并不能把元素添加到其中

类型通配符上限:<? extends 类型>

  • List<? extends Number>:表示的类型是Number或其子类型

类型通配符下限:<?super 类型>

  • List<? super Number>:表示的类型是Number或其父类型

语法

泛型类名称<? extends List>a = null;

A<? extends List>a = null;
a = new A<ArrayList> ();    // 正确
b = new A<LinkedList> ();    // 正确
// 错误 HashMap类没有实现List接口

继承泛型类和实现泛型接口

//继承泛型类
public class FatherClass<T1>{}
public class SonClass<T1,T2,T3> extents FatherClass<T1>{}
//在泛型中实现接口
interface interface1<T1>{}
interface SubClass<T1,T2,T3> implements
Interface1<T2>{}

扩展:
可变参数(即参数个数可变)

格式:修饰符 返回值类型 方法名(数据类型…变量名){}

范例

public static int sum(int…a){}

注意

这里的变量其实是一个数组。

如果一个方法有多个参数,包含可变参数,可变参数要放在后面。

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

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

相关文章

MATLAB环境下脑电信号EEG的谱分析

脑电信号一直伴随着人类的生命&#xff0c;脑电波是脑神经细胞发生新陈代谢、离子交换时细胞群兴奋突触电位总和&#xff0c;脑电信号的节律性则和丘脑相关&#xff0c;含有丰富的大脑活动信息。通常我们所接触的脑电图都是头皮脑电图&#xff0c;在有些特殊场合还需要皮下部位…

TikTok网络相关问题详解来了,附原生住宅代理IP供应商推荐,

想要迈过TikTok新手门槛&#xff0c;首先必须要学习的就是网络问题。很多人开始做TikTok账号或者TikTok小店时&#xff0c;都会遇到一些先前没有遇到的词汇和概念&#xff0c;比如原生IP&#xff0c;独享IP&#xff0c;甚至专线&#xff0c;那么一个IP可以做几个账号呢&#xf…

0粉低成本带货!职人号矩阵正成为商家的香饽饽

近年来&#xff0c;中国消费市场变化不断&#xff0c;线上消费持续上涨&#xff0c;线上线下一体化成为零售行业的发展新趋势。 加上抖音等平台都在大力发展本地生活&#xff0c;众多连锁商家、本地商家、百货商场纷纷加快数字化转型步伐&#xff0c;掘金线上海量流量&#xff…

机器学习:原理、应用与未来展望

第一章 是什么 机器学习&#xff08;Machine Learning&#xff09;是一门跨学科的学科&#xff0c;它使用计算机模拟或实现人类学习行为&#xff0c;通过不断地获取新的知识和技能&#xff0c;重新组织已有的知识结构&#xff0c;从而提高自身的性能。机器学习涉及多个学科&am…

HGAME 2024 WEEK4 WP

文章目录 IOTez7621 MISCezKeyboardMaybezip**Mondrians &#x1f511; REchange webReverse and Escalation. 想念21和22年的平台和week4的 6557225了 IOT ez7621 拿到固件直接binwalk解&#xff0c;之后grep出hgame 在usr/lib/opkg/info/kmod-flag.control找到这个&#x…

Quartz 任务调度框架源码阅读解析

概念: quartz 是一个基于JAVA的定时任务调度框架 案例: <dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.0</version></dependency>JobDetail job JobBuilder.newJob(Sc…

TP6上传图片到OSS(记录贴)

1&#xff0c;先安装&#xff0c;我使用composer安装 在项目的根目录运行composer require aliyuncs/oss-sdk-php 2,安装成功以后vendor目录下可以看到如图&#xff1a; 3&#xff0c;上传图片代码如下&#xff1a; <?php namespace app\controller;use app\BaseControll…

宝塔FTP服务设置并结合cpolar内网穿透实现远程传输文件

文章目录 1. Linux安装Cpolar2. 创建FTP公网地址3. 宝塔FTP服务设置4. FTP服务远程连接小结 5. 固定FTP公网地址6. 固定FTP地址连接 宝塔FTP是宝塔面板中的一项功能&#xff0c;用于设置和管理FTP服务。通过宝塔FTP&#xff0c;用户可以创建FTP账号&#xff0c;配置FTP用户权限…

D*算法超详解 (D星算法 / Dynamic A*算法/ Dstar算法)(死循环解决--跟其他资料不一样奥)

所需先验知识&#xff08;没有先验知识可能会有大碍&#xff0c;了解的话会对D*的理解有帮助&#xff09;&#xff1a;A*算法/ Dijkstra算法 何为D*算法 Dijkstra算法是无启发的寻找图中两节点的最短连接路径的算法&#xff0c;A*算法则是在Dijkstra算法的基础上加入了启发函数…

数据抽取平台pydatax介绍--实现和项目使用

数据抽取平台pydatax实现过程中&#xff0c;有2个关键点&#xff1a; 1、是否能在python3中调用执行datax任务&#xff0c;自己测试了一下可以&#xff0c;代码如下&#xff1a; 这个str1就是配置的shell文件 try:result os.popen(str1).read() except Exception as …

吴恩达机器学习全课程笔记第四篇

目录 前言 P61-P68 激活函数 Softmax算法 P69-P73 Adam算法 更多类型的层 模型评估 P74-P79 偏差和方差 建立表现基准 学习曲线 偏差和方差与神经网络 前言 这是吴恩达机器学习笔记的第四篇&#xff0c;第三篇笔记请见&#xff1a; 吴恩达机器学习全课程笔记第…

ubuntu20.04 ROS-Noetic 配置qtcreator的ROS环境

文章目录 1 安装qtcreator1.1 下载安装Qt1.2 配置命令启动qtcreator2 配置ROS2.1 直接安装qtcreator-ros2.2 在qtcreator上安装ros_qtc_plugin插件3 注意3.1 构建套件3.2 更新、删除qt4 参考链接1 安装qtcreator QT官网:Qt Downloads 下载包链接:qt5.12.12 Qt5.12.12默认qtc…

如何系统性的学习推荐系统?

推荐一本适合推荐系统、计算广告、个性化搜索领域的从业人员阅读的书&#xff1a;《互联网大厂推荐算法实战》。快手公司算法专家10余年的实战经验总结。涵盖一线互联网公司当前采用的主流推荐算法&#xff0c;凸显可用性、实用性提供从算法基本原理&#xff0c;到技术框架再到…

0代码自动化测试:RF 框架实现企业级 UI 自动化测试!

RobotFramework框架可以作为公司要做自动化 但是又不会代码的一种临时和紧急情况的替代方案&#xff0c;上手简单。 前言 现在大家去找工作&#xff0c;反馈回来的基本上自动化测试都是刚需&#xff01;没有自动化测试技能&#xff0c;纯手工测试基本没有什么市场。 但是很多人…

qml 项目依赖

文章目录 出现的问题最终对比下一步 把 apptestQml3_6.exe 放到一个单独目录下&#xff0c;执行 windeployqt.exe ./apptestQml3_6.exe但是出了很多问题&#xff0c;根本运行不起来。 但是在release目录下执行下&#xff0c;程序能跑起来。 根据错误提示&#xff0c;进行添加。…

浮点数二分(一个数开根号)

#include<iostream> using namespace std; int main(){double x;cin>>x;double l0,rx;while(r-l>1e-8){double mid(lr)/2;if(mid*mid>x)rmid;else lmid;}cout<<l<<endl;return 0; }

IJCAI 2023 |时空数据(Spatial-Temporal)论文

本次IJCAI 2023共收到4566份投稿&#xff0c;接收率大约15%&#xff0c;本文总结了IJCAI 2023有关时空数据&#xff08;spatial-temporal&#xff09;的论文。 时空数据Topic:轨迹异常检测&#xff0c;时空预测&#xff0c;信控优化等。 目录 Open Anomalous Trajectory Reco…

大学生课程|统计基础与python分析8|员工离职预测模型(免费下载所有课程材料)

此系列为基础学习系列&#xff0c;请自行学习&#xff0c;课程资源免费获取地址&#xff1a; https://download.csdn.net/download/weixin_68126662/88866689 久菜盒子工作室&#xff1a;大数据科学团队/全网可搜索的久菜盒子工作室 我们是&#xff1a;985硕博/美国全奖doctor/…

深度学习500问——Chapter02:机器学习基础(1)

文章目录 前言 2.1 基本概念 2.1.1 大话理解机器学习本质 2.1.2 什么是神经网络 2.1.3 各种常见算法图示 2.1.4 计算图的导数计算 2.1.5 理解局部最优与全局最优 2.1.5 大数据与深度学习之间的关系 2.2 机器学习学习方式 2.2.1 监督学习 2.2.2 非监督式学习 2.2.3 …

Maven【3】( 依赖的范围,传递性和依赖的排除)(命令行操作)

文章目录 【1】依赖的范围结论验证①验证 compile 范围对 main 目录有效②验证test范围对main目录无效③验证test和provided范围不参与服务器部署 【2】依赖的传递性①compile 范围&#xff1a;可以传递②test 或 provided 范围&#xff1a;不能传递 【3】依赖的排除 【1】依赖…