Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
StringBuffer对象可以是Java中TreeSet中的键吗?_Java_Hashset_Comparable_Treeset_Stringbuffer - Fatal编程技术网

StringBuffer对象可以是Java中TreeSet中的键吗?

StringBuffer对象可以是Java中TreeSet中的键吗?,java,hashset,comparable,treeset,stringbuffer,Java,Hashset,Comparable,Treeset,Stringbuffer,我有下面的代码,试图将StringBuffer对象作为键放入树集中。我这样做的原因是想看看是否可以将可变对象作为键。我没有得到任何编译错误。但是当我运行这段代码时,我得到了代码下面的错误。 特别是,我得到这个java.lang.StringBuffer不能转换为java.lang.Compariable。这个错误表示什么 从javadoc中,我看到StringBuffer类被声明为final(公共final类StringBuffer),这难道不意味着它是不可变的,因此是可散列的吗 我是散列和不可

我有下面的代码,试图将StringBuffer对象作为键放入树集中。我这样做的原因是想看看是否可以将可变对象作为键。我没有得到任何编译错误。但是当我运行这段代码时,我得到了代码下面的错误。 特别是,我得到这个
java.lang.StringBuffer不能转换为java.lang.Compariable
。这个错误表示什么

从javadoc中,我看到StringBuffer类被声明为final(
公共final类StringBuffer
),这难道不意味着它是不可变的,因此是可散列的吗

我是散列和不可变内容的新手,所以请在这里帮助我

谢谢

import java.util.*;
class MutableKeys {
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>();
        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);
    }
}

Exception in thread "main" java.lang.ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
    at java.util.TreeMap.put(TreeMap.java:542)
    at java.util.TreeSet.add(TreeSet.java:238)
    at inheritance.MutableKeys.main
import java.util.*;
类可变键{
公共静态void main(字符串[]args){
StringBuffer one=新的StringBuffer(“一”);
StringBuffer二=新的StringBuffer(“二”);
StringBuffer三=新的StringBuffer(“三”);
设置sb=新树集();
某人加(一);
某人加(二);
某人加(三);
System.out.println(“更改前设置:+sb”);
一.附加(“一个或多个”);
System.out.println(“更改后设置:+sb”);
}
}
线程“main”java.lang.ClassCastException中的异常:无法将java.lang.StringBuffer转换为java.lang.Compariable
位于java.util.TreeMap.put(TreeMap.java:542)
添加(TreeSet.java:238)
位于heritation.MutableKeys.main

问题在于
TreeSet
对放入其中的项目进行排序。因为
StringBuffer
没有实现
compariable
,所以
TreeSet
不知道如何对它们进行排序。创建
树集时,应传入
比较器
。比较器将告诉
TreeSet
如何排序
StringBuffer
s。或者,您可以使用不排序元素的
哈希集


就不变性而言:类声明上的最后一个关键字意味着您不能将其子类化(扩展)。它本身并不能使类不可变。不可变意味着对象的状态在创建后不能更改
StringBuffer
s在创建后肯定可以更改它们的状态,因此它们不是不可变的。

声明类
final
并不意味着它是不可变的,它意味着不允许任何类对其进行子类化。实际上,
StringBuffer
是非常可变的;这就是这门课的重点

因为
StringBuffer
不可比较
。但是,在任何类型的
集合
(或
映射
)中,将可变对象作为键都不是一个好主意。如果必须使用
树集
,则创建并使用自定义的
比较器
对象来比较
StringBuffer
对象

  • StringBuffer
    public final类StringBuffer
    这一事实意味着您不能将其子类化。StringBuffer是非常可变的(这就是重点,您可以修改缓冲区的内容。)

  • 您不希望使用可变的内容作为键,因为在修改对象后,其equals()和hashcode()方法将返回不同的结果,您将无法在映射中找到它

  • 如果您真的想在树集合中使用StringBuffer,您必须提供自己的比较器,因为StringBuffer没有实现Comparable


  • TreeSet
    仅获取可比较的
    对象,其中as
    StringBuffer
    不是
    Comaprable
    对象

    抛出ClassCastException-如果指定的对象无法与此集合中当前的元素进行比较

    您可以使用
    String
    对象(因为String是可比较的),而不是
    StringBuffer
    对象。
    例如:

        Set<String> sb=new TreeSet<String>();
        sb.add(one.toString());
        sb.add(two.toString());
        sb.add(three.toString());
        System.out.println("set before change: "+ sb);
        System.out.println("set After change: "+ sb);
    
    Set sb=new TreeSet();
    某人加上(一个toString());
    某人加上(两个toString());
    某人加上(三个toString());
    System.out.println(“更改前设置:+sb”);
    System.out.println(“更改后设置:+sb”);
    
    您提出了几个问题:

  • 一般问题:“能否为哈希设置可变密钥”
  • 具体问题:“StringBuffer可以用作树集的键吗?”
  • 你有些事情弄糊涂了,我会帮你解决的

    Java中地图使用了两种识别策略(或多或少)

  • 散列:一个输入“Foo”被转换成一个尽可能好的尝试,以生成一个唯一访问数组索引的数字。(纯粹主义者,请不要辱骂我,我是故意简化的)。此索引是存储值的位置。有可能“Foo”和“Bar”实际生成相同的索引值,这意味着它们都将映射到相同的数组位置。显然这是行不通的,所以这就是“equals()”方法的用武之地;它用于消除歧义

  • 比较:通过使用比较方法,您不需要这个额外的消歧步骤,因为比较从一开始就不会产生这种冲突。“Foo”等于的唯一键是“Foo”。一个非常好的主意是,如果可以的话,将“equals()”定义为compareTo()==0;为了一致性。这不是要求

  • 现在谈谈你的一般性问题:

  • 映射的键可以是可变的。回答:是的,非常非常糟糕和愚蠢。示例:Map.put(k,v);k、 modifyInternalHash();Map.get(k)=null;//这里不好
    实际上,这是由于散列的粗心造成的。虽然这可能发生在比较地图上,但诊断起来要容易得多

  • StringBuffer可以用作树映射/集的键吗?对使用替代构造函数:TreeSet(ComparatorComparator)并为StringBuffer定义自己的比较方法

  • 祝你好运class Comparatorbuff implements Comparator<StringBuffer> { @Override public int compare(StringBuffer s1, StringBuffer s2) { return s1.toString().compareTo(s2.toString()); } } in your main method: modify as follows Set<StringBuffer> sb=new TreeSet<StringBuffer>(new Comparatorbuff());