Java Set荟萃的详解

 欧宝加盟     |      2021-03-09 22:20

一,Set

Set:偏重独一无二的性质,该体系荟萃能够清新某物是否已近存在于荟萃中,不会存储重复的元素

用于存储无序(存入和掏出的挨次纷歧定相通)元素,值不及重复。

对象的很是性

   引用到堆上联相符个对象的两个引用是很是的。倘若对两个引用调用hashCode手段,会得到相通的效果,倘若对象所属的类异国遮盖Object的hashCode手段的话,hashCode会返回每个对象专有的序号(java是依据对象的内存地址计算出的此序号),以是两个分歧的对象的hashCode值是不能够很是的。

倘若想要让两个分歧的Person对象视为很是的,就必须遮盖Object继下来的hashCode手段和equals手段,由于Object  hashCode手段返回的是该对象的内存地址,以是必须重写hashCode手段,才能保证两个分歧的对象具有相通的hashCode,同时也必要两个分歧对象比较equals手段会返回true

该荟萃中异国专有的手段,直接继承自Collection。

---| Itreable      接口 实现该接口能够行使添强for循环---| Collection描述一切荟萃共性的接口---| List接口    能够有重复元素的荟萃---| ArrayList---|  LinkedList---| Set接口    不能够有重复元素的荟萃

案例:set荟萃增补元素并行使迭代器迭代元素。

public class Demo4 {public static void main(String[] args) {//Set 荟萃存和取的挨次纷歧致。Set hs = new HashSet();hs.add("世界军事");hs.add("兵器知识");hs.add("舰船知识");hs.add("汉和防务");System.out.println(hs);// [舰船知识, 世界军事, 兵器知识, 汉和防务]Iterator it = hs.iterator();while (it.hasNext()) {System.out.println(it.next());}}}
二,HashSet
---| Itreable      接口 实现该接口能够行使添强for循环---| Collection描述一切荟萃共性的接口---| List接口    能够有重复元素的荟萃---| ArrayList---|  LinkedList---| Set接口    不能够有重复元素的荟萃---| HashSet  线程担心然,存取速度快。底层是以哈希外实现的。

HashSet

哈希外边存放的是哈希值。HashSet存储元素的挨次并不是依照存时兴的挨次(和List隐微分歧) 是依照哈希值来存的以是取数据也是依照哈希值取得。

HashSet不存入重复元素的规则.行使hashcode和equals

由于Set荟萃是不及存入重复元素的荟萃。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会议定元素的hashcode()和equals手段进走判断元素师否重复。

当你试图把对象添入HashSet时,HashSet会行使对象的hashCode来判断对象添入的位置。同时也会与其他已经添入的对象的hashCode进走比较,倘若异国很是的hashCode,HashSet就会倘若对象异国重复展现。

浅易一句话,倘若对象的hashCode值是分歧的,那么HashSet会认为对象是不能够很是的。

因此吾们自定义类的时候必要重写hashCode,来确保对象具有相通的hashCode值。

倘若元素(对象)的hashCode值相通,是不是就无法存入HashSet中了? 自然不是,会不息行使equals 进走比较.倘若 equals为true那么HashSet认为新添入的对象重复了,以是添入战败。倘若equals 为false那么HashSet 认为新添入的对象异国重复.新元素能够存入.

总结:

元素的哈希值是议定元素的hashcode手段 来获取的, HashSet最先判断两个元素的哈希值,倘若哈希值相通,接着会比较equals手段 倘若 equls效果为true ,HashSet就视为联相符个元素。倘若equals 为false就不是联相符个元素。

哈希值相通equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(能够认为哈希值相通的元素放在一个哈希桶中)。也就是哈希相通的存一列。

hashtable

图片

图1:hashCode值不相通的情况

图2:hashCode值相通,但equals不相通的情况。

HashSet:议定hashCode值来确定元素在内存中的位置。一个hashCode位置上能够存放众个元素。

当hashcode() 值相通equals() 返回为true 时,hashset 荟萃认为这两个元素是相通的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 手段的值,倘若相通才会往判断equals 倘若不相通,是不会调用equals手段的。

HashSet到底是如何判断两个元素重复。

议定hashCode手段和equals手段来保证元素的唯一性,add()返回的是boolean类型

判断两个元素是否相通,先要判断元素的hashCode值是否相反,只有在该值相反的情况下,才会判断equals手段,倘若存储在HashSet中的两个对象hashCode手段的值相通equals手段返回的效果是true,那么HashSet认为这两个元素是相通元素,只存储一个(重复元素无法存入)。

仔细:HashSet荟萃在判断元素是否相通先判断hashCode手段,倘若相通才会判断equals。倘若不相通,是不会调用equals手段的。

HashSet 和ArrayList荟萃都有判断元素是否相通的手段,

boolean contains(Object o)

HashSet行使hashCode和equals手段,ArrayList行使了equals手段

案例:

行使HashSet存储字符串,并尝试增补重复字符串

回顾String类的equals()、hashCode()两个手段。

public class Demo4 {public static void main(String[] args) {// Set 荟萃存和取的挨次纷歧致。Set hs = new HashSet();hs.add("世界军事");hs.add("兵器知识");hs.add("舰船知识");hs.add("汉和防务");

// 返回此 set 中的元素的数目System.out.println(hs.size()); // 4

// 倘若此 set 尚未包含指定元素,则返回 trueboolean add = hs.add("世界军事"); // falseSystem.out.println(add);

// 返回此 set 中的元素的数目System.out.println(hs.size());// 4Iterator it = hs.iterator();while (it.hasNext()) {System.out.println(it.next());}}}

行使HashSet存储自定义对象,并尝试增补重复对象(对象的重复的鉴定)

public class Demo4 {public static void main(String[] args) {HashSet hs = new HashSet();hs.add(new Person("jack", 20));hs.add(new Person("rose", 20));hs.add(new Person("hmm", 20));hs.add(new Person("lilei", 20));hs.add(new Person("jack", 20));

Iterator it = hs.iterator();while (it.hasNext()) {Object next = it.next();System.out.println(next);}}}

class Person {private String name;private int age;

Person() {

}

public Person(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 hashCode() {System.out.println("hashCode:" + this.name);return this.name.hashCode() + age * 37;}

@Overridepublic boolean equals(Object obj) {System.out.println(this + "---equals---" + obj);if (obj instanceof Person) {Person p = (Person) obj;return this.name.equals(p.name) && this.age == p.age;} else {return false;}}

@Overridepublic String toString() {

return "Person@name:" + this.name + " age:" + this.age;}

}

题目:现在有一批数据,请求不及重复存储元素,而且要排序。ArrayList 、 LinkedList不及往除重复数据。HashSet能够往除重复,但是是无序。

以是这时候就要行使TreeSet了

三,TreeSet

案例:行使TreeSet荟萃存储字符串元素,并遍历

public class Demo5 {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add("ccc");ts.add("aaa");ts.add("ddd");ts.add("bbb");

System.out.println(ts); // [aaa, bbb, ccc, ddd]

}}
---| Itreable      接口 实现该接口能够行使添强for循环---| Collection描述一切荟萃共性的接口---| List接口    有序,欧宝加盟能够重复,有角标的荟萃---| ArrayList---|  LinkedList---| Set接口    无序,不能够重复的荟萃---| HashSet  线程担心然,存取速度快。底层是以hash外实现的。---| TreeSet  红-暗树的数据组织,默认对元素进走自然排序(String)。倘若在比较的时候两个对象返回值为0,那么元素重复。

红-暗树

红暗树是一栽特定类型的二叉树

图片

红暗树算法的规则: 左幼右大。

既然TreeSet能够自然排序,那么TreeSet一定是有排序规则的。

1:让存入的元素自定义比较规则。

2:给TreeSet指定排序规则。

手段一:元素自己具备比较性

元素自己具备比较性,必要元素实现Comparable接口,重写compareTo手段,也就是让元素自己具备比较性,这栽手段叫做元素的自然排序也叫做默认排序。

手段二:容器具备比较性

当元素自己不具备比较性,或者自己具备的比较性不是所必要的。那么此时能够让容器自己具备。必要定义一个类实现接口Comparator,重写compare手段,并将该接口的子类实例对象行为参数传递给TreeMap荟萃的组织手段。

仔细:当Comparable比较手段和Comparator比较手段同时存在时,以Comparator的比较手段为主;

仔细:在重写compareTo或者compare手段时,必须要清晰比较的主要条件很是时要比较次要条件。(倘若姓名和年龄不息的人造相通的人,倘若想要对人依照年龄的大幼来排序,倘若年龄相通的人,必要如那里理?不及直接return 0,由于能够姓名分歧(年龄相通姓名分歧的人是分歧的人)。此时就必要进走次要条件判断(必要判断姓名),只有姓名和年龄同时很是的才能够返回0.)

议定return 0来判断唯一性。

题目:为什么行使TreeSet存入字符串,字符串默认输出是按升序排列的?由于字符串实现了一个接口,叫做Comparable 接口.字符串重写了该接口的compareTo 手段,以是String对象具备了比较性.那么同样道理,吾的自定义元素(例如Person类,Book类)想要存入TreeSet荟萃,就必要实现该接口,也就是要让自定义对象具备比较性.

存入TreeSet荟萃中的元素要具备比较性.

比较性要实现Comparable接口,重写该接口的compareTo手段

TreeSet属于Set荟萃,该荟萃的元素是不及重复的,TreeSet如何保证元素的唯一性

议定compareTo或者compare手段中的来保证元素的唯一性。

增补的元素必须要实现Comparable接口。当compareTo()函数返回值为0时,表明两个对象很是,此时该对象不会增补进来。

比较器接口

----| Comparable       compareTo(Object o)     元素自己具备比较性----| Comparator       compare( Object o1, Object o2 )给容器传入比较器

TreeSet荟萃排序的两栽手段:

一,让元素自己具备比较性。

也就是元素必要实现Comparable接口,遮盖compareTo 手段。

这栽手段也行为元素的自然排序,也可称为默认排序。

年龄依照搜要条件,年龄相通再比姓名。

public class Demo4 {public static void main(String[] args) {TreeSet ts = new TreeSet();ts.add(new Person("aa", 20, "男"));ts.add(new Person("bb", 18, "女"));ts.add(new Person("cc", 17, "男"));ts.add(new Person("dd", 17, "女"));ts.add(new Person("dd", 15, "女"));ts.add(new Person("dd", 15, "女"));

System.out.println(ts);System.out.println(ts.size()); // 5

}}

class Person implements Comparable {private String name;private int age;private String gender;

public Person() {

}

public Person(String name, int age, String gender) {

this.name = name;this.age = age;this.gender = gender;}

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;}

public String getGender() {return gender;}

public void setGender(String gender) {this.gender = gender;}

@Overridepublic int hashCode() {return name.hashCode() + age * 37;}

public boolean equals(Object obj) {System.err.println(this + "equals :" + obj);if (!(obj instanceof Person)) {return false;}Person p = (Person) obj;return this.name.equals(p.name) && this.age == p.age;

}

public String toString() {return "Person [name=" + name + ", age=" + age + ", gender=" + gender+ "]";}

@Overridepublic int compareTo(Object obj) {

Person p = (Person) obj;System.out.println(this+" compareTo:"+p);if (this.age > p.age) {return 1;}if (this.age < p.age) {return -1;}return this.name.compareTo(p.name);}

}

二,让容器自己具备比较性,自定义比较器。

需求:当元素自己不具备比较性,或者元素自己具备的比较性不是所需的。

那么这时只能让容器自己具备。

定义一个类实现Comparator 接口,遮盖compare手段。

并将该接口的子类对象行为参数传递给TreeSet荟萃的组织函数。

当Comparable比较手段,及Comparator比较手段同时存在,以Comparator

比较手段为主。

public class Demo5 {public static void main(String[] args) {TreeSet ts = new TreeSet(new MyComparator());ts.add(new Book("think in java", 100));ts.add(new Book("java 中央技术", 75));ts.add(new Book("当代操作编制", 50));ts.add(new Book("java就业教程", 35));ts.add(new Book("think in java", 100));ts.add(new Book("ccc in java", 100));

System.out.println(ts);}}

class MyComparator implements Comparator {

public int compare(Object o1, Object o2) {Book b1 = (Book) o1;Book b2 = (Book) o2;System.out.println(b1+" comparator "+b2);if (b1.getPrice() > b2.getPrice()) {return 1;}if (b1.getPrice() < b2.getPrice()) {return -1;}return b1.getName().compareTo(b2.getName());}

}

class Book {private String name;private double price;

public Book() {

}

public String getName() {return name;}

public void setName(String name) {this.name = name;}

public double getPrice() {return price;}

public void setPrice(double price) {this.price = price;}

public Book(String name, double price) {

this.name = name;this.price = price;}

@Overridepublic String toString() {return "Book [name=" + name + ", price=" + price + "]";}

}
四,LinkedHashSet

会保存插入的挨次。

望到array,就要想到角标。

望到link,就要想到first,last。

望到hash,就要想到hashCode,equals.

望到tree,就要想到两个接口。Comparable,Comparator。

分享一些技术学习视频原料:https://pan.baidu.com/s/13dbR69NLIEyP1tQyRTl4xw