JANA-11.1-Set、HashSet與TreeSet;Map、HashMap與TreeMap講解

集合Set
1.Set
  常用方法:直接查看api,裏面的方法我們基本都是學過的
  Set的遍歷 1:Iterator,2:foreach
2.HashSet(查詢api看說明進行講解)
  2.1 元素順序:元素唯一,但是無序(它不保證 set 的迭代順序;特別是它不保證該順序恆久不變)
  2.2如何保證元素的唯一性的呢(分析源碼)?
    通過簡單的分析,我們知道HashSet集合保證元素的唯一性和add()方法相關。
    如何我們想深入的瞭解,就必須看add()方法的源碼,看它的底層依賴什麼內容?

//  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {...}
//        
//      左邊:e.hash == hash
//          比較對象的哈希值。
//        
//      右邊:((k = e.key) == key || key.equals(k))
//          左邊:(k = e.key) == key
//              比較對象的地址值。
//        
//          右邊:key.equals(k)
//              比較的是對象的內容是否相同。默認情況下比較的是地址值

結論:
  底層數據結構是哈希表。
  哈希表依賴兩個方法:hashCode()和equals()
執行流程:
  首先判斷哈希值是否相同,如果不同,就直接添加到集合。
    如果相同,繼續執行equals(),看其返回值,
    如果是false,就直接添加到集合。
     如果是true,說明元素重複不添加。
使用注意事項:如果你看到哈希結構的集合,就要考慮可能需要重寫這兩個方法。add()方法,保證唯一性的原理(底層依賴於hashCode()和equals()方法,保證了元素的唯一性)。

package com.edu.study7;
//需求:舉例說明元素唯一性
import java.util.HashSet;
public class HashSetDemo {
    public static void main(String[] args) {
        /**HashSet集合
         * 元素唯一,但是無序
         * 
         * 基本數據類型包裝類以及String類中已經重寫過hashCode()和equals()方法
         * 所以自動保證了元素唯一性
         */
        //創建HashSet集合
        HashSet<String> hashSet = new HashSet<String>();

        //給集合添加元素
        hashSet.add("hello");
        hashSet.add("world");
        hashSet.add("java");
        hashSet.add("hello");
        hashSet.add("php");
        hashSet.add("c");
        hashSet.add("你好哦");
        hashSet.add("heihei");

        //遍歷
        for (String s : hashSet) {
            System.out.println(s);
        }
    }
}
//第一次運行結果:              第八次運行結果:
//      hello                       hello       
//      heihei                      c
//      c                           heihei
//      php                         php
//      你好哦                     你好哦
//      java                        java
//      world                       world

需求:自定義學生對象,保證 集合元素唯一性

package com.edu.study7;

public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}
package com.edu.study7;
//HashSet集合,自定義類中必須重寫hashCode()和equals()方法,纔可以保證元素唯一性
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
    public static void main(String[] args) {
        //創建HashSet集合
        HashSet<Student> hashSet = new HashSet<Student>();
        //創建學生對象
        Student s1 = new Student("張三",13);
        Student s2 = new Student("李四",13);
        Student s3 = new Student("王五",13);
        Student s4 = new Student("張三",13);
        //給集合添加元素
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        hashSet.add(s4);

        //遍歷
        Iterator<Student> it = hashSet.iterator();
        while (it.hasNext()) {
            Student s = it.next();
            System.out.println(s.getName()+" "+s.getAge());
        }
    }
}
//不重寫輸出結果:      重寫:
//  李四 13               李四 13
//  張三 13               張三 13
//  王五 13               王五 13
//  張三 13

3.TreeSet(查看api,得出結論)
3.1 元素順序:使用元素的自然順序對元素進行排序,或者根據創建 set時提供的 Comparator進行排序(比較器排序),具體取決於使用的構造方法。
3.2 TreeSet集合的底層算法:二叉樹

package com.edu.study8;
/**
 * 基本數據類包裝類以及String類都實現Comparable接口
 * 且都重寫了compareTo()方法
 */
import java.util.TreeSet;
public class TreeSetDemo {
    public static void main(String[] args) {
        //創建TreeSet集合
/**     TreeSet<String> treeSet = new TreeSet<String>();
        treeSet.add("hello");
        treeSet.add("world");
        treeSet.add("c");
        treeSet.add("java");

        //遍歷
        for (String string : treeSet) {
            System.out.println(string);
        }
    //輸出:
    //  c
    //  hello
    //  java
    //  world
*/

        TreeSet<Integer> ts = new TreeSet<Integer>();
        ts.add(12);
        ts.add(25);
        ts.add(89);
        ts.add(3);
        //遍歷
        for (Integer i : ts) {
            System.out.println(i);
        }
    //輸出結果: 
    //  3
    //  12
    //  25
    //  89
    }
}

3.3 元素要求, 加入自定義JavaBean
需求:存入學生對象(姓名,年齡),1.按年齡排序,2.姓名排序(自然排序實現Comparable接口,並重寫comparaTo()方法)

package com.edu_04;
//新建Student類
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    //實現Comparable接口的同時必須實現這個比較法
    @Override
    public int compareTo(Student s) {
        //就是寫的是元素的比較規則,由你自己去動手寫出
        //按照學生的年齡進行排序
        /**
         * 兩個對象進行比較:
         * s
         * this
         */
        int num = this.age - s.age;
        //判斷年齡是否相同,如果相同比較姓名
        /**
         * 寫這個比較規則的時候注意兩點:
         * 1.他有主要條件,先按照主要條件進行排序
         * 2.如果主要條件相同,就需要你自己分析出來他的次要條件,再去按照次要條件進行比較
         */
        int num2 = num==0?this.name.compareTo(s.name):num;
        return num2;
    }
}
package com.edu_04;
import java.util.TreeSet;
/**
 * java.lang.ClassCastException:類型轉換異常
 * TreeSet集合有兩種排序方式:至於哪兩種排序方式,取決於他的構造器
 * 自然排序:無參構造public TreeSet()
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        //創建TreeSet集合,存儲自定義對象
        TreeSet<Student> ts = new TreeSet<Student>();

        //給集合中添加Student對象
        Student s = new Student("guodegang", 50);
        Student s6 = new Student("liuyifei", 50);
        Student s2 = new Student("zhangxueyou", 55);
        Student s3 = new Student("amu", 45);
        Student s4 = new Student("tf-boys", 18);
        Student s5 = new Student("wangfeng", 49);

        ts.add(s);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍歷集合
        for (Student student : ts) {
            System.out.println(student);
        }
    }
}

需求:創建set集合的時候,傳入Comparator(比較器排序)進行排序,進行排序(比較器排序)

package com.edu_05;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo {
    public static void main(String[] args) {
        //使用匿名內部類
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num==0?s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });

        //創建對象存入集合
        Student s = new Student("guodegang", 50);
        Student s6 = new Student("liuyifei", 50);
        Student s2 = new Student("zhangxueyou", 55);
        Student s3 = new Student("amu", 45);
        Student s4 = new Student("tf-boys", 18);
        Student s5 = new Student("wangfeng", 49);

        ts.add(s);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍歷集合
        for (Student student : ts) {
            System.out.println(student);
        }   
    }
}

4. HashSet與TreeSet的相同點與不同點
  相同點:
    單列集合,元素不可重複
  不同點
    1. 底層存儲的數據結構不同
    HashSet底層用的是HashMap哈希表結構存儲,而TreeSet底層用的是TreeMap樹結構存儲
    2.存儲時保證數據唯一性依據不同
    HashSet是通過複寫hashCode()方法和equals()方法來保證的,而TreeSet通過Compareable接口的compareTo()方法來保證的
    3.有序性不一樣
    HashSet無序,TreeSet有序

集合Map
一 一對應的映射關係。這種關係的集合在java叫Map。
Map:將鍵映射到值的對象。一個映射不能包含重複的鍵;每個鍵最多隻能映射到一個值。
1. Map接口中的方法:

   A:刪除功能
    void clear():移除集合中的所有鍵值對元素
    V remove(Object key):根據鍵移除鍵值對元素,並返回值
  B:判斷功能
    boolean containsKey(Object key):判斷集合中是否包含指定的鍵
    boolean containsValue(Object value):判斷集合中是否包含指定的值
    boolean isEmpty():判斷集合是否爲空
  C:獲取功能
    Set<Map.Entry<K,V>> entrySet():獲取鍵值對對象的集合,遍歷鍵值對對象,利用getKey(),getValue()取出鍵和值        
    V get(Object key):根據鍵獲取值
    Set<k> keySet():獲取所有的鍵
    Collection<v> values():獲取所有的值
  D:添加功能
    V put(K key,V value):集合添加鍵值對
  E:長度功能
    int size():鍵值對對數。

2. HashMap
  2.1元素順序:元素順序不可預測
  2.2底層算法:哈希算法
  2.3對鍵沒有要求(僅僅相對於TreeMap來說)

package com.edu.study12;
//練習:存入(String,String)進行練習
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
    public static void main(String[] args) {
        //創建HashMap集合
        HashMap<String, String> hashMap = new HashMap<String, String>();
        //給集合添加元素
        hashMap.put("A", "a");
        hashMap.put("B", "b");
        hashMap.put("C", "c");
        hashMap.put("D", "d");
        hashMap.put("A", "e");
        //當後面存入的元素和前面的鍵的值相同的時候,前面的元素的值會被後面的元素的值代替

        Set<String> keySet = hashMap.keySet();
        for (String key : keySet) {
            System.out.println(key+" "+hashMap.get(key));
        }
    }
}
//  D d
//  A e
//  B b
//  C c

練習 :

package com.edu.study13;
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
}
package com.edu.study13;
//練習:存入(String,Student)
import java.util.HashMap;
import java.util.Set;

public class HashMapDemo {
    public static void main(String[] args) {
        //創建HashMap集合
        HashMap<String, Student> hashMap = new HashMap<String, Student>();
        //創建Student對象
        Student s1 = new Student("zhang",6);
        Student s2 = new Student("li",25);
        Student s3 = new Student("sun",17);
        Student s4 = new Student("zhang",6);
        //給集合中添加元素
        hashMap.put("中國", s1);
        hashMap.put("韓國", s2);
        hashMap.put("美國", s3);
        hashMap.put("日本", s4);
        //當後面存入的元素和前面的鍵的值相同的時候,前面的元素的值會被後面的元素的值代替

        //通過鍵找值
        Set<String> keySet = hashMap.keySet();
            //得到的Set本質上是HashSet,元素唯一,無序
            //而鍵爲String類型,已經重寫了hashCode()和equals()方法,故保證了唯一性
        for (String key : keySet) {//因爲在Student類中重寫toString()方法
            System.out.println(key+" "+hashMap.get(key));
        }
    }
}
//日本 Student [name=zhang, age=6]
//韓國 Student [name=li, age=25]
//美國 Student [name=sun, age=17]
//中國 Student [name=zhang, age=6]

練習:

package com.edu.study14;
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }   
}
package com.edu.study14;
//傳入(Student, String),進行練習
import java.util.HashMap;
import java.util.Set;
public class HashMapDemo {
    public static void main(String[] args) {
        //創建HashMap集合
        HashMap<Student, String> hashMap = new HashMap<Student, String>();
        //創建Student對象
        Student s1 = new Student("zhang",6);
        Student s2 = new Student("liu",13);
        Student s3 = new Student("sun",20);
        Student s4 = new Student("zhang",6);
        //給集合添加元素
        hashMap.put(s1, "美國");
        hashMap.put(s2, "中國");
        hashMap.put(s3, "韓國");
        hashMap.put(s4, "中國");

        //遍歷
        Set<Student> keySet = hashMap.keySet();
            //此時的Set實質上是HashSet,元素唯一,無序
            //而鍵是Student類對象,應重寫hashCode()和equals()方法,方可保證唯一性
            //在Student類中重寫hashCode()和equals()方法

        for (Student key : keySet) {
            //在Student類中重寫toString()方法
            System.out.println(key+"  "+hashMap.get(key));
        }

    }
}
//  Student [name=liu, age=13]  中國
//  Student [name=sun, age=20]  韓國
//  Student [name=zhang, age=6]  中國

3. Treemap
3.1元素順序:元素順序與鍵的排序規則有關
3.2底層算法:Tree算法
4. 遍歷
集合遍歷:①獲取建的集合 ②遍歷鍵 ③根據鍵找值foreach()

1.foreach():根據丈夫找妻子(根據鍵找值)
2.entrySet():(Set<Map.Entry<K,V>> entrySet())先找到夫妻的結婚證,再從結婚證裏面找到丈夫和妻子(先找到鍵值對對象,再從鍵值對對象裏面找到鍵和值)

練習:存入(Integer,String)

package com.edu_11;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapDemo {
    public static void main(String[] args) {
        //1.存入(Integer,String),主要驗證排序方式
        //c創建TreeMap集合
        TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
        //存入元素
        tm.put(1, "趙");
        tm.put(4, "劉");
        tm.put(2, "坤");
        tm.put(3, "李");

        //遍歷集合
        Set<Integer> keys = tm.keySet();
        for (Integer key : keys) {
            System.out.println(key+"  "+tm.get(key));
        }
    }
}
/**     1  趙
        2  坤
        3  李
        4  劉
*/

練習:存入(Student,String)
新建學生類

package com.edu_12;
public class Student implements Comparable<Student>{
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    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;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }
    @Override
    public int compareTo(Student s) {
        //先按年齡排序,年齡相同按照姓名排序
        //int num = this.age - s.age;
        int num =s.age - this.age; 
        int num2 = num==0?this.name.compareTo(s.name):num;
        return num2;
    }
}

測試

package com.edu_12;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapDemo {
    public static void main(String[] args) {
        // 2.存入(Student,String),鍵:Student   值:地址
        //創建TreeMap集合
        TreeMap<Student, String> tm = new TreeMap<>();

        //創建學生對相同
        Student s1 = new Student("郭德綱", 50);
        Student s2 = new Student("劉德華", 55);
        Student s3 = new Student("張學友", 58);
        Student s4 = new Student("黎明", 40);
        Student s5 = new Student("郭德綱", 50);

        //將元素存入集合
        tm.put(s1, "中國");
        tm.put(s2, "中國");
        tm.put(s3, "中國");
        tm.put(s4, "中國");
        tm.put(s5, "中國");

        //遍歷集合
        Set<Student> keys = tm.keySet();
        for (Student s : keys) {
            System.out.println(s+"  "+tm.get(s));
        }   
    }
}
/** Student [name=張學友, age=58]  中國
    Student [name=劉德華, age=55]  中國
    Student [name=郭德綱, age=50]  中國
    Student [name=黎明, age=40]  中國
*/  

5. HashMap與TreeMap的相同點與不同點
  相同點:
  主要用於存儲鍵(key)值(value)對,根據鍵得到值,因此鍵不允許鍵重複,但允許值重複。
  不同點:
  1.HashMap裏面存入的鍵值對在取出的時候是隨機的,也是我們最常用的一個Map.根據鍵可以直接獲取它的值,具有很快的訪問速度。在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。
  2.TreeMap取出來的是排序後的鍵值對。但如果您要按自然順序或自定義順序遍歷鍵,那麼TreeMap會更好。

發佈了41 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章