**集合框架Set接口
1、Set接口**
public interface Set extends Collection
一个不包含重复元素的 collection。更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。
2、HashSet
public class HashSet extends AbstractSet implements Set, Cloneable, Serializable
类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
3、TreeSet
public class TreeSet extends AbstractSet implements NavigableSet, Cloneable, Serializable
基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。
4、LinkedHashSet
public class LinkedHashSet extends HashSet implements Set, Cloneable, Serializable
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。
此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。
注意,插入顺序不 受在 set 中重新插入的 元素的影响。
(如果在 s.contains(e) 返回 true 后立即调用 s.add(e),则元素 e 会被重新插入到 set s 中。)
- Set接口
- 1、无序的(不保证顺序)
- 2、不允许重复元素
- HashSet、TreeSet、LinkedHashSet
- 如果要排序,选择treeSet
- 如果不要排序,也不用保正顺序选择HashSet
- 不要排序,要保正顺序,选择LinkedHashSet
LinkedHashSet
- 哈希表和链接列表实现,
- 维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。
TreeSet
- 有序的,基于TreeMap(二叉树数据结构),对象需要比较大小,通过对象比较器来实现,
- 对象比较器还可以用来去除重复元素,如果自定义的数据类,没有实现比较器接口,将无法添加到TreeSet集合中。
- HashSet
- 1、实现原理,基于哈希表(HashMap)实现
- 2、不允许重复,可以有一个NULL元素
- 3、不保证顺序恒久不变
- 4、添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的object对象
- 5、排除重复元素是通过equals来检查对象是否相同
- 6、判断两个对象是否相同,先判断两个对象的hashCode是否相同(如果两个对象的hashCode相同,不一定是同一个对象,如果不同,那一定不是
- 同一个对象),如果不同,则两个对象不是同一个对象,如果相同,还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对比象。
- 7、自定义对象要认为属性值都相同时为同一个对象,有这种需求时,那么我们要重写对象所在类的hashCode和equals方法。
- 小结
- (1)哈希表的存储结构:数组+链表,数组里的每个元素以链表的形式存储
- (2)如何把对象存储到哈希表中,先计算对象的hashCode值,再对数组的长度求余数,来决定对象要存储在数组中的哪个位置
- (3)解决hashSet中的重复值使用的方式是,参考第6点
package com.vince;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
/**
* Set接口
* 1、无序的(不保证顺序)
* 2、不允许重复元素
* HashSet、TreeSet、LinkedHashSet
*
* 如果要排序,选择treeSet
* 如果不要排序,也不用保正顺序选择HashSet
* 不要排序,要保正顺序,选择LinkedHashSet
* @author vince
* @description
*/
public class SetDemo {
/**
* 哈希表和链接列表实现,
* 维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。
*/
private static void linkedHashSet(){
LinkedHashSet<Cat> set = new LinkedHashSet<>();
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",3,1);
set.add(c1);
set.add(c2);
set.add(c3);
set.add(c4);
for(Cat c: set){
System.out.println(c);
}
}
/**
* 有序的,基于TreeMap(二叉树数据结构),对象需要比较大小,通过对象比较器来实现,
* 对象比较器还可以用来去除重复元素,如果自定义的数据类,没有实现比较器接口,将无法添加到TreeSet集合中。
*
*/
private static void treeSet(){
TreeSet<Cat> tree = new TreeSet<>(new CatComparator());
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",3,1);
tree.add(c1);
tree.add(c2);
tree.add(c3);
tree.add(c4);
System.out.println(tree.size());
for(Cat c: tree){
System.out.println(c);
}
}
/**
* HashSet
* 1、实现原理,基于哈希表(HashMap)实现
* 2、不允许重复,可以有一个NULL元素
* 3、不保证顺序恒久不变
* 4、添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的object对象
* 5、排除重复元素是通过equals来检查对象是否相同
* 6、判断两个对象是否相同,先判断两个对象的hashCode是否相同(如果两个对象的hashCode相同,不一定是同一个对象,如果不同,那一定不是
* 同一个对象),如果不同,则两个对象不是同一个对象,如果相同,还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对比象。
* 7、自定义对象要认为属性值都相同时为同一个对象,有这种需求时,那么我们要重写对象所在类的hashCode和equals方法。
*
* 小结
* (1)哈希表的存储结构:数组+链表,数组里的每个元素以链表的形式存储
* (2)如何把对象存储到哈希表中,先计算对象的hashCode值,再对数组的长度求余数,来决定对象要存储在数组中的哪个位置
* (3)解决hashSet中的重复值使用的方式是,参考第6点
*/
private static void hashSet(){
Set<String> set = new HashSet<>();
set.add("飞飞");
set.add("备备");
set.add("亮亮");
set.add("关关");
set.add("曹操");
set.add("亮亮");
System.out.println(set.size());
String[] names = set.toArray(new String[]{});
for(String s: names){
System.out.println(s);
}
Cat c1 = new Cat("miaomiao",5,1);
Cat c2 = new Cat("huahua",2,2);
Cat c3 = new Cat("tom",5,3);
Cat c4 = new Cat("miaomiao",5,1);
Set<Cat> cats = new HashSet<>();
cats.add(c1);
cats.add(c2);
cats.add(c3);
cats.add(c4);
//cats.add(c1);
System.out.println(cats.size());
for(Cat c: cats){
System.out.println(c);
}
System.out.println("c1="+c1.hashCode());
System.out.println("c2="+c2.hashCode());
System.out.println("c3="+c3.hashCode());
System.out.println("c4="+c4.hashCode());
}
public static void main(String[] args) {
// hashSet();
// treeSet();
linkedHashSet();
}
}
Cat.java
package com.vince;
public class Cat {
private String name;
private int age;
private int id;
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 int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Cat [name=" + name + ", age=" + age + ", id=" + id + "]";
}
public Cat(String name, int age, int id) {
super();
this.name = name;
this.age = age;
this.id = id;
}
public Cat() {
super();
// TODO Auto-generated constructor stub
}
@Override
public int hashCode() {
final int prime = 31; //系数 31*1+5 * 31+1 11111
int result = 1;
result = prime * result + age;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Cat other = (Cat) obj;
if (age != other.age)
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
CatComparator TreeSet那个地方使用
package com.vince;
import java.util.Comparator;
public class CatComparator implements Comparator<Cat> {
@Override
public int compare(Cat o1, Cat o2) {
return o1.getAge()-o2.getAge();
}
}
126HashSet判断重复值的原理
不会重复 是Set的一个特点
如上图 添加亮亮 再次添加应该是顶掉了 所以始终就一个亮亮
但是添加Cat猫的对象 注意他们的属性值虽然相等 但是 c1 c4并不相等 它们不是一个对象 所以equals值为false
那HashSet怎么解决这类问题呢
先分析一下HashCode
hashCode深入分析
hashcode() 方法,在object类中定义如下:
public native int hashCode();
hashCode是本地方法,它的实现是根据本地机器相关,当然我们可以在自己写的类中覆盖hashcode()方法,比如String、Integer、Double。。。。等等这些类都是覆盖了hashcode()方法的。
在java的集合中,判断两个对象是否相等的规则是:
(1)判断两个对象的hashCode是否相等
如果不相等,认为两个对象也不相等,结束
如果相等,转入2
(2)判断两个对象用equals运算是否相等
如果不相等,认为两个对象也不相等
如果相等,认为两个对象相等
(equals()是判断两个对象是否相等的关键)
当在Cat里复写HashCode和Equals后
Set存的对象就成了三个了 不会有值重复的了
判断两个对象是否相同,
先判断两个对象的hashCode是否相同(如果两个对象的hashCode相同,不一定是同一个对象,如果不同,那一定不是同一个对象),
如果不同,则两个对象不是同一个对象,
如果相同,还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对比象。
自定义对象要认为属性值都相同时为同一个对象,有这种需求时,那么我们要重写对象所在类的hashCode和equals方法。
哈希表的实现就是数组加链表
127 TreeSet
Tom没有存进去
所以Comparator的作用 一个是排序
一个是重复的值不能存入(Comparator比较的是年龄 认为年龄相等即重复了)