Set集合类要求集合中不存在相同的元素。
一、HashSet
1、核心结构
private transient HashMap<E,Object> map; //内部采用HashMap实现,key为保存的元素的hash值,value为PRESENT.
private static final Object PRESENT = new Object(); //value值
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
public HashSet() {
map = new HashMap<>();
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
HashSet(int initialCapacity, float loadFactor, boolean dummy) {
map = new LinkedHashMap<>(initialCapacity, loadFactor); //LinkedHashSet
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
public int size() {
return map.size();
}
public void clear() {
map.clear();
}
public int size() {
return map.size();
}
}
有序的HashSet集合,保存了元素的添加顺序.
public class LinkedHashSet<E>
extends HashSet<E> implements Set<E>, Cloneable, java.io.Serializable {
public LinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor, true);//LinkedHashMap实现
}
public LinkedHashSet(int initialCapacity) {
super(initialCapacity, .75f, true); //LinkedHashMap实现
}
public LinkedHashSet() {
super(16, .75f, true); //LinkedHashMap实现
}
}
三、TreeSet
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
{
private static final Object PRESENT = new Object();
public TreeSet() {
this(new TreeMap<E,Object>()); //内部使用TreeMap实现
}
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator)); //内部使用TreeMap实现
}
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
}
TreeSet存储对象的时候, 可以排序, 但是需要指定排序的算法,默认采用自然顺序排序。
自然顺序排序
//自然顺序
SortedSet<String> set3=new TreeSet<String>();
set3.add("D");
set3.add("B");
set3.add("D");
set3.add("C");
set3.add("A");
set3.add("C");
System.out.println(set3);//ABCD
set3=new TreeSet<String>();
set3.add("1");
set3.add("4");
set3.add("2");
set3.add("3");
System.out.println(set3);//1234
自定义类的对象排序
1、类实现Comparable接口
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person per) {//应该将所有属性都进行比较
if(this.age>per.age){
return 1;
}
if(this.age<per.age){
return -1;
}else{
return this.name.compareTo(per.name);//调用String中的compareTo()方法
}
}
}
2、自定义Comparator,通过TreeSet的构造函数传入
TreeSet<Person> treeSet = new TreeSet<Person>(comparator);
Comparator comparator = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
if (o1.age > o2.age) {
return 1;
} else if (o1.age < o2.age) {
return -1;
}
return o1.name.compareTo(o2.name);//调用String中的compareTo()方法
};
在使用TreeSet存储对象的时候, add()方法内部就会自动调用compareTo()方法进行比较, 根据比较结果使用二叉树形式进行存储。
四、Set保存类对象
如果是类对象,需要重写该类的hashCode()和equals()方法,这样Set集合才能正常去重
public class Person {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
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;
Person2 other = (Person2) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
//测试
Set<Person> set=new HashSet<Person>();
set.add(new Person("张三", 21));
set.add(new Person("李四", 22));
set.add(new Person("王五", 23));
set.add(new Person("王五", 23)); //重复
set.add(new Person("赵六", 24));
set.add(new Person("赵六二", 24));
}