大家都知道。在Map和Set不可存在反復元素?
可是對於內部的細節我們並不了解。今天我們就一塊來 探討一下!
1 對於 HashMap HashSet
他們的底層數據結構的實現是:維護了一張 HashTable 。容器中的元素所有存儲在Hashtable 中。他們再加入元素的時候,是怎樣推斷是否存在有反復元素的呢? 每個被加入的元素都有一個 hashCode(哈希值),他們先比較哈希值,是否同樣? 不同樣的元素,加入進入 HashTable. 假設hashCode同樣的話, 再去比較 equals()方法,假設也同樣的話,JVM就覺得數據已經存在了。就不會加入數據!
如圖1:

2 對於 TreeMap TreeSet
他們底層是數據結構的實現是:維護了一棵二叉樹。 容器中加入元素的時候,他們有是怎么推斷是否有同樣元素的?我們都直到 TreeMap TreeSet 她們 都是 有序的存儲數據。
為了維護 數據的唯一性。 再存入數據的時候,他們會調用元素中 實現的 Comparable 的 compareTo() 方法(代碼1)。 或者 集合本身創建的時候 傳入了 迭代器(代碼2). 詳細的實現是:調用比較方法,返回-1 的時候,加入到左子樹,返回1 的時候 加入到 右子樹。
返回0 有同樣數據 不加入該元素!
如圖2

代碼1;(原理一)
package stu.love.v;
import java.util.*;
//什么時候用Map
/*
當存在映射關系時。
每一個學員都相應一個地址
姓名,年齡同樣的視為同一個人
*/
// 容器中的對象 本身 具備比較性。
class StudentD implements Comparable<StudentD>
{
private String name;
private int age;
public StudentD(String name,int age)
{
this.name = name;
this.age = age;
}
public int compareTo(StudentD stu)
{
int t = this.age-stu.age;
return t==0?this.name.compareTo(stu.name):t;
}
// 重寫了 hashCode 方法
public int hashCode()
{
return name.hashCode()+age*36;
}
// 重寫了 equals 方法
public boolean equals(Object obj)
{
if(!(obj instanceof StudentD))
throw new ClassCastException("類型異常");
StudentD stu =(StudentD)obj;
return this.name.equals(stu.name) && this.age ==stu.age;
}
public void setName(String name)
{
this.name = name;
}
public void setAge(int age)
{
this.age = age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
public String toString()
{
return this.name +","+age;
}
}
class Demo16
{
public static void main(String[] args)
{
//保證鍵唯一的原理,先推斷哈希值是否同樣,同樣再推斷equals()
HashMap<StudentD,String> hm = new HashMap<StudentD,String>();
hm.put(new StudentD("xiaobai",23),"shanghai");
hm.put(new StudentD("wanghei",20),"beijing");
hm.put(new StudentD("lisi",28),"shenzhen");
hm.put(new StudentD("lisi",28),"shenzhen");
// Map 第一種 迭代方式 依據 key 找 value
Set<StudentD> set=hm.keySet();
for(Iterator<StudentD> ite = set.iterator();ite.hasNext();)
{
StudentD stu = ite.next();
String value = hm.get(stu);
sop(stu+"的地址是:"+value);
}
// map 的 另外一種 迭代方式 獲取 鍵值對。entry 獲取當中的 key 和 value
Set<Map.Entry<StudentD,String>> entry = hm.entrySet();
for(Iterator<Map.Entry<StudentD,String>> ite = entry.iterator();ite.hasNext();)
{
Map.Entry<StudentD,String> kv = ite.next();
StudentD key = kv.getKey();
String value = kv.getValue();
sop(key+"的地址是:"+value);
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
代碼2:
package stu.love.v;
/*
TreeMap:
HashMap保證鍵唯一的原理和HashSet同樣
TreeMap保證鍵唯一的原理和TreeSet同樣
*/
import java.util.*;
class Student1
{
private String name;
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;
}
private int age;
public Student1(String name,int age)
{
this.name = name;
this.age = age;
}
public String toString()
{
return name+","+age;
}
}
// 比較器
class CompareByName implements Comparator<Student1>
{
public int compare(Student1 s1,Student1 s2)
{
// 這樣寫的方法 很好! 簡潔
int t = s1.getName().compareTo(s2.getName());
return t ==0?s1.getAge()-s2.getAge():t;
}
}
class Demo17
{
public static void main(String[] args)
{
// 原理二:
//保證鍵唯一的原理:比較方法的返回值為0
TreeMap<Student1,String> tm = new TreeMap<Student1,String>(new CompareByName());
tm.put(new Student1("xiaobai",23),"shanghai");
tm.put(new Student1("wanghei",20),"beijing");
tm.put(new Student1("lisi",28),"shenzhen");
tm.put(new Student1("lisi",28),"shenzhen");
Set<Map.Entry<Student1,String>> entry = tm.entrySet();
for(Iterator<Map.Entry<Student1,String>> it = entry.iterator();it.hasNext();)
{
Map.Entry<Student1,String> kv = it.next();
Student1 key = kv.getKey();
String value = kv.getValue();
sop(key+"的地址是:"+value);
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
