目录
(2)实现Comparable接口,覆写compareTo()方法
2、 HashSet、LinkedHashSet 以及 TreeSet。
TreeSet是一个有序的集合,基于TreeMap实现,支持两种排序方式:自然排序和定制排序。
TreeSet是非同步的,线程不安全的。
如下图:
观察上图:
- TreeSet(NavigableMap
m) { - this.m = m;
- }
- public TreeSet() {
- this(new TreeMap
()); - }
- public TreeSet(Comparator super E> comparator) {
- this(new TreeMap<>(comparator));
- }
- public TreeSet(Collection extends E> c) {
- this();
- addAll(c);
- }
- public TreeSet(SortedSet
s) { - this(s.comparator());
- addAll(s);
- }
通过上面的构造方法,可以看出TreeSet的底层是用TreeMap实现的。在构造方法中会创建一个TreeMap实例,用于存放元素,另外TreeSet是有序的,也提供了制定比较器的构造函数,如果没有提供比较器,则采用key的自然顺序进行比较大小,如果指定的比较器,则采用指定的比较器,进行key值大小的比较。
- //遍历方法,返回m.keyset集合
- public Iterator
iterator() { - return m.navigableKeySet().iterator();
- }
-
- //逆序排序的迭代器
- public Iterator
descendingIterator() { - return m.descendingKeySet().iterator();
- }
-
- /**
- * @since 1.6
- */
- public NavigableSet
descendingSet() { - return new TreeSet<>(m.descendingMap());
- }
-
- //返回 m 包含的键值对的数量
- public int size() {
- return m.size();
- }
-
- //是否为空
- public boolean isEmpty() {
- return m.isEmpty();
- }
-
- //是否包含指定的key
- public boolean contains(Object o) {
- return m.containsKey(o);
- }
-
- //添加元素,调用m.put方法实现
- public boolean add(E e) {
- return m.put(e, PRESENT)==null;
- }
-
- //删除方法,调用m.remove()方法实现
- public boolean remove(Object o) {
- return m.remove(o)==PRESENT;
- }
-
- //清除集合
- public void clear() {
- m.clear();
- }
-
- //将一个集合中的所有元素添加到TreeSet中
- public boolean addAll(Collection extends E> c) {
- // Use linear-time version if applicable
- if (m.size()==0 && c.size() > 0 &&
- c instanceof SortedSet &&
- m instanceof TreeMap) {
- SortedSet extends E> set = (SortedSet extends E>) c;
- TreeMap
map = (TreeMap) m; - Comparator super E> cc = (Comparator super E>) set.comparator();
- Comparator super E> mc = map.comparator();
- if (cc==mc || (cc != null && cc.equals(mc))) {
- map.addAllForTreeSet(set, PRESENT);
- return true;
- }
- }
- return super.addAll(c);
- }
-
- //返回子集合,通过 m.subMap()方法实现
- public NavigableSet
subSet(E fromElement, boolean fromInclusive, - E toElement, boolean toInclusive) {
- return new TreeSet<>(m.subMap(fromElement, fromInclusive,
- toElement, toInclusive));
- }
-
- //返回set的头部
- public NavigableSet
headSet(E toElement, boolean inclusive) { - return new TreeSet<>(m.headMap(toElement, inclusive));
- }
-
- //返回尾部
- public NavigableSet
tailSet(E fromElement, boolean inclusive) { - return new TreeSet<>(m.tailMap(fromElement, inclusive));
- }
-
- //返回子Set
- public SortedSet
subSet(E fromElement, E toElement) { - return subSet(fromElement, true, toElement, false);
- }
-
- //返回set的头部
- public SortedSet
headSet(E toElement) { - return headSet(toElement, false);
- }
-
- //返回set的尾部
- public SortedSet
tailSet(E fromElement) { - return tailSet(fromElement, true);
- }
- //返回m使用的比较器
- public Comparator super E> comparator() {
- return m.comparator();
- }
-
- //返回第一个元素
- public E first() {
- return m.firstKey();
- }
- //返回最后一个元素
- public E last() {
- return m.lastKey();
- }
-
- //返回set中小于e的最大的元素
- public E lower(E e) {
- return m.lowerKey(e);
- }
-
- //返回set中小于/等于e的最大元素
- public E floor(E e) {
- return m.floorKey(e);
- }
-
- //返回set中大于/等于e的最大元素
- public E ceiling(E e) {
- return m.ceilingKey(e);
- }
-
- //返回set中大于e的最小元素
- public E higher(E e) {
- return m.higherKey(e);
- }
-
- //获取TreeSet中第一个元素,并从Set中删除该元素
- public E pollFirst() {
- Map.Entry
e = m.pollFirstEntry(); - return (e == null) ? null : e.getKey();
- }
-
- //获取TreeSet中最后一个元素,并从Set中删除该元素
- public E pollLast() {
- Map.Entry
e = m.pollLastEntry(); - return (e == null) ? null : e.getKey();
- }
-
- //克隆方法
- public Object clone() {
- TreeSet
clone = null; - try {
- clone = (TreeSet
) super.clone(); - } catch (CloneNotSupportedException e) {
- throw new InternalError();
- }
-
- clone.m = new TreeMap<>(m);
- return clone;
- }
-
- //将对象写入到输出流中。
- private void writeObject(java.io.ObjectOutputStream s)
- throws java.io.IOException {
- // Write out any hidden stuff
- s.defaultWriteObject();
-
- // Write out Comparator
- s.writeObject(m.comparator());
-
- // Write out size
- s.writeInt(m.size());
-
- // Write out all elements in the proper order.
- for (E e : m.keySet())
- s.writeObject(e);
- }
-
- //从输入流中读取对象的信息
- private void readObject(java.io.ObjectInputStream s)
- throws java.io.IOException, ClassNotFoundException {
- // Read in any hidden stuff
- s.defaultReadObject();
-
- // Read in Comparator
- Comparator super E> c = (Comparator super E>) s.readObject();
-
- // Create backing TreeMap
- TreeMap
tm; - if (c==null)
- tm = new TreeMap<>();
- else
- tm = new TreeMap<>(c);
- m = tm;
-
- // Read in size
- int size = s.readInt();
-
- tm.readTreeSet(size, s, PRESENT);
- }
-
- import java.util.*;
-
- class Student{
- private int id;
- private String name;
- private int age;
-
- public Student(int id, String name, int age) {
- this.id = id;
- this.name = name;
- this.age = age;
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = 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;
- }
-
- @Override
- public String toString() {
- return "Student{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
- class MyComparator implements Comparator{
-
- @Override
- public int compare(Object o1, Object o2) {
- Student s1 = (Student) o1;
- Student s2 = (Student) o2;
- return s1.getAge() - s2.getAge();
- }
- }
- public class Main {
- public static void main(String[] args) {
- TreeSet treeSet = new TreeSet(new MyComparator());
- treeSet.add(new Student(1, "tom", 23));
- treeSet.add(new Student(2, "Jerry", 20));
- treeSet.add(new Student(3, "Jack", 17));
- treeSet.add(new Student(4, "Marry", 54));
- treeSet.add(new Student(5, "Baby", 8));
- Iterator iterator = treeSet.iterator();
- while(iterator.hasNext()){
- System.out.println(iterator.next());
- }
-
- }
- }
- import java.util.*;
-
- class Student implements Comparable{
- private int id;
- private String name;
- private int age;
-
- public Student(int id, String name, int age) {
- this.id = id;
- this.name = name;
- this.age = age;
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = 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;
- }
-
- @Override
- public String toString() {
- return "Student{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
-
- @Override
- public int compareTo(Object o) {
- if(!(o instanceof Student)){
- throw new RuntimeException("对象有问题");
- }
- Student s = (Student) o;
- if(this.age > s.age){
- return -1;
- }else{
- return 1;
- }
- }
- }
-
- public class Main {
- public static void main(String[] args) {
- TreeSet treeSet = new TreeSet();
- treeSet.add(new Student(1, "tom", 23));
- treeSet.add(new Student(2, "Jerry", 20));
- treeSet.add(new Student(3, "Jack", 17));
- treeSet.add(new Student(4, "Marry", 54));
- treeSet.add(new Student(5, "Baby", 8));
- Iterator iterator = treeSet.iterator();
- while(iterator.hasNext()){
- System.out.println(iterator.next());
- }
-
- }
- }
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
TreeSet集合对象的加入过程:
TreeSet的底层是通过二叉树来完成存储的,无序的集合
当我们将一个对象加入treeset中,treeset会将第一个对象作为根对象,然后调用对象的compareTo方法拿第二个对象和第一个比较,当返回值等于0时,说明2个对象内容相等,treeset就不把第二个对象加入集合。返回>1时,说明第二个对象大于第一个对象,将第二个对象放在右边,返回-1时,则将第二个对象放在左边,依次类推 。
HashSet集合对象的加入过程:
hashset底层是hash值的地址,它里面存的对象是无序的。
第一个对象进入集合时,hashset会调用object类的hashcode根据对象在堆内存里的地址调用对象重写的hashcode计算出一个hash值,然后第一个对象就进入hashset集合中的任意一个位置。
第二个对象开始进入集合,hashset先根据第二个对象在堆内存的地址调用对象的计算出一个hash值,如果第二个对象和第一个对象在堆内存里的地址是相同的,那么得到的hash值也是相同的,直接返回true,hash得到true后就不把第二个元素加入集合(这段是hash源码程序中的操作)。如果第二个对象和第一个对象在堆内存里地址是不同的,这时hashset类会先调用自己的方法遍历集合中的元素,当遍历到某个元素时,调用对象的equals方法,如果相等,返回true,则说明这两个对象的内容是相同的,hashset得到true后不会把第二个对象加入集合。