Set集合之HashSet类、LinkedHashSet类、TreeSet类和EnumSet类

Set集合之HashSet类、LinkedHashSet类、TreeSet类和EnumSet类

(一)HashSet类

  • 前言:HashSet是Set接口的典型实现,绝大多数时候使用Set集合就是使用这个实现类。HashSet按照Hash算法来存储集合中元素,因此具有很好的存取和查找性能。至于HashCode值如何计算,Hash算法的原理以及HashSet的在内存中存储实现读者可以看我这篇博文:equals和HashCode深入理解以及Hash算法原理。
      在这里我想给读者提醒一下几个对HashSet类使用的小建议:
      
  • HashSet的存储原理是先判断对象的HashCode()值,找到存储区域存入但是当HashCode值相同时(我的理解是HashCode值在计算过程中不小心冲突了),equals返回false,则这时候系统会在这个位置采用链式结构来保存多个对象,这时候会导致性能下降。(其实我们这里讲的对象是指对象引用,容器类或者说集合类添加进去的都是同一个引用类型的对象引用,集合中的元素是对象实例化后的对象引用,在内存中保存的是地址)
  • 内存泄露问题:当程序把可变对象添加到HashSet中后,尽量不要去修改该集合元素中参与计算hashCode()、equals()的实例变量,这样将导致对象hashCode值改变,要去访问该对象时找不到。

  • 以下是HashSet使用例子,Set集合存储自定义类时,建议该类重写hashCode和equals方法,这是保证元素唯一性的前提,一般还会重写toString方法。

Person.java
package bean;
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 ;
    Person other = (Person) 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;
  }
  @Override
  public String toString() {
    return "Person [name=" + name + ", age=" + age + "]" ;
  }
}

HashSetDemo.java

package Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import bean.Person;
public class HashSetDemo {
  public static void main(String[] args) {
    // Set集合保证元素唯一性。
    Set<String> set = new HashSet<String>();
    set.add("Java1");
    set.add("Java2");
    set.add("Java1");
    set.add("Java1");
    set.add("Java2");
    //用迭代器对Set集合进行遍历
    for (Iterator<String> it = set.iterator(); it.hasNext();) {
      System.out.println( it.next());
    }
    System.out.println( "-------------------");
    // Set集合存储自定义类时,建议该类重写hashCode和equals方法,这是保证元素唯一性的前提,一般还会重写toString方法。
    Set<Person> setObj = new HashSet<Person>();
    setObj.add(new Person( "Jacob", 25));
    setObj.add(new Person( "Meteor", 23));
    setObj.add(new Person( "Tom", 26));
    setObj.add(new Person( "Llllin", 27));
    setObj.add(new Person( "Jacob", 24));
    for (Iterator<Person> it = setObj.iterator(); it.hasNext();) {
      System.out.println( it.next());
    }
  }
}

运行结果
Java2
java1

Person [name=Jacob, age=25]
Person [name=Tom, age=26]
Person [name=Jacob, age=24]
Person [name=Meteor, age=23]
Person [name=Llllin, age=27]

(二)LinkedHashSet集合

  • HashSet类有一个子类LinkedHashSet,LinkedHashSet集合也是根据hashCode值来决定元素的存储位置,但它同时使用链表来维护元素的次序。
  • LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但是在迭代访问Set里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。
package collection;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class Set_LinkedHashSet {

  public static void main(String[] args) {
    /* * LinkedHashSet可以保持元素存取顺序 */
    Set<String> set1 = new HashSet<String>();
    Set<String> set2 = new LinkedHashSet<String>();
    init(set1 );
    init(set2 );

    System.out.println( "HashSet:");
    for (Iterator<String> it = set1.iterator(); it.hasNext();) {
      System.out.println( it.next());
    }
    System.out.println( "LinkedHashSet:");
    for (Iterator<String> it = set2.iterator(); it.hasNext();) {
      System.out.println( it.next());
    }
  }

  public static void init(Set<String> set) {
    set.add("Java1");
    set.add("Java2");
    set.add("Java3");
    set.add("Java4");
    set.add("Java5");
  }
}

运行结果
HashSet:
Java2
Java3
Java4
Java5
Java1
LinkedHashSet:
Java1
Java2
Java3
Java4
Java5

(三)TreeSet集合

  • TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。从这句话中我们可以看出,添加到TreeSet中的元素(对象的实例)必须实现了Comparable接口或者传入比较器Comparator,具体可以看我们这篇博文[Comparable和Comparator].(http://blog.csdn.net/qq_21688757/article/details/53084282)
  • 使用自然排序和比较器加入TreeSet集合进行排序:
package bean;

public class Person implements Comparable<Person> {

  private String name;
  private int age;

  public Person(String name, int age) {
    super();
    this.name = name;
    this.age = age;
  }

  public Person() {
    super();
  }

  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 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 ;
    Person other = (Person) 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;
  }

  @Override
  public String toString() {
    return "Person [name=" + name + ", age=" + age + "]" ;
  }
 //先按字符串默认排列,若相同再按年龄排列
  @Override
  public int compareTo(Person o) {
    int margin = this.name.compareTo( o. name);
    return margin == 0 ? this. age - o. age : margin;
  }
}

ComparatorByAge.java
package comparator;

import java.util.Comparator;

import bean.Person;

public class ComparatorByAge implements Comparator<Person> {
     //先按年龄升序排列,若相同在按字符串排列
     @Override
     public int compare(Person o1, Person o2) {
           int margin = o1.getAge() - o2.getAge();
           return margin == 0 ? o1 .compareTo(o2 ) : margin ;
     }
}
  • TreeSetDemo.java
package collection.set;

import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import bean.Person;
import comparator.ComparatorByAge;
import comparator.ComparatorByLength;

public class TreeSetDemo {

  public static void main(String[] args) {
    // 使用自然排序将字符串加入TreeSet集合
    System.out.println( "字符串(自然排序):" );
    Set<String> set = new TreeSet<String>();
    set.add("java");
    set.add("linkedhashset");
    set.add("awesome");
    set.add("zzz");
    set.add("treeset");

    // 元素在添加的时候就已经间接调用compareTo方法进行排序
    for (Object object : set) {
      System.out.println( object);
    }

    // 使用比较器将字符串按由长至短加入TreeSet集合
    System.out.println( "字符串(比较器):" );
    Set<String> setComparatorByLength =
        new TreeSet<String>(Collections. reverseOrder(new ComparatorByLength()));
    setComparatorByLength.add( "java");
    setComparatorByLength.add( "linkedhashset");
    setComparatorByLength.add( "awesome");
    setComparatorByLength.add( "zzz");
    setComparatorByLength.add( "treeset");

    for (String string : setComparatorByLength) {
      System.out.println( string);
    }

    // 使用自然排序将自定义类加入TreeSet集合
    System.out.println( "自定义类(自然排序):" );
    Set<Person> setObj = new TreeSet<Person>();
    setObj.add(new Person( "jacob", 25));
    setObj.add(new Person( "meteor", 23));
    setObj.add(new Person( "kitty", 22));
    setObj.add(new Person( "tom", 26));
    for (Iterator<Person> it = setObj.iterator(); it.hasNext();) {
      System.out.println( it.next());
    }

    // 使用比较器将自定义类加入TreeSet集合
    System.out.println( "自定义类(比较器):" );
    TreeSet<Person> setObjComparatorByAge = new TreeSet<Person>(new ComparatorByAge());
    setObjComparatorByAge.add( new Person( "jacob", 25));
    setObjComparatorByAge.add( new Person( "meteor", 23));
    setObjComparatorByAge.add( new Person( "kitty", 22));
    setObjComparatorByAge.add( new Person( "tom", 26));
    for (Iterator<Person> it = setObjComparatorByAge.iterator(); it .hasNext();) {
      System.out.println( it.next());
    }
  }
}

运行结果
字符串(自然排序):
awesome
java
linkedhashset
treeset
zzz
字符串(比较器):
linkedhashset
treeset
awesome
java
zzz
自定义类(自然排序):
Person [name=jacob, age=25]
Person [name=kitty, age=22]
Person [name=meteor, age=23]
Person [name=tom, age=26]
自定义类(比较器):
Person [name=kitty, age=22]
Person [name=meteor, age=23]
Person [name=jacob, age=25]
Person [name=tom, age=26]

你可能感兴趣的:(HashCode,存储,hashset,Set集合,LinkedH)