如何在Java中为TreeSet中使用的StringBuffer类实现一个比较器?

如何在Java中为TreeSet中使用的StringBuffer类实现一个比较器?,java,comparator,treeset,stringbuffer,Java,Comparator,Treeset,Stringbuffer,我想为StringBuffer实现一个比较器,它比较StringBuffer并相应地添加到TreeSet。这纯粹是为了学习目的。我知道在Hasable集合中有一个可变对象是个坏主意。但这里的目的是如何为现有的Java StringBuffer类实现comparator,并使用它创建树集。 我现在的代码如下。代码不编译。请帮帮我。谢谢 public class ComparatorExample { public class SbufferComparator implements C

我想为StringBuffer实现一个比较器,它比较StringBuffer并相应地添加到TreeSet。这纯粹是为了学习目的。我知道在Hasable集合中有一个可变对象是个坏主意。但这里的目的是如何为现有的Java StringBuffer类实现comparator,并使用它创建树集。 我现在的代码如下。代码不编译。请帮帮我。谢谢

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实现Comparator{
@凌驾
公共整数比较(StringBuffer s1、StringBuffer s2){
返回s1.toString().compareTo(s2.toString());
}
}
公共静态void main(字符串[]args){
StringBuffer one=新的StringBuffer(“一”);
StringBuffer二=新的StringBuffer(“二”);
StringBuffer三=新的StringBuffer(“三”);
设置sb=新树集(新的SbufferComparator());
某人加(一);
某人加(二);
某人加(三);
System.out.println(“更改前设置:+sb”);
一.附加(“一个或多个”);
System.out.println(“更改后设置:+sb”);
}
}

内部类
SbufferComparator
必须是静态的,或者必须重构为顶级类

否则,需要构造一个封闭的对象实例:

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

将其保留为非静态内部类没有多大意义,因为它不使用其封闭类中的任何实例字段或方法。因此,将其设置为静态或顶级。

内部类
SbufferComparator
必须是静态的,或者必须重构为顶级类

否则,需要构造一个封闭的对象实例:

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

将其保留为非静态内部类没有多大意义,因为它不使用其封闭类中的任何实例字段或方法。因此,将其设置为静态或顶级。

您应该在一个单独的文件中创建comparator类,而不是在同一个类中,或者如果您希望将其保留在内部,则将其设置为静态

    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);
        }
    }
import java.util.Comparator;
导入java.util.Set;
导入java.util.TreeSet;
公共类比较示例{
私有静态类SbufferComparator实现Comparator{
@凌驾
公共整数比较(StringBuffer s1、StringBuffer s2){
返回s1.toString().compareTo(s2.toString());
}
}
公共静态void main(字符串[]args){
StringBuffer one=新的StringBuffer(“一”);
StringBuffer二=新的StringBuffer(“二”);
StringBuffer三=新的StringBuffer(“三”);
设置sb=新树集(新的SbufferComparator());
某人加(一);
某人加(二);
某人加(三);
System.out.println(“更改前设置:+sb”);
一.附加(“一个或多个”);
System.out.println(“更改后设置:+sb”);
}
}

注意进口声明

您应该在一个单独的文件中创建comparator类,而不是在同一个类中,或者如果希望将其保持在内部,则应将其设置为静态

    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);
        }
    }
import java.util.Comparator;
导入java.util.Set;
导入java.util.TreeSet;
公共类比较示例{
私有静态类SbufferComparator实现Comparator{
@凌驾
公共整数比较(StringBuffer s1、StringBuffer s2){
返回s1.toString().compareTo(s2.toString());
}
}
公共静态void main(字符串[]args){
StringBuffer one=新的StringBuffer(“一”);
StringBuffer二=新的StringBuffer(“二”);
StringBuffer三=新的StringBuffer(“三”);
设置sb=新树集(新的SbufferComparator());
某人加(一);
某人加(二);
某人加(三);
System.out.println(“更改前设置:+sb”);
一.附加(“一个或多个”);
System.out.println(“更改后设置:+sb”);
}
}

注意进口声明

由于以下几个原因,比较或存储缓冲区是危险的

  • StringBuffer
    是不必要的线程安全的,基本上不推荐使用
    StringBuilder
    。改用那个类
  • StringBuffer
    StringBuilder
    都是可变的,这意味着它们不能安全地插入到
    TreeSet
    中,因为它们可以更改(例如,
    sb.insert(0,'z')
    将使字符串以
    z
    开头,从而更改任何后续比较的结果)因此,请断开
    树集
  • 存储这样一个对象没有什么好处,如果您需要继续使用它,那么以后构建一个新的
    StringBuilder
    就很简单了
  • 您的比较器速度很慢,每次调用比较器时都需要重建字符串,即
    O(m log n)
    其中
    m
    是缓冲区长度,
    n
    是树大小
  • 我强烈建议直接将字符串存储在
    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);
    }
    

    更糟糕的是,由于底层的树结构,准确地找到哪些字段或找不到哪些字段取决于映射大小和错误点。使用从/
    /
    holdChar
    值,您将看到任意不同的结果。尝试
    holdChar='f'例如。

    出于以下几个原因,比较或存储缓冲区是危险的

  • StringBuffer
    是不必要的线程安全的