StringBuffer对象可以是Java中TreeSet中的键吗?
我有下面的代码,试图将StringBuffer对象作为键放入树集中。我这样做的原因是想看看是否可以将可变对象作为键。我没有得到任何编译错误。但是当我运行这段代码时,我得到了代码下面的错误。 特别是,我得到这个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),这难道不意味着它是不可变的,因此是可散列的吗 我是散列和不可
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
仅获取可比较的对象,其中asStringBuffer
不是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());