簡體   English   中英

如何在Java中實現StringBuffer類的比較器以在TreeSet中使用?

[英]how to implement a comparator for StringBuffer class in Java for use in TreeSet?

我想為StringBuffer實現一個比較器,該比較器比較StringBuffer並相應地添加到TreeSet中。 這純粹是出於學習目的。 我知道在Hasable集合中包含可變對象是一個壞主意。 但是這里的目的是如何為現有的Java StringBuffer類實現比較器並使用它來創建TreeSet。 我當前的代碼如下。 該代碼無法編譯。 請在這里幫助我。 謝謝

public class ComparatorExample {


    public class SbufferComparator implements Comparator<StringBuffer> {

        @Override
        public int compare(StringBuffer s1, StringBuffer s2) {
            return s1.toString().compareTo(s2.toString());

        }

    }


        public static void main(String[] args) {
                StringBuffer one = new StringBuffer("one");
                StringBuffer  two = new StringBuffer("two");
                StringBuffer three = new StringBuffer("three");
                Set<StringBuffer> sb=new TreeSet<StringBuffer>(new SbufferComparator());
                sb.add(one);
                sb.add(two);
                sb.add(three);
                System.out.println("set before change: "+ sb);
                one.append("onemore");
                System.out.println("set After change: "+ sb);
            }
        }

內部類SbufferComparator必須是靜態的,或者必須重構為頂級類。

否則,需要構造一個封閉的對象實例:

ComparatorExample ce = new ComparatorExample();
SbufferComparator comparator = ce.new SbufferComparator();

將其保留為非靜態內部類沒有太大意義,因為它不使用其封閉類中的任何實例字段或方法。 因此,使其為靜態或頂級。

如果要保留比較器類的內部內容,則應在單獨的文件中創建比較器類,而不是在同一類中,或者將其設置為靜態。

    import java.util.Comparator;
    import java.util.Set;
    import java.util.TreeSet;

public class ComparatorExample {
private static class SbufferComparator implements Comparator<StringBuffer> {

        @Override
        public int compare(StringBuffer s1, StringBuffer s2) {
            return s1.toString().compareTo(s2.toString());

        }

}


    public static void main(String[] args) {
            StringBuffer one = new StringBuffer("one");
            StringBuffer  two = new StringBuffer("two");
            StringBuffer three = new StringBuffer("three");
            Set<StringBuffer> sb=new TreeSet<StringBuffer>(new SbufferComparator());
            sb.add(one);
            sb.add(two);
            sb.add(three);
            System.out.println("set before change: "+ sb);
            one.append("onemore");
            System.out.println("set After change: "+ sb);
        }
    }

注意導入聲明!

由於某些原因,比較或存儲緩沖區很危險。

  1. StringBuffer不必要是線程安全的,而實際上不建議使用StringBuilder 請改用該類。
  2. StringBufferStringBuilder都是可變的,這意味着它們不能安全地插入到TreeSet ,因為它們可以更改(例如sb.insert(0, 'z')會使字符串以z開頭,更改任何后續的結果比較),並因此破壞TreeSet
  3. 存儲這樣的對象幾乎沒有好處,如果以后需要繼續使用它,則構造一個新的StringBuilder並不容易。
  4. 您的比較器很慢,每次調用比較器時都需要重建字符串,即O(m log n) ,其中m是緩沖區長度, n是樹的大小。

我強烈建議直接將字符串直接存儲在TreeSet 這樣可以工作得更干凈,更快,並避免出現危險的邊緣情況,例如亂序渲染TreeSet


這是一個示例,演示在TreeSet使用可變對象(如緩沖區)如何打破所有期望:

public static void main(String[] args) {
    TreeSet<StringBuilder> tree = new TreeSet<>(new Comparator<StringBuilder>() {
        @Override
        public int compare(StringBuilder one, StringBuilder two) {
            return one.toString().compareTo(two.toString());
        }});

    char from = 'a', to = 'm'; // change to adjust map size
    char holdChar = 'd'; // change holdChar to adjust error location
    StringBuilder hold = null;

    for(char c = from; c <= to; c++) {
        StringBuilder sb = new StringBuilder().append(c).append(c).append(c);
        tree.add(sb);
        if(c == holdChar) {
            hold = sb;
        }
    }
    System.out.println(tree);

    hold.insert(0, to);

    for(char c = from; c <= to; c++) {
        StringBuilder sb = new StringBuilder().append(c).append(c).append(c);
        if(c == holdChar) {
            sb.insert(0, to);
        }
        System.out.println("Tree contains "+sb+(tree.contains(sb) ? "" : " NOPE!!"));
    }
    System.out.println(tree);
}

從理論上講,第二個for循環中正在測試的每個StringBuilder都存在於映射中,但是映射不再能夠准確地確定這一點:

[aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii, jjj, kkk, lll, mmm]
Tree contains aaa
Tree contains bbb
Tree contains ccc
Tree contains mddd
Tree contains eee NOPE!!
Tree contains fff NOPE!!
Tree contains ggg NOPE!!
Tree contains hhh NOPE!!
Tree contains iii NOPE!!
Tree contains jjj NOPE!!
Tree contains kkk NOPE!!
Tree contains lll NOPE!!
Tree contains mmm
[aaa, bbb, ccc, mddd, eee, fff, ggg, hhh, iii, jjj, kkk, lll, mmm]

更糟糕的是,由於底層樹結構的緣故,准確找到或未正確找到哪些字段取決於映射大小和錯誤點。 使用from / to / holdChar值,您將看到任意不同的結果。 嘗試holdChar = 'f'; 例如。

現在,您有一個名為SbufferComparator的內部類。 由於它是非靜態的,因此您需要一個實例來訪問其方法。 您只需將其設為靜態即可工作!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM