Java基礎教程——Set


Set·無序,不重復

HashSet

特點:沒有重復數據,數據不按存入的順序輸出。

HashSet由Hash表結構支持。不支持set的迭代順序,不保證順序。
但是Hash表結構查詢速度很快。

創建集合使用代碼:

Set<String> s = new HashSet<>();

代碼演示:常用方法和遍歷輸出

import java.util.*;
public class TestHashSet {
	public static void main(String[] args) {
		m010賦值And遍歷();
	}
	public static void m010賦值And遍歷() {
		System.out.println("=====賦值And遍歷");
		Set<String> s = new HashSet<>();
		s.add("孫悟空");
		s.add("小白龍");
		s.add("豬八戒");
		s.add("沙悟凈");
		s.add("孫悟空");
		System.out.println("是否為空:" + s.isEmpty());
		System.out.println("是否包含:" + s.contains("小白龍"));
		System.out.println("移除:" + s.remove("小白龍"));
		// (1)foreach:遍歷set
		for (String str : s) {
			System.out.println(str);
		}
		// (2)迭代器:遍歷set
		Iterator<String> it = s.iterator();
		while (it.hasNext()) {
			String str = it.next();
			System.out.println("Iterator : " + str);
		}
		// (3)*Java 8新增遍歷方法
		s.forEach(elm -> System.out.println("Lambda:" + elm));
	}
}

Hash和Hash表

Hash

HashCode,是一個十進制整數,是對象的地址值(邏輯地址,不是物理地址)
Object類有一個方法,可以獲取對象的Hash值。

public native int hashCode();

String重寫了hashCode方法

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

以至於有些不同字符串的hashCode相等(字符串還是不等的,無論==還是equals):

		System.out.println("重地".hashCode());
		System.out.println("通話".hashCode());
		System.out.println("--------------");
		System.out.println("方面".hashCode());
		System.out.println("樹人".hashCode());
		System.out.println("--------------");
		System.out.println("兒女".hashCode());
		System.out.println("農豐".hashCode());
		System.out.println("--------------");
		System.out.println("Ea".hashCode());
		System.out.println("FB".hashCode());

Hash表

Java8之前:Hash表使用數組+鏈表;
Java8之后加入了紅黑樹,查詢速度加快。

Hash表結構的示意圖如下所示:

數組里存儲的是HashCode。
HashCode相同的元素加入相同鏈表;
如果鏈表長度超過8,就轉為紅黑樹以提高查詢速度。

怎么才算重復?

HashSet中,元素不重復指“equals方法比較為true,且hashCode不同”。

下列示例代碼中,只有equals為true、且hashCode相同的對象未重復存入Set中。

import java.util.*;
class A_equalsT {
	public boolean equals(Object obj) {
		return true;
	}
}
class B_hash1 {
	public int hashCode() {
		return 1;
	}
}
class C_hash2_equalsT {
	public int hashCode() {
		return 2;
	}
	public boolean equals(Object obj) {
		return true;
	}
}
public class TestSet怎么才算重復 {
	public static void main(String[] args) {
		Set<Object> _set = new HashSet<Object>();
		_set.add(new A_equalsT());
		_set.add(new A_equalsT());
		_set.add(new B_hash1());
		_set.add(new B_hash1());
		_set.add(new C_hash2_equalsT());
		_set.add(new C_hash2_equalsT());
		for (Object object : _set) {
			System.out.println(object);
		}
	}
}

運行結果:(C_hash2_equalsT只存入一份,說明被看作重復對象)

B_hash1@1
B_hash1@1
C_hash2_equalsT@2
A_equalsT@15db9742
A_equalsT@6d06d69c

HashSet存儲自定義元素時,需要重寫hashCode和equals方法,才能保證集合中對象的唯一性。

練習:

創建Student類,至少需要包含id、name。創建多個Student對象加入HashSet,如果學號(id)相同則不重復加入。

TreeSet

TreeSet支持兩種排序方式,自然排序和定制排序。默認為自然排序,和HashSet的輸出順序不一樣。

TreeSet使用紅黑樹存儲元素(示例和下一小節一起)。

LinkedHashSet

Set也可以有序,這個LinkedHashSet就能按照輸入順序輸出結果。

LinkedHashSet也是根據元素的hashCode值決定元素的存儲位置,但是加了一條鏈表記錄元素的存儲順序,這使得元素有序。

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
public class TestTree{
	public static void main(String[] args) {
		m020各種Set();
	}
	private static void m020各種Set() {
		System.out.println("|-HashSet:");
		Set<String> _set;
		_set = new HashSet<String>();
		_set.add("B");
		_set.add("A");
		_set.add("1");
		_set.add("2");
		_set.add(null);
		printSet(_set);
		System.out.println("|-TreeSet不接受空值:");
		_set = new TreeSet<String>();
		_set.add("B");
		_set.add("A");
		_set.add("1");
		_set.add("2");
		// _set.add(null);
		printSet(_set);
		System.out.println("|-LinkedHashSet:有序");
		_set = new LinkedHashSet<String>();
		_set.add("B");
		_set.add("A");
		_set.add("1");
		_set.add("2");
		_set.add(null);
		printSet(_set);
	}
	private static void printSet(Set<String> _set) {
		for (String str : _set) {
			System.out.print(str + " ");
		}
		System.out.println();
	}
}

|-HashSet:
null A 1 B 2
|-TreeSet不接受空值:
1 2 A B
|-LinkedHashSet:有序
B A 1 2 null

Set的性能

HashSet綜合效率最高,LinkedHashSet因為有鏈表,遍歷時會更快一些。TreeSet因為要維護紅黑樹,效率較低。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM