「 深刻淺出 」集合Set


系列文章
java

「 深刻淺出 」集合List
安全

「 深刻淺出 」java集合Collection和Map
ide


Set繼承自Collection接口,不能包含有重複元素。本篇文章主要講Set中三個比較重要的實現類:HashSet、TreeSet。性能

Set

Set是一個存儲無序且不重複元素的集合。
在使用Set集合的時候,應該注意兩點測試

  • 爲Set集合裏的元素的實現類重寫equals()和hashCode()方法()this

  • 若傳入重複的元素,重複元素會被忽略(能夠用於作集合的去重)spa

擴展
判斷兩個元素相等的標準:兩個對象經過equals()方法比較相等,而且兩個對象的hashCode()方法返回值也相等。線程

HashSet

HashSet是Set接口的典型實現,是哈希表結構,主要利用HashMap的key來存儲元素,計算插入元素的hashCode來獲取元素在集合中的位置,所以具備很好的存取和查找性能。code

主要特色
1.不容許出現重複元素
2.存儲的元素是無序的
3.不是同步的,若是多個線程同時訪問一個HashSet,則必須經過代碼來保證其同步。
4.集合元素值能夠是null。對象

HashSet基本操做
public class HashSetTest {
        public static void main(String[] agrs){
            //建立HashSet集合:
            Set<String> hashSet = new HashSet<String>();
            System.out.println("HashSet初始容量大小:"+hashSet.size());

            //元素添加:
            hashSet.add("my");
            hashSet.add("name");
            hashSet.add("is");
            hashSet.add("ken");
            hashSet.add("hello");
            hashSet.add("everyone");
            System.out.println("HashSet容量大小:"+hashSet.size());

            //迭代器遍歷:
            Iterator<String> iterator = hashSet.iterator();
            while (iterator.hasNext()){
                String str = iterator.next();
                System.out.print(str+" ");
            }
            System.out.print("\n");
            //元素刪除:
            hashSet.remove("ken");
            System.out.println("HashSet元素大小:" + hashSet.size());
            hashSet.clear();
            System.out.println("HashSet元素大小:" + hashSet.size());

            //集合判斷:
            boolean isEmpty = hashSet.isEmpty();
            System.out.println("HashSet是否爲空:" + isEmpty);
            boolean isContains = hashSet.contains("hello");
            System.out.println("HashSet是否爲空:" + isContains);
        }
}
//out:
HashSet初始容量大小:0
HashSet容量大小:6
ken everyone name is hello my 
HashSet元素大小:5
HashSet元素大小:0
HashSet是否爲空:true
HashSet是否爲空:false

細節注意事項可看如下例子:

//重寫類A的equals方法老是返回true,但沒有重寫其hashCode()方法。
//不能保證當前對象是HashSet中的惟一對象
class A {
    @Override
    public boolean equals(Object obj
{
        return true;
    }
}

//重寫類B的hashCode()方法老是返回1,但沒有重寫其equals()方法。
//不能保證當前對象是HashSet中的惟一對象
class B {
    @Override
    public int hashCode() 
{
        return 1;
    }
}

//重寫重寫類C的hashCode()方法老是返回2,且有重寫其equals()方法
class C {
    @Override
    public int hashCode() 
{
        return 2;
    }

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

public class HashSetTest {
    public static void main(String[] args{
        HashSet books = new HashSet();
        //分別向books集合中添加兩個A對象,兩個B對象,兩個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);
    }
}
//out
[B@1, B@1, C@2, A@3bc257, A@785d65]

能夠看出,只有當同時重寫了equals方法和hashCode方法時,才能按照本身的意圖判斷對象是否相等,不然均斷定爲不相等,可加入Set集合中。

TreeSet

與HashSet集合相似,TreeSet也是基於Map來實現,其底層結構爲紅黑樹(特殊的二叉查找樹)
與HashSet不一樣的是,TreeSet具備排序功能,分爲天然排序(123456)和自定義排序兩類,默認是天然排序

具備以下特色:

  • 對插入的元素進行排序,是一個有序的集合(主要與HashSet的區別)

  • 底層使用紅黑樹結構,而不是哈希表結構

  • 容許插入Null值

  • 不容許插入重複元素

  • 線程不安全

TreeSet基本操做
public class TreeSetTest {
     public static void main(String[] agrs){
        TreeSet<String> treeSet = new TreeSet<String>();
        System.out.println("TreeSet初始化容量大小:"+treeSet.size());

        //元素添加:
        treeSet.add("my");
        treeSet.add("name");
        treeSet.add("ken");
        treeSet.add("hello");
        treeSet.add("world");
        treeSet.add("1");
        treeSet.add("2");
        treeSet.add("3");
        System.out.println("TreeSet容量大小:" + treeSet.size());
        System.out.println("TreeSet元素順序爲:" + treeSet.toString());


        System.out.println("遍歷元素升序:");
        //迭代器遍歷:升序
        Iterator<String> iteratorAesc = treeSet.iterator();
        while(iteratorAesc.hasNext()){
            String str = iteratorAesc.next();
            System.out.print(str + " ");
        }
        System.out.println("\n");
        System.out.println("遍歷元素降序:");
        //迭代器遍歷:降序
        Iterator<String> iteratorDesc = treeSet.descendingIterator();
        while(iteratorDesc.hasNext()){
            String str = iteratorDesc.next();
            System.out.print(str + " ");
        }
        System.out.println("\n");
        //元素獲取:實現NavigableSet接口
        String firstEle = treeSet.first();//獲取TreeSet頭節點:
        System.out.println("TreeSet頭節點爲:" + firstEle);

        // 獲取指定元素以前的全部元素集合:(不包含指定元素)
        SortedSet<String> headSet = treeSet.headSet("ken");
        System.out.println("ken節點以前的元素爲:"+headSet.toString());

        //獲取給定元素之間的集合:(包含頭,不包含尾)
        SortedSet subSet = treeSet.subSet("1","hello");
        System.out.println("1--hello之間節點元素爲:"+subSet.toString());

        //集合判斷:
        boolean isEmpty = treeSet.isEmpty();
        System.out.println("TreeSet是否爲空:"+isEmpty);
        boolean isContain = treeSet.contains("who");
        System.out.println("TreeSet是否包含who元素:"+isContain);

        //元素刪除:
        boolean kenRemove = treeSet.remove("ken");
        System.out.println("ken元素是否被刪除"+kenRemove);

        //集合中不存在的元素,刪除返回false
        boolean whoRemove = treeSet.remove("who");
        System.out.println("who元素是否被刪除"+whoRemove);

        //刪除並返回第一個元素:若是set集合不存在元素,則返回null
        String pollFirst = treeSet.pollFirst();
        System.out.println("刪除的第一個元素:"+pollFirst);

        //刪除並返回最後一個元素:若是set集合不存在元素,則返回null
        String pollLast = treeSet.pollLast();
        System.out.println("刪除的最後一個元素:"+pollLast);

        treeSet.clear();//清空集合
    }
}
//out:
TreeSet初始化容量大小:0
TreeSet容量大小:8
TreeSet元素順序爲:[123, hello, ken, my, name, world]
遍歷元素升序:
1 2 3 hello ken my name world 

遍歷元素降序:
world name my ken hello 3 2 1 

TreeSet頭節點爲:1
ken節點以前的元素爲:[123, hello]
1--hello之間節點元素爲:[123]
TreeSet是否爲空:false
TreeSet是否包含who元素:false
jiaboyan元素是否被刪除false
who元素是否被刪除false
刪除的第一個元素:1
刪除的最後一個元素:world
TreeSet元素排序

咱們講到了TreeSet是一個有序集合,能夠對集合元素排序,其中分爲天然排序和自定義排序

天然排序(正序與反序)
public class TreeSetTest {
   public static void main(String[] agrs){
        TreeSet<String> treeSetString = new TreeSet<String>();
        treeSetString.add("a");
        treeSetString.add("z");
        treeSetString.add("d");
        treeSetString.add("b");
        System.out.println("字母正序:" + treeSetString.toString());
        System.out.println("字母反序:" + treeSetString.descendingSet().toString());

        TreeSet<Integer> treeSetInteger = new TreeSet<Integer>();
        treeSetInteger.add(1);
        treeSetInteger.add(24);
        treeSetInteger.add(23);
        treeSetInteger.add(6);
        System.out.println("數字正序:" + treeSetInteger.toString());
        System.out.println("數字反序:" + treeSetInteger.descendingSet().toString());
    }
}
//out
字母順序:[a, b, d, z]
數字順序:[162324]
自定義排序

當使用的是本身定義的類時,就須要作一些特殊處理,不然會報錯Exception in thread "main" java.lang.ClassCastException,有兩種實現方式
1.實現Comparable接口

public class Person implements Comparable<Person>{
        private String name;
        private Integer age;
        public Person(){}
        public Person(String name,Integer age){
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        @Override
        public int compareTo(Person person) {
            //若是name長度同樣,則比較年齡的大小
            //須要考慮相等的狀況,不然相等的狀況只顯示先加入集合的元素
            if(this.age.equals(person.age)){
                return 1;
            }
            return this.age - person.age;
        }
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

    public static void main(String[] agrs){
        TreeSet<Person> treeSet = new TreeSet<Person>();

        //排序對象:
        Person p1 = new Person("ken",18);
        Person p2 = new Person("xiaoming",15);
        Person p3 = new Person("laowang",15);
        Person p4 = new Person("zhangsan",25);

        //添加到集合:
        treeSet.add(p1);
        treeSet.add(p2);
        treeSet.add(p3);
        treeSet.add(p4);
        System.out.println("TreeSet集合順序爲:"+treeSet);
    }

}
//out:
TreeSet集合順序爲:[Person{name='xiaoming', age=15}, Person{name='laowang', age=15}, 
Person{name='ken', age=18}, Person{name='zhangsan', age=25}]
2.實現Comparetor接口,並重寫compare方法
//自定義Person類的比較器:
public class PersonComparator implements Comparator<Person{
    @Override
    public int compare(Person p1, Person p2) {
        //比較名字長度,從大到小排序
        //須要考慮相等的狀況,不然相等的狀況只顯示先加入集合的元素
        if(p2.getName().length() == p1.getName().length()){
            return  1;
        }
        return p2.getName().length() - p1.getName().length();
    }
}

測試程序

 public static void main(String[] agrs){
        TreeSet<Person> treeSet = new TreeSet<Person>(new PersonComparator());

        //排序對象:
        Person p1 = new Person("ken",18);
        Person p2 = new Person("xiaoming",15);
        Person p3 = new Person("laowang",15);
        Person p4 = new Person("zhangsan",25);

        //添加到集合:
        treeSet.add(p1);
        treeSet.add(p2);
        treeSet.add(p3);
        treeSet.add(p4);
        System.out.println("TreeSet集合順序爲:"+treeSet);
    }
//out
TreeSet集合順序爲:[Person{name='xiaoming', age=15}, Person{name='zhangsan', age=25}, 
Person{name='laowang', age=15}, Person{name='ken', age=18}]

後續文章將對java集合中的具體實現類進行深刻了解。有興趣的話能夠觀看後續內容,進一步瞭解java集合內容。

相關文章
相關標籤/搜索