JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet

      一Set接口

      Set接口可以与数学中的集合的概念相对应。Set接口是Collection接口的子接口,Set接口里多个对象之间没有明

显的顺序。具体详细方法请参考API文档(可见身边随时带上API文档有多重要),基本与Collection接口中定义的方法相

同。只是行为不同(Set不允许包含重复元素)。

      Set集合不允许重复元素,是因为Set判断两个对象相同不是使用==运算符,而是根据equals()方法。即两个对象

用equals()方法比较返回true,Set就不能接受两个相等的对象。

      我们来做个测试:

import java.util.*;

public class TestSet{  
    public static void main(String[] args){  
        Set books = new HashSet();  
          
        //添加一个字符串对象  
        books.add(new String("我是测试的对象"));  
          
        //再次添加一个字符串对象,  
        //因为两个字符串对象通过equals方法比较相等,所以添加失败,返回false  
        boolean result = books.add(new String("我是测试的对象"));  
          
        System.out.println(result);  
          
        //下面输出看到集合只有一个元素  
        System.out.println(books);    
    }  
} 

      运行结果:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第1张图片

      说明:程序中,book集合两次添加的字符串对象明显不是一个对象(程序通过new关键字来创建字符串对象),

当使用==运算符判断返回false,使用equals方法比较返回true,所以不能添加到Set集合中,最后只能输出一个元

素。

      Set接口中定义的方法:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第2张图片

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第3张图片

      Set接口中的知识,同时也适用于HashSet、TreeSet等实现类。J2SDK API中所提供的Set接口实现类有

HashSet、TreeSet等,下面我们进行逐一介绍。

       二实现类HashSet

       HashSet(哈希集),是Set接口的一个重要实现类。HashSet使用的是相当复杂的方式来存储元素的,使用

HashSet能够最快的获取集合中的元素,效率非常高(以空间换时间)。会根据hashcode()方法和equals()方法来判

断是否是同一个对象,如果hashcode()方法一样,并且equals()方法返回true,则是同一个对象,不能重复存放。

       HashSet实现类中定义的方法:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第4张图片

       HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。

       HashSet的特点:

       (1)HashSet不是同步的,多个线程访问是需要通过代码保证同步。

       (2)集合元素值可以使null。

       (3)HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方

法返回值也相等。

       实例代码:

import java.util.*;

public class TestHashSet  {  
    public static void main(String[] args){  
        Set books = new HashSet();  
        //分别向books集合中添加2个A对象,2个B对象,2个C对象  
        books.add(new A());  
        books.add(new A());  
        books.add(new B());  
        books.add(new B());  
        books.add(new C());  
        books.add(new C());  
        System.out.println(books);  
    }  
} 

//类A的equals方法总是返回true,但没有重写其hashCode()方法  
class A{  
    public boolean equals(Object obj)  {  
        return true;  
    }  
}  

//类B的hashCode()方法总是返回1,但没有重写其equals()方法  
class B{  
    public int hashCode(){  
        return 1;  
    }  
}  

//类C的hashCode()方法总是返回2,但没有重写其equals()方法  
class C{  
    public int hashCode(){  
        return 2;  
    }  

    public boolean equals(Object obj){  
        return true;  
    }  
}   
  

       运行结果:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第5张图片

       说明:

       (1)Object类提供的toString()方法总是返回该对象实现类的类名+@+hashCode(16进制数)值,所以可以看到上面

程序输出的结果。可以通过重写toString()方法来输出自己希望的形式。

      (2)即使2个A对象通过equals()比较返回true,但HashSet依然把它们当成2个对象;即使2个B对象的hashCode()返

回相同值,但HashSet依然把它们当成2个对象。即如果把一个对象放入HashSet中时,如果重写该对象equals()方

法,也应该重写其hashCode()方法。其规则是:如果2个对象通过equals方法比较返回true时,这两个对象的

hashCode也应该相同。

       知道了上面的方法,我们再来看看下面的实例:

import java.util.*;

public class TestHashSet {
    public static void main(String[] args) {
        Set set = new HashSet();
        //添加两个相同的对象
        Student s1 = new Student(1);
        Student s2 = new Student(1);
        Student s3 = new Student(2);
        set.add(s1);
        set.add(s2);
        set.add(s3);
	//遍历set中的对象
        for (Student s : set) {
            System.out.println(s);
        }
    }
}

class Student{
    int id;

    public Student(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return this.id+"";
    }
	
    @Override
    public int hashCode() {
        return this.id;
    }
	
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student){
            Student  stu = (Student) obj;
            if (stu.id == this.id)
                return true;
        }
        return false;
    }
}

       运行结果:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第6张图片

        正如上例所示,重写了hashCode()和equals()方法来区分同意对象后,就不能存放同以对象了。如果注释这两个

方法,则所有Student对象视为不同对象,都可以存放。

        三实现类TreeSet

        TreeSet也不能存放重复对象,但是TreeSet会自动排序,如果存放的对象不能排序则会报错,所以存放的对象

必须指定排序规则。

       TreeSet实现类定义的方法:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第7张图片

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第8张图片

       排序规则包括自然排序和客户排序。

  (1)自然排序:TreeSet要添加哪个对象就在哪个对象类上面实现java.lang.Comparable接口,并且重写

comparaTo()方法,返回0则表示是同一个对象,否则为不同对象。

       (2)客户排序:建立一个第三方类并实现java.util.Comparator接口。并重写方法。定义集合形式为TreeSet ts =

 new TreeSet(new 第三方类());

      下面一个例子用TreeSet存放自然排序的对象:

import java.util.*;

public class TestTreeSet {
    public static void main(String[] args) {
        Set set = new TreeSet();
        Student1 s1 = new Student1(5);
        Student1 s2 = new Student1(1);
        Student1 s3 = new Student1(2);
        Student1 s4 = new Student1(4);
        Student1 s5 = new Student1(3);
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        for (Student1 s : set) {
            System.out.println(s);
        }
    }
}

class Student1 implements Comparable{
    int id;

    public Student1(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return this.id+"";
    }
	
    @Override
    public int hashCode() {
        return this.id;
    }
	
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student1){
            Student1  stu = (Student1) obj;
            if (stu.id == this.id)
                return true;
        }
        return false;
    }
	
    public int compareTo(Student1 o) {
        return (this.id-o.id);
    }
}

        运行结果:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第9张图片

       下面一个例子用TreeSet存放客户排序的对象:

import java.util.*;

public class TestTreeSet2 {
    public static void main(String[] args) {
        Set set = new TreeSet(new MySort());
        Student2 s1 = new Student2(5);
        Student2 s2 = new Student2(1);
        Student2 s3 = new Student2(2);
        Student2 s4 = new Student2(4);
        Student2 s5 = new Student2(3);
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        for (Student2 s : set) {
            System.out.println(s);
        }
    }
}

class MySort implements java.util.Comparator{
    public int compare(Student2 o1, Student2 o2) {
        return o2.id-o1.id;
    }
}

class Student2{
    int id;

    public Student2(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return this.id+"";
    }
	
    @Override
    public int hashCode() {
        return this.id;
    }
	
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student2){
            Student2  stu = (Student2) obj;
            if (stu.id == this.id)
                return true;
        }
        return false;
    }
}

       运行结果:

JavaSE入门学习36:Java集合框架之Set接口及其实现类HashSet和TreeSet_第10张图片
       说明:由运行结果可以看出,TreeSet并不是根据元素的插入顺序进行排序,而是根据元素实际值来进行排序。

TreeSet采用红黑树的数据结构对元素进行排序,具体排序内容会在后续文章中说明。

      

你可能感兴趣的:(JavaSE,JavaSE由浅入深)