Java基础知识 21

Set集合

Set集合:一个不包含重复元素的Collection集合,元素不重复,List集合是允许元素重复的。
Set接口的三个字类:HashSet(),LinkedHashSet(),TreeSet()

HashSet集合


HashSet()集合底层使用的是hashMap()来存储元素,底层数据结构是哈希表,元素无序,且不允许元素重复(存的顺序和去的顺序不一致),可以存储null元素,线程不安全,效率高。哈希表:是一个元素为链表的数组,综合了数组和链表的优点(JDK1.7之前),(JDK1.8之后优化了数组+链表+二叉树)
HashSet(),构造一个新的容器空set,其底层是HashMap实例,默认初始容量是16,加载因子是0.75。

import java.util.HashSet;public class Mytest {public static void main(String[] args) {/** Set接口:一个不包含重复元素的Collection,元素不重复。* list:允许元素重复* Set接口的三个字类:HashSet,LinkedHashSet,TreeSet* HashSet:底层数据结构是哈希表,元素无序(存的顺序和取的顺序不一致),* 且不允许元素重复,可以存储null元素,线程不安全的,但是效率高*///HashSet(),构造一个新的空set,其底层HashMap实例的默认初始容量是16,加载因子是0.75HashSet<String> hashSet = new HashSet<>();hashSet.add("王俊凯");hashSet.add("王源");hashSet.add("易烊千玺");hashSet.add("王俊凯");hashSet.add("王源");hashSet.add("易烊千玺");hashSet.add("王俊凯");hashSet.add("王源");hashSet.add("易烊千玺");System.out.println(hashSet);System.out.println("---------------------");for (String s : hashSet) {System.out.println(s);}}
}

当我们往HashSet集合中存储对象时,会调用hashCode()方法,算出一个值,这个值就是确定这个对象放到表中的位置。那假如有两个对象,算出的位置是一样的,就会调用equals()方法,去比较两个对象的地址值是否一样,如果不一样那就存储进去,形成链表结构。

import java.util.HashSet;public class Mytest {public static void main(String[] args) {/**HashSet底层数据结构是哈希表,HashSet是线程不安全的,集合元素可以是null*哈希表:是一个元素为链表的数组,综合了数组和集合的所有优点(像新华字典一样)* (JDK1.7之前)JDK1.8之后优化了(数组+链表+二叉树)*///存储元素为student类型,无序且不允许元素重复HashSet<Student> hashSet = new HashSet<>();hashSet.add(new Student("夏雪",25));hashSet.add(new Student("刘星",24));hashSet.add(new Student("夏雨",23));hashSet.add(new Student("夏雪",25));hashSet.add(new Student("刘星",24));hashSet.add(new Student("夏雨",23));for (Student student : hashSet) {System.out.println(student);}/*当我们往hashset集合中存储对象时,会调用对象的hashcode方法,得到一个值,这个值就是确定这个对象放到表中的位置*//*那如果我们有两个对象算出来的位置值是一样的,就会调用equals()方法,去比较两个对象的地址值是否相同,如果地址值不相同,那就存储进去形成链表结构。*/}
}
---------------------------------
public class Student {private String name;private int age;public Student() {}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;}@Overridepublic boolean equals(Object o) {System.out.println("equals调用了 this:"+this+"==="+"之前的元素"+o);//由于调用equals方法,碰撞次数过多,因此我们去比较 他们的成员变量值if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name);//return super.equals(o);}@Overridepublic int hashCode() {//return Objects.hash(name, age);//如果写死hashCode值,肯定会造成碰撞次数过多return 0;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

为了减少碰撞,我们应该合理的去重写hashCode方法,来减少碰撞(减少调用equals方法的次数),尽量是在哈希表中横向排列,减少链表的形成。

public class Mytest2 {public static void main(String[] args) {HashSet<Integer> hashSet = new HashSet<>();hashSet.add(1000);hashSet.add(2000);hashSet.add(3000);hashSet.add(1000);hashSet.add(2000);hashSet.add(3000);hashSet.add(1000);hashSet.add(2000);hashSet.add(3000);System.out.println(hashSet);System.out.println("-----------------");for (Integer integer : hashSet) {System.out.println(integer);}//String类和Integer类,已经重写了hashCode()方法和equals()方法}
}

HashSet集合能够保证元素唯一性的原因重写了hashCode()方法和equals()方法来保证的,如果元素不重写hashCode()方法和equals()方法,则无法保证元素的唯一性。
我们合理的重写hashCode()方法,是为了元素能够在哈希表中尽可能的横向排列,减少碰撞(减少equals方法的调用)

import org.westos.demo2.Student;import java.util.HashSet;public class Mytest {public static void main(String[] args) {/**HashSet底层数据结构是哈希表,HashSet是线程不安全的,集合元素可以是null*哈希表:是一个元素为链表的数组,综合了数组和集合的所有优点(像新华字典一样)* (JDK1.7之前)JDK1.8之后优化了(数组+链表+二叉树)*///存储元素为student类型,无序且不允许元素重复HashSet<Student> hashSet = new HashSet<>();hashSet.add(new Student("夏雪",25));hashSet.add(new Student("刘星",24));hashSet.add(new Student("夏雨",23));hashSet.add(new Student("夏雪",25));hashSet.add(new Student("刘星",24));hashSet.add(new Student("夏雨",23));for (Student student : hashSet) {System.out.println(student.getName() + "===" + student.getAge());}/*当我们往hashset集合中存储对象时,会调用对象的hashcode方法,得到一个值,这个值就是确定这个对象放到表中的位置*//*那如果我们有两个对象算出来的位置值是一样的,就会调用equals()方法,去比较两个对象的地址值是否相同,如果地址值不相同,那就存储进去形成链表结构。*//*hashSet:集合能保证元素的唯一性,是靠元素重写hashCode()方法和equals()方法来保证的。如果元素不重写hashCode()和equals()方法,则无法保证元素的唯一性。我们合理的重写hashCode()方法是为了元素能够在哈希表中尽量横线分布,减少碰撞(减少equals方法的调用)*/}
}
----------------------------------
public class Student {private String name;private int age;public Student() {}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;}/* @Overridepublic boolean equals(Object o) {//System.out.println("equals调用了 this:"+this+"==="+"之前的元素"+o);//由于调用equals方法,碰撞次数过多,因此我们去比较 他们的成员变量值if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name);//return super.equals(o);}@Overridepublic int hashCode() {//return Objects.hash(name, age);//如果写死hashCode值,肯定会造成碰撞次数过多return this.name.hashCode()+this.age*5;}*/@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

HashSet集合的三种遍历方式:

import java.util.HashSet;
import java.util.Iterator;
import java.util.function.Consumer;public class Mytest {public static void main(String[] args) {HashSet<Integer> hashSet = new HashSet<>();hashSet.add(100);hashSet.add(200);hashSet.add(300);//hashSet集合遍历的三种方式//1.使用迭代器进行遍历Iterator<Integer> iterator = hashSet.iterator();while (iterator.hasNext()) {Integer next = iterator.next();System.out.println(next);}System.out.println("-------------------");//2.使用增强for循环来进行遍历for (Integer integer : hashSet) {System.out.println(integer);}System.out.println("-------------------");//3.使用forEach()方法来进行遍历hashSet.forEach(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println(integer);}});}
}

对元素进行去重:HashSet(Collection<? extends E> c),构造一个包含指定 collection 中的元素的新 set。你把List集合传进来,构建一个HashSet集合,就帮你去重了。

import java.util.ArrayList;
import java.util.HashSet;public class Mytest2 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(100);list.add(100);list.add(100);list.add(200);list.add(200);list.add(200);list.add(300);list.add(300);list.add(300);System.out.println(list);/*对元素进行去重HashSet(Collection<? extends E> c)构造一个包含指定 collection 中的元素的新 set。你把List集合传进来,构建一个HashSet集合,就帮你去重了*/HashSet<Integer> hashSet = new HashSet<>(list);System.out.println(hashSet);}
}

LinkedHashSet集合

LinkedHashSet集合的底层数据结构是链表+哈希表,链表能够保证元素的有序,哈希表能够保证元素的唯一性。(但是还是要重写hashCode方法和equals方法),LinkedHashSet元素有序且唯一,线程不安全的,但效率高。

import java.util.LinkedHashSet;public class Mytest {public static void main(String[] args) {/**LinkedHashSet 底层数据结构是链表+哈希表,* 链表能够保证元素有序,哈希表能够保证元素唯一。(但是还是要重写hashCode()和equals()方法)* LinkedHashSet 元素有序且唯一,线程不安全,但效率高* hashSet:无序,唯一*/LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();linkedHashSet.add("唐僧");linkedHashSet.add("孙悟空");linkedHashSet.add("猪八戒");linkedHashSet.add("沙悟净");linkedHashSet.add("唐僧");linkedHashSet.add("孙悟空");linkedHashSet.add("猪八戒");linkedHashSet.add("沙悟净");//遍历元素for (String s : linkedHashSet) {System.out.println(s);}}
}

TreeSet集合


TreeSet:底层数据结构使用的是二叉树,元素唯一,且能对元素进行排序。
TreeSet集合对元素进行排序有两种方法:自然排序法和比较器排序法。
(1)自然排序法:当你使用空参构造时,就是自然排序法。如果使用自然排序法,自然排序对元素有要求,要求元素必须实现一个Comparable接口,重写这个接口中的compareTo方法,这个比较的方法是根据返回值是 0 正 负 来决定元素在二叉树中放的位置,以及是否往进放。

import java.util.TreeSet;public class Mytest{public static void main(String[] args) {//使用自然排序:来排序学生对象,根据学生的年龄大小 来排序TreeSet<Student> treeSet = new TreeSet<>();treeSet.add(new Student("诸葛亮",50));treeSet.add(new Student("周瑜",48));treeSet.add(new Student("刘备",52));treeSet.add(new Student("关羽",58));treeSet.add(new Student("张飞",45));treeSet.add(new Student("曹操",55));treeSet.add(new Student("诸葛亮",50));treeSet.add(new Student("关羽",58));//如果这里出现了年龄一样,但是名字不一样的情况。这时候就需要我们在适当修改一下compareTo方法treeSet.add(new Student("孙权",52));//遍历元素for (Student student : treeSet) {System.out.println(student.getName()+"======"+student.getAge());}}
}
-------------------------------------------
public class Student implements Comparable<Student>{private String name;private int age;public Student() {}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;}@Overridepublic int compareTo(Student o) {//按照年龄的大小来比较int num=this.age-o.age;//年龄相同,但是名字不一样的情况,这种就需要比较姓名是否相同//使用三目运算符进行判别上面这种情况int num2=num==0 ? this.name.compareTo(o.name):num;返回值的 正 负  0 来决定元素在二叉树中的放置的左右位置,返回0 就不往里面存储return num2;//return 0;//返回是0,你写死了,只能返回一个根元素。}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

(2)比较器排序法: TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。Comparator接口,强行对某个对象Collections进行了整体排序比较函数。采用比较器排序,根据比较器中的compare()方法的返回值的正 负 0 ,来决定元素在二叉树中放的位置。

import java.util.Comparator;
import java.util.TreeSet;public class Mytest {public static void main(String[] args) {//使用比较器排序,按照姓名的长度来排序TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {//先比较姓名的长度int num1 = s1.getName().length() - s2.getName().length();//姓名长度一样时,再比较年龄大小int num2=num1==0?s1.getAge()-s2.getAge():num1;//年龄相同时,再比较姓名的内容int num3=num2==0?s1.getName().compareTo(s2.getName()):num2;return num3;}});treeSet.add(new Student("吴用智多星",50));treeSet.add(new Student("黑旋风李逵", 57));treeSet.add(new Student("宋江及时雨", 57));treeSet.add(new Student("武松行者", 57));treeSet.add(new Student("花和尚鲁智深", 23));treeSet.add(new Student("立地太岁阮小二", 97));treeSet.add(new Student("扈三娘", 47));treeSet.add(new Student("白胜", 17));treeSet.add(new Student("时迁", 17));treeSet.add(new Student("西门大官人", 87));for (Student student : treeSet) {System.out.println(student.getName()+"==="+student.getAge());}}
}
----------------------------------------
public class Student {private String name;private int age;public Student() {}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;public class Mytest2 {public static void main(String[] args) {//Comparator 这个比较器,不光TreeSet能用,其他的有些类也能用//可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort)ArrayList<Integer> list = new ArrayList<>();list.add(1000);list.add(800);list.add(950);list.add(860);list.add(503);list.add(640);list.add(999);list.sort(new Comparator<Integer>() {@Overridepublic int compare(Integer a, Integer b) {return a-b;}});System.out.println(list);System.out.println("------------------");int[] arr={20,30,90,41,33};Arrays.sort(arr);System.out.println(Arrays.toString(arr));System.out.println("------------------");Integer[] arr2={20,30,1,-5,90,41,33};//参数2:可以传入比较器Arrays.sort(arr2, new Comparator<Integer>() {@Overridepublic int compare(Integer a, Integer b) {return b-a;}});System.out.println(Arrays.toString(arr2));}
}

Java基础知识 21(Set集合,HashSet集合以及它的三种遍历方式(迭代器,增强for循环,forEach),LinkedHashSet集合,TreeSet集合(自然排序法,比较器排序法))相关推荐

  1. Java中List集合的三种遍历方式(全网最详)

    Map集合:链接: Map集合的五种遍历方式及Treemap方法 Set集合:链接: Java中遍历Set集合的三种方法 TreeSet集合:链接: Java深入了解TreeSet,和迭代器遍历方法 ...

  2. java中map的遍历方法_Java中Map的三种遍历方式

    集合中的三种遍历方式,如下代码: import java.util.Collection; import java.util.HashMap; import java.util.Iterator; i ...

  3. 重温数据结构:二叉树的常见方法及三种遍历方式 Java 实现

    读完本文你将了解到: 什么是二叉树 Binary Tree 两种特殊的二叉树 满二叉树 完全二叉树 满二叉树 和 完全二叉树 的对比图 二叉树的实现 用 递归节点实现法左右链表示法 表示一个二叉树节点 ...

  4. Java Collection集合的三种遍历方式

    文章目录 Collection遍历方式 迭代器遍历 foreach遍历 Lambda遍历 Collection遍历方式 Collection集合遍历的方式有三种: 迭代器 foreach/增强for循 ...

  5. Map集合的概述与特点,常用API及特有的三种遍历方式总结,带应用

    一.概述 Map集合是一种双列集合.由两部分组成. 键和值.称为键值对. Map集合分为: 示例: //1.创建一个Map集合对象 Map <String , Integer> maps ...

  6. Java中Map集合的三种遍历方式

    文章目录 Map集合的遍历方式 Map集合的遍历方式一: 键找值 Map集合的遍历方式二: 键值对 Map集合的遍历方式三: Lambda Map集合的遍历方式 Map集合的遍历方式有3种: 方式一: ...

  7. java集合 HashMap的三种遍历方式

    前言: HashMap的集合中的比重是无可厚非的,由自身的数组+链表/红黑树构成的(JDK 1.8),这样使得HashMap优点表现出来: 数组查询效率快: 链表的插入和删除效率也加快 但是HashM ...

  8. java arraylist 遍历_java集合ArrayList的三种遍历方式

    ArrayList ArrayList 使用连续的内存单元存储数据元素,是一个其容量能够动态增长的动态数组. 当添加或删除数据元素时(最后位置除外),ArrayList 需要移动其被添加(或删除)元素 ...

  9. 11 java基础之继承:区分子类方法中变量的三种变量

    在子类方法中使用三种同名变量,需要使用super关键字来访问同名的成员变量 /* 局部变量: 直接写成员变量名 本类的成员变量: this.成员变量名 父类的成员变量: super.成员变量名*/ 父 ...

最新文章

  1. /bin,/sbin,/usr/sbin,/usr/bin 目录区别
  2. OO Design之SOLID原则
  3. 1、django安装,问题,创建项目,编写第一个demo
  4. iframe嵌入页面白屏_封闭在家学网页制作!为页面嵌入PDF文件——零基础自学网页制作
  5. eBPF技术应用云原生网络实践系列之基于socket的service | 龙蜥技术
  6. MongoDB安装中断问题 - 踩坑篇
  7. SharePoint2010人员搜索
  8. matlab编写信号采集程序,MATLAB语音信号采集课程设计
  9. 我需要一个媒体服务器来进行一对多的WebRTC广播吗?
  10. oracle in table类型,Oracle Built-in Data Types(Oracle内置数据类型)
  11. python(九):函数、匿名函数 lambda
  12. 病历管理系统设计与实现
  13. 北京市常用电话号码表
  14. Flutter diff: /../Podfile.lock: No such file or directory AndroidStudio上的解决
  15. Python索引 说明
  16. 外地人在成都买房被限购怎么办?看完就知道
  17. 2021年中国不锈钢行业发展现状及重点企业对比分析[图]
  18. 项目管理资格认证PMP考前培训班
  19. MFC VC++多线程间通信
  20. 百度、腾讯和阿里内部的级别和薪资待遇是什么样的?-转自知乎

热门文章

  1. WPF编程,实现鼠标拖动控件并带有中间动效
  2. bugku-md5 collision(NUPT_CTF)
  3. 如何关闭139端口及445端口等危险端
  4. Ubuntu 16.04网络配置
  5. 「读书笔记」《如何阅读一本书》 | 随笔 |摘抄 |未完待续
  6. (串口通信编程) 开源串口调试助手Common (Com Monitor)
  7. 2017软件工程实践第一次作业(随笔)
  8. C# 串口 并口 打印代码
  9. 基于 python 多光谱遥感数据处理、图像分类、定量评估及机器学习方法
  10. Toolboxes--工具箱