1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Java基础知识 21(Set集合 HashSet集合以及它的三种遍历方式(迭代器 增强for循环

Java基础知识 21(Set集合 HashSet集合以及它的三种遍历方式(迭代器 增强for循环

时间:2022-03-30 12:37:03

相关推荐

Java基础知识 21(Set集合 HashSet集合以及它的三种遍历方式(迭代器 增强for循环

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 ? pareTo(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 parator;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 parator;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集合(自然排序法 比较器排序法))

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。