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(); } }
二、LinkedHashSet
有序的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)); }
