五、集合——3-Set集合

3-Set集合

  Set集合与Collection集合基本相同,没有提供额外的方法。

  Set集合中不许包含相同的元素,如果试图把两个相同的元素添加到同一个Set中,添加操作会失败add()方法将返回false,新元素也不会被添加。(适用于HashSet、LinkedHashSet、TreeSet)

1.HashSet

(1)HashSet按照哈希算法存储集合中的元素,具有很好的存取和查找性能;

(2)HashSet的特征:

  1)不保证元素的排列顺序,可能和添加顺序不同,顺序也可能发生改变;

  2)HashSet不是同步的,当多个线程访问同一个HashSet时,必须通过代码保证其同步;

  3)集合元素值可以为null;

(3)HashSet判断两个元素是否相同的标准:

  ①元素通过equals()方法返回true;

  ②元素的hashCode()方法的返回值相同;

(4)当把对象放入HashSet中时,如果需要重写该对象对应类的equals()方法,那么也应该重写其hashCode()方法,其规则是:当两个对象通过equals()方法比较返回true时,两个对象的hashCode()方法的返回值也相同;

(5)当程序把可变对象添加到HashSet集合中时,尽量不要去修改该集合元素中参与计算hashCode()、equals()的实例变量,否则将会导致HashSet无法正确操作集合元素。

2.LinkedHashSet

(1)LinkedHashSet是HashSet的子类;

(2)LinkedHashSet同样根据hashcode值来确定元素的存储位置,同时也是用链表来维护元素的次序;

(3)由于LinkedHashSet是用了链表来维护元素次序,所以元素的顺序与元素添加时的顺序是一致的,但是LinkedHashSet同样不能够存放相同的元素。

3.TreeSet

(1)TreeSet是SortedSet接口的实现类,TreeSet可以确保元素处于有序的状态(这里的有序状态是指按照一定的规则对元素进行排序);

(2)TreeSet的通用方法:

import java.util.TreeSet;

//TreeSet的通用方法
public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet nums = new TreeSet();
        //看似是放入了基本类型的元素,但实际上这里有一个自动装箱的过程
        //在集合中实际的元素是Integer
        nums.add(1);
        nums.add(5);
        nums.add(3);
        nums.add(2);
        nums.add(6);
        //输出元素
        System.out.println(nums);    //已完成排序
        //输出集合第一个元素
        System.out.println(nums.first());
        //输出集合的最后一个元素
        System.out.println(nums.last());
        //返回小于4的子集
        System.out.println(nums.headSet(4));
        //返回大于5的子集
        System.out.println(nums.tailSet(5));
        //返回大于等于3小于5的子集
        System.out.println(nums.subSet(3, 5));
    }
}

 

(3)自然排序

1)自然排序,就是TreeSet调用集合元素的compareTo(Object obj)方法来比较元素之间的大小,然后将元素按照升序排列;

2)Comparable接口:

  该接口中定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的类对象就可以比较大小,obj1.compareTo(obj2):

  当返回值为0,obj1和obj2相等

  当返回值为正整数,obj1>obj2

  当返回值为负整数,obj1<obj2

3)已经实现了Comparable接口的常用类:

  ①基本数据类型的包装类;

  ②String;

  ③Date、Time;

4)向TreeSet中添加的元素必须实现Comparable接口(当只有一个元素时,可以不用,但这没有任何意义);

5)TreeSet若要正常工作需要存放同一个类型的元素;

6)TreeSet判断两个元素是否相等:compareTo()方法的返回值是否为0,为0则相同;

7)当需要把一个对象放入TreeSet中,重写该对象对应类的equals()方法时,应该保证此方法与compareTo()方法有一致的结果;

8)尽量不要修改放入TreeSet集合中的可变对象元素;

9)自然排序的使用:

Student类:

//需要放入TreeSet中,所以应该实现Comparable接口
public class Student implements Comparable{
    private String name;
    private int age;
    public Student(){
        
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }
    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;
    }
    //实现Comparable接口必须实现compareTo()方法
    @Override
    public int compareTo(Object o) {
        // TODO Auto-generated method stub
        Student stu = (Student) o;
        //return 0 this=stu
        //return>0 this>stu
        //return<0 this<stu
        return this.age - stu.age;
    }
    //重写toString方法
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "["+this.name+"]";
    }
}

 

 

 

CompareToTest类:

import java.util.TreeSet;

public class CompareToTest {
    public static void main(String[] args) {
        TreeSet set = new TreeSet();
        Student a = new Student("A",18);
        Student b = new Student("B",13);
        Student c = new Student("C",15);
        Student d = new Student("D",11);
        //添加元素
        set.add(a);
        set.add(b);
        set.add(c);
        set.add(d);
        System.out.println(set);
    }
}

 

(4)定制排序

1)自定义的排序方式,如降序排序等,通过接口Comparator接口实现;

2)在Comparator接口中包含一个compare(T o1,T o2)方法,它的返回值是一个int:

  当返回值为0时,o1=o2;

  当返回值大于0时,o1>o2;

  当返回值小于0时,o1<o2;

3)使用定制排序仍然需要保证TreeSet中为同一类型的元素;

4)定制排序的使用:

import java.util.Comparator;
import java.util.TreeSet;


public class ComparatorTest {
    public static void main(String[] args) {
        //使用定制排序
        //需要使用Comparator接口
        //并与TreeSet建立关联
        TreeSet set = new TreeSet(new Comparator(){

            @Override
            public int compare(Object o1, Object o2) {
                // TODO Auto-generated method stub
                Student stu1 = (Student)o1;
                Student stu2 = (Student)o2;
                return stu1.getAge()>stu2.getAge()?-1:stu1.getAge()<stu2.getAge()?1:0;
            }});
    }
}

 

 

 

 

 

4.EnumSet

(1)EnumSet是一个专门为枚举类设计的集合类,在EnumSet中所有元素必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式的指定;

(2)EnumSet集合也是有序的,以枚举值在Enum类内部的定义顺序来决定集合元素的顺序;

(3)EnumSet不允许添加null元素,但是可以判断是否含有null,也可以视图删除null;

(4)使用EnumSet保存枚举类的多个枚举值:

import java.util.EnumSet;

enum Season{
    SPRING,SUMMER,FALL,WINTER
}
public class EnumSetTest1 {
    public static void main(String[] args) {
        //创建一个EnumSet,集合元素是Enum类Season的全部枚举值
        EnumSet es1 = EnumSet.allOf(Season.class);
        System.out.println(es1);
        //创建一个EnumSet空集合,指定集合元素为Season类的枚举值
        EnumSet es2 = EnumSet.noneOf(Season.class);
        System.out.println(es2);
        //为es2添加元素
        //集合中的顺序为枚举值的顺序
        es2.add(Season.FALL);
        es2.add(Season.SUMMER);
        System.out.println(es2);
        //以指定枚举值创建EnumSet集合
        EnumSet es3 = EnumSet.of(Season.FALL,Season.SUMMER);
        System.out.println(es3);
    }
}

 

 

 

(5)EnumSet的其他用法:

import java.util.Collection;
import java.util.EnumSet;
import java.util.HashSet;
enum Season2{
    SPRING,SUMMER,FALL,WINTER
}
public class EnumSetTest2 {
    public static void main(String[] args) {
        Collection set = new HashSet();
        set.clear();
        set.add(Season2.FALL);
        set.add(Season2.SPRING);
        set.add(Season2.WINTER);
        System.out.println(set);
        //复制Collection中的所有元素来创建EnumSet集合
        EnumSet es = EnumSet.copyOf(set);
        System.out.println(es);
    }
}

 

 

 

5.Set各实现类的性能分析

(1)HashSet的性能比TreeSet的性能要好,因为TreeSet使用红黑树算法维持元素的顺序,在需要保持排序方式的Set时才选用TreeSet;

(2)遍历LinkedHashSet的性能要优于遍历HashSet的性能;

(3)EnumSet是所有Set中性能最好的,但它只能保存同一个枚举类的枚举值作为元素;

(4)所有的Set集合都是非线程安全的,当需要有多个线程同时访问同一个Set时,需要手动实现Set集合的线程同步,可以使用工具类Collections的synchronizedSet方法来包装该Set集合,例如:

  SrotedSet s = Collections.synchronizedSet(new TreeSet());

posted @ 2017-08-02 19:56  丶theDawn  阅读(169)  评论(0编辑  收藏  举报