2020年4月22日 星期三

TreeSet集合: Comparable接口& Comparator接口

TreeSet集合的特性:
1. 無序但可以排序,必須實現Comparable接口和重寫compareTo方法,簡單來說就是必須提供編譯器排序的依據方法,詳細可以看創建對象TreeSett的無參構造方法(Comparator = null),以及新增元素使用add方法,底層調用TreeMap的put方法。
*不實現和重寫:
創建一個類,編譯器會報錯,錯誤類型: java.lang.ClassCastException

兩種解法:
(1) 實現Comparable接口和重寫 compareTo方法
(2) 使用Comparator比較器

(1) 第一種:
放在TreeSet集合中的元素需要實現 java.lang.Comparable接口,並且重寫compareTo方法
,compareTo方法需要編寫比較的邏輯 k.compareTo(t.key),返回值可能是 0,  <0,  >0,
比較規則是程序員自己指定的,比如說升序或降序

import java.util.*;

public class test01 {
    public static void main(String[] args) {
        User u1 = new User("100", "Hina");
        User u3 = new User("300", "Rui");
        User u2 = new User("200", "Natsuo");

        TreeSet<User> t = new TreeSet<>();
        t.add(u1);
        t.add(u2);
        t.add(u3);
        
        // 遍歷TreeSet集合
        for(User u : t){
            System.out.println(u);
        }
    }
}

// 寫一個User類 讓他實現Comparable接口 
class User implements Comparable<User>{
    private String idCard;
    private String name;
    public User(String idCard, String name){
        this.idCard = idCard;
        this.name = name;
    }
// Setter and Getter
    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 重寫compareTo方法,這邊用
    // String Integer.valueof()方法把String轉int讓他比較大小
    @Override
    public int compareTo(User u) {
        int thisint = Integer.valueOf(this.getIdCard());
        int userint = Integer.valueOf(u.idCard);
        return thisint - userint;

    }
    
    // 重寫toString方法讓遍歷時顯示每個元素 
    public String toString(){
        return "User[idCard= " + idCard + " , name= " + name + "]";
    }
}

(2) 第二種: 構造TreeSet或TreeMap集合時傳一個比較器對象


import java.util.*;

public class test01 {
    public static void main(String[] args) {
        User u1 = new User("100", "Hina");
        User u3 = new User("3000", "Rui");
        User u2 = new User("20", "Natsuo");

        // TreeSet<User> t= new TreeSet<>();
        // 這樣不行,要傳遞比較器

        // 給構造方法傳遞一個比較器
        TreeSet<User> t = new TreeSet<>(new UserCompare());
        t.add(u1);
        t.add(u2);
        t.add(u3);

        // 遍歷TreeSet集合
        for(User u : t){
            System.out.println(u);
        }
    }
}

    // 寫一個User類 讓他實現Comparable接口
class User{
    private String idCard;
    private String name;
    public User(String idCard, String name){
        this.idCard = idCard;
        this.name = name;
    }
    // Setter and Getter
    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    // 重寫toString方法讓遍歷時顯示每個元素
    public String toString(){
        return "User[idCard= " + idCard + " , name= " + name + "]";
    }
}

    // 單獨寫一個比較器
    // 比較器時現 java.util.Comparator接口
    // Comparable是 java.lang包下
    // Comparator是 java.util包下
class UserCompare implements Comparator<User>{

    // 重寫Compare方法,制定比較條件
    @Override
    public int compare(User o1, User o2) {
        int thisint = Integer.valueOf(o1.getIdCard());
        int userint = Integer.valueOf(o2.getIdCard());
        return thisint - userint;
    }
}

或者使用匿名內部類:
不用單獨寫一個比較器,但只能單次使用,無法代碼復用

        // 傳入比較器,比較器使用匿名內部類,直接new接口
        TreeSet<User> t = new TreeSet<>(new Comparator<User>(){
            public int compare(User o1, User o2) {
                int thisint = Integer.valueOf(o1.getIdCard());
                int userint = Integer.valueOf(o2.getIdCard());
                return thisint - userint;
            }
        });


*比較兩種方法:
1. Comparable是 java.lang包下,Comparator是 java.util包下
2. Comparable接口實現後,把代碼寫進此類當中,Comparator接口要獨立寫一個類
3. 當比較規則不會發生變化或只有一個,實現Comparable接口
比較規則多個,需要多個比較規則之間切換,建議使用Comparator接口,且此接口的設計符合OCP原則。


沒有留言:

張貼留言