初识Java 10-3 集合

目录

 Collection和Iterator的对比

for-in和迭代器

总结图


本笔记参考自: 《On Java 中文版》


 Collection和Iterator的对比

        Collection是所有序列集合的共同根接口。因此,可以认为它是一个为表示其他接口之间的共性而出现的“附属接口”。

        java.util.AbstractCollection提供了一个Collection的默认实现,所以可以通过创建AbstractCollection的新子类来避免不必要的代码重复。这种接口存在的另一个理由是,通过面向接口的编程方式,我们的代码可以变得更加通用。一个实现了接口的方法也可以应用于任何的Collection类型。

    在Java中,实现Collection需要提供iterator()方法,这就将迭代器和集合捆绑起来了。

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.List;public class InterfaceVsIterator {public static void display(Iterator<Pet> it) {while (it.hasNext()) {Pet p = it.next();System.out.print(p.id() + ": " + p + " ");}System.out.println();}public static void display(Collection<Pet> pets) {for (Pet p : pets)System.out.print(p.id() + ": " + p + " ");System.out.println();}public static void main(String[] args) {List<Pet> petList = new PetCreator().list(8);Set<Pet> petSet = new HashSet<>(petList);Map<String, Pet> petMap = new LinkedHashMap<>();String[] names = ("拉尔夫, 埃里克, 罗宾, 蕾西, " + "布里特妮, 山姆, 斑点, 路威").split(", ");for (int i = 0; i < names.length; i++)petMap.put(names[i], petList.get(i));// Collectiondisplay(petList);display(petSet);// IteratorSystem.out.println();display(petList.iterator());display(petSet.iterator());System.out.println();System.out.println(petMap);System.out.println(petMap.keySet());display(petMap.values());display(petMap.values().iterator());}
}

        程序执行的结果是:

(笔者使用的是JDK 11,输出结果与《On Java》中有所出入。推测是因为哈希的实现有区别。)

        在上述程序中可以发现,Collection和Iterator都实现了解耦,display()方法不需要理解底层集合的特定实现。

        若要实现一个不是Collection的外部类,让其实现Collection接口可能会很麻烦或是复杂的,这时就会体现出Iterator的优势了。下面的例子将会继承AbstractCollection类:

import java.util.AbstractCollection;
import java.util.Iterator;public class CollectionSequence extends AbstractCollection {private Pet[] pets = new PetCreator().array(8); // 返回一个Pet[]数组@Overridepublic int size() { // 必须实现的接口方法size()return pets.length;}@Overridepublic Iterator<Pet> iterator() { // 必须自己提供iterator()方法return new Iterator<Pet>() { // Java的类型推断能力有限,所以这里还是需要标明类型private int index = 0;@Overridepublic boolean hasNext() {return index < pets.length;}@Overridepublic Pet next() {return pets[index++];}@Overridepublic void remove() { // remove是可选的实现,就算这里不进行实现也没有关系throw new UnsupportedOperationException();}};}public static void main(String[] args) {CollectionSequence c = new CollectionSequence();InterfaceVsIterator.display(c);InterfaceVsIterator.display(c.iterator());}
}

        程序执行的结果如下:

        这个例子实现了一个Collection,为此还提供了一个iterator()的实现。但这里我们就发现,与继承AbstractCollection类相比,只实现iterator()所需的工作并没有减少太多。另外,实现Collection还需要提供我们并不需要使用的其他方法的实现。

        所以,先继承,在添加创建迭代器的能力,这样会比较轻松:

    生成一个Iterator,是将序列与处理序列的方法连接起来的耦合性最低的方法。与Collection相比,这种做法对序列类的约束会少的多。

for-in和迭代器

        for-in语法可以配合任何Collection对象使用:

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;public class ForInCollections {public static void main(String[] args) {Collection<String> cs = new LinkedList<>();Collections.addAll(cs, "不吃葡萄倒吐葡萄皮".split(""));for (String s : cs)System.out.print("'" + s + "'");System.out.println();}
}

        程序执行的结果如下:

        for-in语句之所以能这么做,其原理是因为Java 5引入了一个叫做Iterable的接口,这个接口包含的iterator()方法会生成一个Iteratorfor-in使用这个Iterable接口遍历序列。

        举一反三,若我们创建了一个实现了Iterable接口的类,那么这个类也就可以被用于for-in语句中:

import java.util.Iterator;public class IterableClass implements Iterable<String> {protected String[] words = ("扁担没有板凳宽,板凳没有扁担长".split(""));@Overridepublic Iterator<String> iterator() {return new Iterator<String>() {private int index = 0;@Overridepublic boolean hasNext() {return index < words.length;}@Overridepublic String next() {return words[index++];}@Overridepublic void remove() {throw new UnsupportedOperationException();}};}public static void main(String[] args) {for (String s : new IterableClass())System.out.print(s + " ");System.out.println();}
}

        程序执行的结果如下:

        for-in语句可以配合数组或实现了Iterable接口的类进行使用,但这并不是说数组也自动实现了Iterable,也并不存在任何装箱操作:

import java.util.Arrays;public class ArrayIsNotIterable {static <T> void test(Iterable<T> ib) {for (T t : ib)System.out.print(t + " ");System.out.println();}public static void main(String[] args) {test(Arrays.asList(1, 2, 3));String[] strings = { "A", "B", "C" };// 数组可以配合for-in进行使用// 但并没有实现Iterable接口,因此无法作为参数传入test()// test(strings);// 必须将strings显式地转换为Iterable:test(Arrays.asList(strings));}
}

        程序执行的结果如下:

适配器方法惯用法

        当我们需要以不止一种方式将类用在for-in语句时,继承就不能很好地满足我们了。此时,我们需要做的是提供一个满足for-in语句要求的特定接口。比如:默认的迭代器是向前的,若我们还需要进行向后的迭代,那么一个好的方法就是添加一个生成Iterable对象的方法:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;class ReversibleArrayList<T> extends ArrayList<T> {ReversibleArrayList(Collection<T> c) {super(c);}public Iterable<T> reversed() { // 添加一个迭代器return new Iterable<T>() {public Iterator<T> iterator() {return new Iterator<T>() {int current = size() - 1;@Overridepublic boolean hasNext() {return current > -1;}@Overridepublic T next() {return get(current--);}@Overridepublic void remove() { // 未实现throw new UnsupportedOperationException();}};}};}
}public class AdapterMethodIdiom {public static void main(String[] args) {ReversibleArrayList<String> ral = new ReversibleArrayList<>(Arrays.asList("To be continued".split(" ")));// 通过iterator()获得原始的迭代器for (String s : ral)System.out.print(s + " ");System.out.println();// 使用自建的迭代器for (String s : ral.reversed())System.out.print(s + " ");System.out.println();}
}

        程序执行的结果是:

        在main(),可以看见调用ralral.reversed()产生的是不同的行为。

        另外,迭代器也可以通过使用其他类来实现:

        上述这个类将会返回一个被打乱的Iterator

        最后再提一下Arrays.asList(),这个方法会返回一个包装过的ArrayList。若将包装后的ArrayList传递给Collections.shuffle(),那么原始数组不会受到影响。但若直接将Arrays.asList()生成的List打乱顺序,那么shuffle()方法会改变底层数组:

import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;public class ModifyingArraysAsList {public static void main(String[] args) {Random rand = new Random(47);Integer[] ia = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };List<Integer> list1 = new ArrayList<>(Arrays.asList(ia)); // System.out.println("在乱序之前:" + list1);Collections.shuffle(list1, rand);System.out.println("在乱序之后:" + list1);System.out.println("数组本身:" + Arrays.toString(ia));System.out.println();List<Integer> list2 = Arrays.asList(ia);System.out.println("在乱序之前:" + list2);Collections.shuffle(list2, rand);System.out.println("在乱序之后:" + list2);System.out.println("数组本身:" + Arrays.toString(ia));}
}

        程序执行的结果如下:

        注意:Arrays.asList()产生的List对象,会将原本的底层数组作为其物理实现。所以,若需要修改List,最好将其复制到另一个集合中。

总结图

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

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

相关文章

Git大全

目录 一、Git概述 1.1Git简介 1.2Git工作流程图 1.3查看Git的版本 1.4 Git 使用前配置 1.5为常用指令配置别名&#xff08;可选&#xff09; 1.5.1打开用户目录&#xff0c;创建 .bashrc 文件 1.5.2在 .bashrc 文件中输入如下内容&#xff1a; 1.5.3打开gitBash&#xff0c;执行…

C++:类中的静态成员函数以及静态成员变量

一、静态成员变量 静态成员&#xff1a;在类定义中&#xff0c;它的成员&#xff08;包括成员变量和成员函数&#xff09;&#xff0c;这些成员可以用关键字static声明为静态的&#xff0c;称为静态成员。 静态成员变量需要在类外分配空间&#xff0c;static 成员变量是在初始…

【解决方案】edge浏览器批量添加到集锦功能消失的解决方案

edge的集锦功能很好用&#xff0c;右键标签页会出现如下选项&#xff1a; 但在某次edge更新后&#xff0c;右键标签页不再出现该选项&#xff1a; 这里可以参考为什么我的Edge浏览器右键标签页没有“将所有标签页添加到集锦”功能&#xff1f; - Microsoft Community 一文提出…

pcl--第十节 点云曲面重建

曲面重建技术在逆向工程、数据可视化、机器视觉、虚拟现实、医疗技术等领域中得到了广泛的应用 。 例如&#xff0c;在汽车、航空等工业领域中&#xff0c;复杂外形产品的设计仍需要根据手工模型&#xff0c;采用逆向工程的手段建立产品的数字化模型&#xff0c;根据测量数据建…

超级好用绘图工具(Draw.io+Github)

超级好用绘图工具&#xff08;Draw.ioGithub&#xff09; 方案简介 绘图工具&#xff1a;Draw.io 存储方式&#xff1a; Github 1 Draw.io 1.2 简介 ​ 是一款免费开源的在线流程图绘制软件&#xff0c;可以用于创建流程图、组织结构图、网络图、UML图等各种类型的图表。…

windows server 2019 、2012等服务器查看系统和应用程序日志

查看windows系统日志 点击左下角的windows按钮&#xff0c;输入事件两个字&#xff0c;会显示时间查看器 点击事件查看器&#xff0c;windows日志下面可以卡到系统日志和应用程序的日志 筛选时间范围内的日志 修改记录时间 选组自定义范围 选择事件事件 输入事件范围&#xff…

C语言大佬的必杀技---宏的高级用法

C语言大佬的必杀技—宏的高级用法 目录: 字符串化标记的拼接宏的嵌套替换多条语句防止一个文件被重复包含宏和函数的区别 可能大家在学习的时候用得比较少&#xff0c;但是在一些代码量比较大的时候&#xff0c;这样使用&#xff0c;可以大大的提高代码的可读性&#xff0c;…

从零开始:新手快速在国产操作系统中搭建高可用K8S(V1.28)集群落地实践

微信改版了&#xff0c;现在看到我们全凭缘分&#xff0c;为了不错过【全栈工程师修炼指南】重要内容及福利&#xff0c;大家记得按照上方步骤设置「接收文章推送」哦~ 关注【公众号】回复【学习交流群】加入【SecDevOps】学习交流群! 文章目录&#xff1a; 本文为作者原创文章…

day03_基础语法

今日内容 零、复习昨日 一、Idea安装&#xff0c;配置 二、Idea使用 三、输出语句 四、变量 五、数据类型 附录: 单词 零、 复习昨日 1 装软件(typora,思维导图) 2 gpt(学会让他帮你解决问题) 3 java发展(常识) 4 HelloWorld程序 5 编码规范 6 安装jdk,配置环境变量 电脑常识 任…

STM32-无人机-电机-定时器基础知识与PWM输出原理

电机控制基础——定时器基础知识与PWM输出原理 - 掘金单片机开发中&#xff0c;电机的控制与定时器有着密不可分的关系&#xff0c;无论是直流电机&#xff0c;步进电机还是舵机&#xff0c;都会用到定时器&#xff0c;比如最常用的有刷直流电机&#xff0c;会使用定时器产生PW…

在GIS(地理信息系统)中,常见的地理文件记录

在GIS&#xff08;地理信息系统&#xff09;中&#xff0c;常见的地理文件包括以下几种&#xff1a; .cpg&#xff08;Code Page文件&#xff09;&#xff1a;这个文件是指定地理数据文件编码的文件&#xff0c;它告诉软件如何正确地读取和解释地理数据文件中的字符编码。比如…

海外代理IP是什么?如何使用?

一、海外代理IP是什么&#xff1f; 首先&#xff0c;代理服务器是在用户和互联网之间提供网关的系统或路由器。它是一个服务器&#xff0c;被称为“中介”&#xff0c;因为它位于最终用户和他们在线访问的网页之间。 海外IP代理是就是指从海外地区获取的IP地址&#xff0c;用…

Linux学习-HIS系统部署(1)

Git安装 #安装中文支持&#xff08;选做&#xff09; [rootProgramer ~]# echo $LANG #查看当前系统语言及编码 en_US.UTF-8 [rootProgramer ~]# yum -y install langpacks-zh_CN.noarch #安装中文支持 [rootProgramer ~]# vim /etc/locale.co…

差值结构的顺序偏好

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由5张二值化的图片组成&#xff0c;让A 中有5个点&#xff0c;B中有1个点&#xff0c;且不重合&#xff0c;统计迭代次数并排序。 第一种情况 差值结构 迭代次数 L E - - 2 10491.…

python随手小练1

题目&#xff1a; 使用python做一个简单的英雄联盟商城登录界面 具体操作&#xff1a; print("英雄联盟商城登录界面") print("~ * "*15 "~") #找其规律 a "1、用户登录" b "2、新用户注册" c "3、退出系统&quo…

手动部署 OceanBase 集群

手动部署一个 OB 单副本集群&#xff0c;包括一个 OBProxy 节点 部署环境 服务器信息 IP地址 192.168.0.26 网卡名 ifcfg-enp1s0 OS Kylin Linux Advanced Server release V10 CPU 8C 内存 32G 磁盘1 本地盘 /data/1 磁盘2 本地盘 /data/log1 机器和角色划分 …

es小记(copy_to)

简单创建索引复制字段 1: 3个主分片,各自有一个副本,总分片数为 3*26; refresh_interval为刷新频率; 其他参数描述,转载自 PUT test1 { “settings”:{ “number_of_shards”: 1, “number_of_replicas”: 1, “refresh_interval”: “30s” }, “mappings”:{ “properties”…

软件工程知识总结梳理

&#x1f525;&#x1f525;宏夏Coding网站&#xff0c;致力于为编程学习者、互联网求职者提供最需要的内容&#xff01;网站内容包括求职秘籍&#xff0c;葵花宝典&#xff08;学习笔记&#xff09;&#xff0c;资源推荐等内容。在线阅读&#xff1a;https://hongxiac.com&…

ubuntu20.04 安装 pyconcorde

这个包似乎对网络环境要求挺高的&#xff0c;我们直接弄个 射线A型号 的飞机 直接使用 pip install pyconcorde 安装&#xff0c;发现在使用里面的包时会报奇怪的错误&#xff0c;于是决定寻找 github 上的 pyconcorde 源码&#xff0c;看文档进行安装 github 地址&#xff1…

计算π的近似值分数 ——python

利用格里高利公式&#xff1a; 计算 的近似值&#xff0c;直到最后一项的绝对值小于给定精度eps。 输入格式: 输入小于1且大于0的阈值。 输出格式: 输出满足阈值条件的近似圆周率&#xff0c;输出到小数点后6位。 输入样例: 在这里给出一组输入。例如&#xff1a; 0.0…