java集合框架总结三--Set接口及其子类

Set接口

Set与Collection的结构基本上完全一样,不同在于无序,不能重复

Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说两个对象用equals方法比较返回true,Set就不会接受这两个对象。

/**
 * Set演示
 * 2014-4-6
 */
import java.util.HashSet;
import java.util.Set;
public class SetDemo
{
    public static void main(String[] args) 
    {
        Set s=new HashSet();
        s.add("123");
        //添加两个相同的元素,会返回false
        boolean m=s.add("123");
        System.out.println(m);
        System.out.println(s);
    }
}

程序运行结果:

false
[123]

HashSet

内部结构为哈希表

元素无序,不是同步的(注意线程安全问题),集合元素值可以为null

当向 HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该值来决定该对象在HashSet中的存储位置。如果有两个元素通过equals方法比较返回true,但它们的hashCode方法返回值不相等,HashSet将会把它们存储在不同的位置。也就是说HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode方法返回值也相等。

import java.util.HashSet;
/**
 * HashSet类判断两元素相等实例
 * 2014-4-6
 * @author Administrator
 *
 */
public class HashSetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {

        HashSet set=new HashSet();
        set.add(new A());
        set.add(new A());
        set.add(new B());
        set.add(new B());
        set.add(new C());
        set.add(new C());
        System.out.println(set);

    }
}
class A{
    @Override
    public boolean equals(Object obj){
        return true;
    }
}

class B{
    @Override
    public int hashCode(){
        return 1;
    }
}

class C{
    @Override
    public int hashCode(){
        return 2;
    }
    public boolean equals(Object obj){ 
        return true;
    }
}

程序运行结果:

[B@1, B@1, C@2, A@4f1d0d, A@18a992f]

Object类提供的toString方法总是返回该对象实现类的类名+@+hashCode(16进制数)值,所以可以看到上面程序输出的结果。可以通过重写toString方法来输出自己希望的形式。

即使2个A对象通过equals比较返回true,但HashSet依然把它们当成2个对象;即使2个B对象的hashCode()返回相同值,但HashSet依然把它们当成2个对象。即如果把一个对象放入HashSet中时,如果重写该对象equals()方法,也应该重写其hashCode()方法。其规则是:如果2个对象通过equals方法比较返回true时,这两个对象的hashCode也应该相同。

TreeSet:

以对集合中的元素进行排序。是不同步的

TreeSet支持两种排序方法:自然排序和定制排序。默认情况下TreeSet采用自然排序

自然排序

TreeSet会调用集合元素的comparaTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这就是自然排序。

Java提供了一个Comparable接口,该接口中定义了一个comparaTo(Object obj)方法,返回一个整数值,实现了该接口的类的对象就可以比较大小。如:obj1.comparaTo(obj2),如果该方法返回0,则表明这两个对象相等;返回正整数,则表明obj1大于obj2;返回一个负整数,则表明obj1小于obj2。

如果试图把一个对象添加进TreeSet时,则该对象的类必须实现CompareTo接口,否则程序将会出现异常

import java.util.TreeSet;

/**
 * TreeSetTreeSet添加两个相同类型的对象错误示范
 * 2014-4-7
 * @author Administrator
 *
 */
public class TreeSetDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TreeSet set=new TreeSet();
        set.add(new Error());
        //添加两个相同元素,会引发java.lang.ClassCastException异常
        set.add(new Error());
        
    }
}

    class Error{
        
    }

向TreeSet集合中添加元素时,只有第一个元素可以无需实现CompareTo接口,后面添加的所有元素都必须实现CompareTo接口。另外向TreeSet中添加的应该是同一个类的对象,不然不好比较,否则也会引发ClassCastException异常。

对于TreeSet集合而言,它判断两个对象不相等的标准是:两个对象通过equals方法比较返回false,或通过compareTo比较没有返回0,即使两个对象是同一个对象,TreeSet也会把他们当成两个对象处理。

import java.util.TreeSet;

/**
 * TreeSet添加两个相同类型的对象示范
 * 2014-4-7
 * @author Administrator
 *
 */
public class TreeSetDemo2 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TreeSet set=new TreeSet();
        Z z=new Z(10);
        set.add(z);
        boolean flag=set.add(z);
        System.out.println(flag);
        System.out.println(set);

    }
}

class Z implements Comparable{
    int age;
    public Z(int age){
        this.age=age;
    }
    public boolean Equals(Object obj){
        return false;
    }
    public int compareTo(Object o) {
        // TODO Auto-generated method stub
        return 1;
    }
}

定制排序

使用定制排序时,TreeSet对集合元素排序时不管集合元素本身大小,而是由Comparator对象负责集合元素的排序规则。