java8 迭代set集合_JavaSE(八)集合之Set

2.2、HashSet特点

不能保证元素的排列顺序,顺序可能和添加的顺序不同,顺序也有可能发生变化。

HashSetf不是同步的,如果多个线程同时来访问一个 HashSet,假设有两个或者两个以上线程同时修改了HashSet 集合时,则必须通过代码来保证其同步。

集合元素值可以是 null。

2.3、HashSet如何保证元素唯一性的原理

当我们想要创建一个集合,该集合里面的元素都具有唯一性时。会遇到两种情况:

1)元素为String类型,可以直接用Hashset集合来创建

2)String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉,只留下一个。

思路图:

75b68f2544a9aa25e1fbc651cfccb87c.png

3)HashSet保证元素唯一性的原理

我们使用Set集合都是需要去掉重复元素的,如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数

当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象

如果没有哈希值相同的对象就直接存入集合

如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存。

4)将自定义类的对象存入HashSet去重复

类中必须重写hashCode()和equals()方法

hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)

equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储。

在开发中并不要我们去写,比如使用eclipse开发中,在类上面 Alt+Shift+s ,再点h,就能生成相对应的重写的hashCode()和equls()方法了。那我们就来分析一下,该怎么写的。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

/*注意:这里是一个Student类:里面有name和age属性。

* 为什么是31?

* 1,31是一个质数,质数是能被1和自己本身整除的数

* 2,31这个数既不大也不小

* 3,31这个数好算,2的五次方-1,2向左移动5位*/@Overridepublic inthashCode() {

finalint prime = 31;int result = 1;

result= prime * result +age;

result= prime * result + ((name == null) ? 0: name.hashCode());returnresult;

}

@Overridepublicboolean equals(Object obj) {if (this == obj) //调用的对象和传入的对象是同一个对象

return true; //直接返回true

if (obj == null) //传入的对象为null

return false; //返回false

if (getClass() != obj.getClass()) //判断两个对象对应的字节码文件是否是同一个字节码

return false; //如果不是直接返回false

Person other = (Person) obj; //向下转型

if (age != other.age) //调用对象的年龄不等于传入对象的年龄

return false; //返回false

if (name == null) { //调用对象的姓名为null

if (other.name != null) //传入对象的姓名不为null

return false; //返回false

} else if (!name.equals(other.name)) //调用对象的姓名不等于传入对象的姓名

return false; //返回false

return true; //返回true

}

细说hashCode和equals方法

2.4、一个案例来说明问题

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package com.zyh.domain;public classPerson {privateString name;private intage;public Person(String name,intage) {this.name =name;this.age =age;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}public intgetAge() {returnage;

}public void setAge(intage) {this.age =age;

}/** 为什么是31?

* 1,31是一个质数,质数是能被1和自己本身整除的数

* 2,31这个数既不大也不小

* 3,31这个数好算,2的五次方-1,2向左移动5位*/@Overridepublic inthashCode() {

finalint prime = 31;int result = 1;

result= prime * result +age;

result= prime * result + ((name == null) ? 0: name.hashCode());returnresult;

}

@Overridepublicboolean equals(Object obj) {if (this == obj) //调用的对象和传入的对象是同一个对象

return true; //直接返回true

if (obj == null) //传入的对象为null

return false; //返回false

if (getClass() != obj.getClass()) //判断两个对象对应的字节码文件是否是同一个字节码

return false; //如果不是直接返回false

Person other = (Person) obj; //向下转型

if (age != other.age) //调用对象的年龄不等于传入对象的年龄

return false; //返回false

if (name == null) { //调用对象的姓名为null

if (other.name != null) //传入对象的姓名不为null

return false; //返回false

} else if (!name.equals(other.name)) //调用对象的姓名不等于传入对象的姓名

return false; //返回false

return true; //返回true

}

@OverridepublicString toString() {return "Person{" +

"name='" + name + '\'' +

", age=" + age +

'}';

}

}

Person

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package com.zyh.Collection.set;

import com.zyh.domain.Person;

import java.util.HashSet;public classHashSetDemo_0010 {/*HashSet集合存储自定义对象并遍历。如果对象的成员变量值相同即为同一个对象

注意了:

你使用的是HashSet集合,这个集合的底层是哈希表结构。

而哈希表结构底层依赖:hashCode()和equals()方法。

如果你认为对象的成员变量值相同即为同一个对象的话,你就应该重写这两个方法。

如何重写呢?不同担心,自动生成即可。*/

public static voidmain(String[] args) {

HashSet hs = new HashSet<>();

hs.add(new Person("boy",10));

hs.add(new Person("girl",34));

hs.add(new Person("girl",34));

hs.add(new Person("boy",10));

hs.add(new Person("person",10));

hs.add(new Person("boy",10));

hs.add(new Person("person",10));

hs.add(new Person("boy",10));

hs.add(new Person("girl",34));//遍历集合

for(Person p : hs){

System.out.println(p.getName()+":"+p.getAge());

}

}

}

HashSetDemo_0010

三、LinkedHashSet

3.1、LinkedHashSet概述

1)LinkedHashSet是HashSet的子类,LinkedHashSet 集合也是根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。

也就是说,当遍历 LinkedHashSet 将会按照添加元素顺序来访问集合里的元素。

2)LinkedHashSet是通过用一个链表的实现来扩展HashSet,从而支持了对HashSet中的元素的排序。所以LinkedHashSet可以按照元素插入时的顺序进行提取。

3)LinkedHashSet 需要维护元素的插入顺序,因此性能略低于 HashSet 的性能,但在迭代访问 Set 里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。

虽然 LinkedHashSet 使用了链表记录集合元素的添加顺序,但 LinkedhasHSet依然是 HashSet,因此它依然不允许集合元素重复。

4)LinkedHashSet只能按照先后顺序来进行排序,TreeSet则是按照比较器给的比较规则进行从小到大排序。其实现也就是借助于TreeMap。

3.2、LinkedHashSet的特点

一是:保证元素唯一。二是:可以保证怎么存就怎么取

3.3、SortedSet接口与TreeSet类

SortedSet接口是Set接口的子接口,除了拥有Set集合的一些基本特点之外,还提供了排序的功能。

TreeSet类就是SortedSet接口的实现类

四、TreeSet

4.1、TreeSet概述

1)TreeSet继承与实现关系

TreeSet 是一个有序的集合,它的作用是提供有序的Set集合。它继承于AbstractSet抽象类,实现了NavigableSet, Cloneable, java.io.Serializable接口。

TreeSet 继承于AbstractSet,所以它是一个Set集合,具有Set的属性和方法。

TreeSet 实现了NavigableSet接口,意味着它支持一系列的导航方法。比如查找与指定目标最匹配项。

TreeSet 实现了Cloneable接口,意味着它能被克隆。

TreeSet 实现了java.io.Serializable接口,意味着它支持序列化。

TreeSet是基于TreeMap实现的。TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator (比较器排序)进行排序。这取决于使用的构造方法。

TreeSet为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销。

另外,TreeSet是非同步的。 它的iterator 方法返回的迭代器是fail-fast的。

2)存储对象

TreeSet存储对象的时候, 可以排序, 但是需要指定排序的算法。

Integer能排序(有默认顺序), String能排序(有默认顺序), 自定义的类存储的时候出现异常(没有顺序)

如果想把自定义类的对象存入TreeSet进行排序, 那么必须实现Comparable接口

在类上implement Comparable

重写compareTo()方法

在使用TreeSet存储对象的时候, add()方法内部就会自动调用compareTo()方法进行比较, 根据比较结果使用二叉树形式进行存储

3)Tree的构造方法

//默认构造函数。使用该构造函数,TreeSet中的元素按照自然排序进行排列。

TreeSet()//创建的TreeSet包含collection

TreeSet(Collection extends E>collection)//指定TreeSet的比较器

TreeSet(Comparator super E>comparator)//创建的TreeSet包含set

TreeSet(SortedSet set)

4)TreeSet与Collection的关系

f60be1fe42dc4463d68f0b73bc2cc35a.png

TreeSet继承于AbstractSet,并且实现了NavigableSet接口。

TreeSet的本质是一个"有序的,并且没有重复元素"的集合,它是通过TreeMap实现的。TreeSet中含有一个"NavigableMap类型的成员变量"m,而m实际上是"TreeMap的实例"。

4.2、TreeSet原理

1)特点

TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列

2)使用方式

2.1)自然顺序(Comparable)

TreeSet类的add()方法中会把存入的对象提升为Comparable类型

调用对象的compareTo()方法和集合中的对象比较

根据compareTo()方法返回的结果进行存储

2.2)比较器顺序(Comparator)

创建TreeSet的时候可以制定 一个Comparator

如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序

add()方法内部会自动调用Comparator接口中compare()方法排序

调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

2.3)两种方式的区别

TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)

TreeSet如果传入Comparator, 就优先按照Comparator

4.3、图解TreeSet的排序原理

4.3.1、环境

我们创建了一个Person类和一个测试类TreeSetDemo_0010类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package com.zyh.domain;public classPerson {privateString name;private intage;public Person(String name,intage) {this.name =name;this.age =age;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}public intgetAge() {returnage;

}public void setAge(intage) {this.age =age;

}/** 为什么是31?

* 1,31是一个质数,质数是能被1和自己本身整除的数

* 2,31这个数既不大也不小

* 3,31这个数好算,2的五次方-1,2向左移动5位*/@Overridepublic inthashCode() {

finalint prime = 31;int result = 1;

result= prime * result +age;

result= prime * result + ((name == null) ? 0: name.hashCode());returnresult;

}

@Overridepublicboolean equals(Object obj) {if (this == obj) //调用的对象和传入的对象是同一个对象

return true; //直接返回true

if (obj == null) //传入的对象为null

return false; //返回false

if (getClass() != obj.getClass()) //判断两个对象对应的字节码文件是否是同一个字节码

return false; //如果不是直接返回false

Person other = (Person) obj; //向下转型

if (age != other.age) //调用对象的年龄不等于传入对象的年龄

return false; //返回false

if (name == null) { //调用对象的姓名为null

if (other.name != null) //传入对象的姓名不为null

return false; //返回false

} else if (!name.equals(other.name)) //调用对象的姓名不等于传入对象的姓名

return false; //返回false

return true; //返回true

}

@OverridepublicString toString() {return "Person{" +

"name='" + name + '\'' +

", age=" + age +

'}';

}

}

Person

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

package com.zyh.Collection.set;

import com.zyh.domain.Person;

import java.util.TreeSet;public classTreeSetDemo_0010 {public static voidmain(String[] args) {

TreeSet ts = new TreeSet<>();

ts.add(new Person("张三",23));

ts.add(new Person("李四",13));

ts.add(new Person("王五",43));

ts.add(new Person("赵六",33));for(Person p:ts){

System.out.println(p);

}

}

}

TreeSetDemo_0010

当我们直接执行的时候,会报错误。

Exception in thread "main" java.lang.ClassCastException: com.zyh.domain.Person cannot be cast to java.lang.Comparable

分析:Integer能排序(有默认顺序), String能排序(有默认顺序), 自定义的类存储的时候出现异常(没有顺序)

4.3.2、自然排序(Comparable)

我们让Person实现Comparable接口,重写compareTo方法

6602f85a018874798103f6e6e1e76f98.png

当我们把返回值设置为1时:

41e00a2710b1cfe2a9d0016ca359becd.png

图解:

94de5a15b07b1fdbe4b13c00c7a26783.png

当返回值是0时,张三作为二叉树的根,当我们其他的元素比较时,都返回0表示相同的对象。所以只会存储张三。

当返回值是-1时,张三作为二叉树的根,李四和它比较时,返回-1说明,李四小,挂在张三的左边。王五一进来也和张三比较返回-1,放在张三左边,在和李四比较返回-1,挂在李四左边,以此类推。

当返回值是1时。和上面一样的推理。

2.1)按照年龄排序

4a7b82547f8dec05948a9153e4c7841b.png

分析:

张三作为二叉树的根,当李四进来的时候,李四的年龄比张三小,挂在张三的左边。当王五进来的时候,王五的年纪比张三大,所以挂在张三的

右边。当赵六的进来的时候,和张三比较年龄结果赵六大,挂在张三的右边,在和王五比较结果比王五小,挂在王五的左边。

结果排序就是:李四、张三、赵六、王五

ec3a69fff1ec2995db96e2c160208c31.png

2.2)按年龄为主要条件,名字是次要条件

8e5412ff332c41745d3b4c9eb04d6874.png

4.3.3、比较器顺序(Comparator)

首先我们查看TreeSet的构造方法发现有一个这样的构造方法:

//指定TreeSet的比较器

TreeSet(Comparator super E> comparator)

通过查看它的构造方法就知道可以传入一个比较器。

构造一个新的空TreeSet,它根据指定比较器进行排序。插入到该 set 的所有元素都必须能够由指定比较器进行相互比较:对于 set 中的任意两个元素 e1 和e2,执行 comparator.compare(e1, e2) 都不得抛出 ClassCastException。

如果用户试图将违反此约束的元素添加到 set 中,则 add 调用将抛出 ClassCastException。

8f0cffbf1c9f4d45d23e01c0e4d4b9fc.png

1)TreeSetd的Comparetor比较器实现的二种方法

第一种:写个类实现Comparator接口

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

classmyComparator implements Comparator{

@Overridepublic intcompare(Object o1, Object o2) {

Person p1=(Person) o1;

Person p2=(Person) o2;int num =p1.getName().compareTo(p2.getName());//0的话是两个相同,进行下一个属性比较

if (num == 0){return new Integer(p1.getAge()).compareTo(newInteger(p2.getAge()));

}returnnum;

}

}

然后在new Set的时候放进去。如

TreeSet ts= new TreeSet(new myComparator());

myComparator

第二种:写内名内部类方法

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

TreeSet ts = new TreeSet(newComparator() {

@Overridepublic intcompare(Object o1, Object o2) {

Person p1=(Person) o1;

Person p2=(Person) o2;int num =p1.getName().compareTo(p2.getName());if (num == 0){return new Integer(p1.getAge()).compareTo(newInteger(p2.getAge()));

}returnnum;

}

});

View Code

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

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

相关文章

AI 发展方向大争论:混合AI ?强化学习 ?将实际知识和常识整合到AI中 ?

一个仿人机器人的延伸手。机器人常常使用强化学习来加以训练来源&#xff1a;云头条作者&#xff1a;Ben Dickson是一名软件工程师&#xff0c;还是探讨技术在如何解决和带来问题的TechTalks博客的创始人。2010年代对于AI界来说意义重大&#xff0c;这归功于深度学习领域取得了…

吴恩达:2020 年,这些 AI 大事件让我无法忘怀...

作者&#xff1a;吴恩达编译&#xff1a;陈大鑫、贝爽编辑&#xff1a;青暮转自&#xff1a;AI科技评论日前&#xff0c;吴恩达在圣诞节之际回顾了2020年AI的一些重大事件&#xff0c;包括AI应对新冠疫情、数据集存在种族偏见、对抗虚假信息算法、AlphaFold预测蛋白质三维结构、…

java工程师的一生_百看不厌之一张图诠释程序员的一生

原标题&#xff1a;百看不厌之一张图诠释程序员的一生01百看不厌系列之一张图诠释程序员的一生。02变得越来越强了...03不知道是干什么的&#xff0c;但又不敢删。。。04当前端的人抱怨Java 时&#xff0c;C程序员05给产品经理设计了一款趁手的宝贝06离职程序员交接项目07这位压…

好久没玩laravel了,5.6玩下(三)

好久没玩laravel了&#xff0c;5.6玩下&#xff08;三&#xff09; 好了&#xff0c;基础的测试通了&#xff0c;咱们开始增删改了 思路整理 先创建项目功能控制器 然后设置路由访问规则 然后开发项目的增删改功能 1 先创建项目的控制器 php artisan make:controller ProjectsC…

OpenAI祭出120亿参数魔法模型!从文本合成图像栩栩如生,仿佛拥有人类的语言想象力...

来源&#xff1a;AI科技评论作者&#xff1a;OpenAI编译&#xff1a;贝爽、陈大鑫前几个月GPT-3刚刚问世的时候&#xff0c;能够根据一段话就写出一个小说、一段哲学语录&#xff0c;就足以令AI圈为之感到兴奋。然而2020年刚刚开始没多久&#xff0c;OpenAI又实现一重大突破&am…

MySQL快速生成连续整数

很多时候需要用到连续的id进行数据对比&#xff0c;如判断是否连续等问题。那么&#xff0c;生成连续整数的方式有多种&#xff0c;首先容易想到的是逐步循环&#xff0c;如果想生成1kw条记录&#xff0c;则需要循环1kw次进行插入&#xff0c;那么有没有其他方式呢&#xff0c;…

MySQL小问题:The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents...

这是因为时区设置不对 问题背景&#xff1a; 在运行storm项目&#xff0c;进行页面显示的时候&#xff0c;报错&#xff1a; java.sql.SQLException: The server time zone value is unrecognized or represents more than one time zone. 这是时区的问题。 我采用的第一个…

中国电子信息工程科技发展十四大趋势(2021)

来源&#xff1a;科技日报、中国电子报&#xff08;转载请注明来源&#xff09;编辑&#xff1a;蒲蒲1月5日&#xff0c;中国工程院信息与电子工程学部、中国信息与电子工程科技发展战略研究中心发布“中国电子信息工程科技发展十四大趋势&#xff08;2021&#xff09;”&#…

rosserial_java_[学习笔记]Rosserial实现Windows-ROS交互操作(1)

安装sudo apt-get install ros-indigo-rosserial-windowssudo apt-get install ros-indigo-rosserial-server编译rosrun rosserial_windows make_libraries.py my_library运行后会产生一个my_library文件夹&#xff0c;在my_library这个文件夹下会生成ros_lib文件夹Windows下创…

Leetcode--122. 买卖股票的最佳时机Ⅱ

给定一个数组&#xff0c;它的第 i 个元素是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易&#xff08;多次买卖一支股票&#xff09;。 注意&#xff1a;你不能同时参与多笔交易&#xff08;你必须在再次购买前出售掉…

语法树的画法(根据文法求字符串)

目录 1.语法树的画法 2.语法树的短语 3.直接短语&#xff08;直接到根部&#xff09; 4.素短语 5.句柄 6.算符优先分析句型 1.语法树的画法 文法G[E]:E->EE | E*E | (E) | i ,字符串 ii*i 推导方式有两种最左推导和最右推导&#xff08;推导的技巧就是逐步靠近字符串…

AI专家喋喋不休展开争论 为什么说预测是智能的本质

来源&#xff1a; 网易智能编译&#xff1a;网易智能 选自&#xff1a;medium参与:Rosie【网易智能讯 6月22日消息】机器学习和智能都植根于预测&#xff0c;这是巧合吗&#xff1f;当我们的技术体现了智能的本质时&#xff0c;我们正在接近一个紧要关头吗&#xff1f;或者说我…

图解丨卷积神经网络数学原理解析

原标题&#xff1a;Gentle Dive into Math Behind Convolutional Neural Networks作 者&#xff1a;Piotr Skalski 编 辑 | Pita  翻 译&#xff1a;通夜&#xff08;中山大学&#xff09;、had_in&#xff08;电子科技大学&#xff09;自动驾驶、智能医疗保健和自助零售这…

[2018湖南省队集训] 6.28 T3 simulate

这道模拟题出的我毫无脾气2333 最重要的是先要发现操作顺序不影响最后的答案&#xff0c;也就是每次随便挑一个>2的数进行操作最后总是可以得到同样的数列。 (这个还不太难想qwq) 但是最骚的是接下来的模拟。。。。 我们考虑从左到右消&#xff0c;假设目前在i&#xff0c;1…

“AI工厂”本质:AI基础设施及怎样将AI转化为运营动力

来源&#xff1a;TechTalks作者&#xff1a;Ben Dickson编译&#xff1a;科技行者持续关注人工智能新闻的朋友肯定已经发现&#xff0c;AI这个字眼已经被异化成了两个截然不同的定义。媒体和影视作品喜欢把AI描述成已然具备人类般的能力、会导致大量失业甚至会出动机械部队进行…

继续深入更新shell脚本容易出错的地方

一、在shell中用到如果需要输入某些值&#xff0c;需要用到read -p命令 这是我写的猜数字游戏&#xff0c;一开始在输出的时候&#xff0c;屏幕上总会打印输出 "INT" 经过反复的练习才发现 双引号后面应该跟着一个空格&#xff0c;然后在写变量&#xff0c;就不会把…

中国工程院发布2021中国电子信息工程科技发展十四大趋势

来源&#xff1a;人民邮电报1月5日&#xff0c;中国工程院信息与电子工程科技发展战略研究中心发布“中国电子信息工程科技发展十四大趋势&#xff08;2021&#xff09;”。这十四大趋势涵盖信息化、计算机系统与软件、网络与通信、计算机应用、网络安全、集成电路、数据、感知…

AcWing--2.01背包问题

有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。 第 ii 件物品的体积是 vivi&#xff0c;价值是 wiwi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入格式 第一行两个整数&#xff…

java实现数组排序代码_Java使用选择排序法对数组排序实现代码

编写程序&#xff0c;实现将输入的字符串转换为一维数组&#xff0c;并使用选择排序法对数组进行排序。思路如下&#xff1a;点击"生成随机数"按钮&#xff0c;创建Random随机数对象&#xff1b;使用JTextArea的setText()方法清空文本域&#xff1b;创建一个整型一维…

ICinsights:中国芯片难达成既定的2025目标

来源&#xff1a;内容由半导体行业观察&#xff08;ID&#xff1a;icbank&#xff09;综合自「ICinsights」&#xff0c;谢谢。据知名分析机构ICinsights报道&#xff0c;在中国的集成电路市场和中国的本土集成电路生产之间应该有一个非常明显的区别。正如IC Insights经常指出的…