![](/img/trans.png)
[英]how to implement a comparator for StringBuffer class in Java for use in TreeSet?
[英]can StringBuffer objects be keys in TreeSet in Java?
我有以下代碼,我試圖將 StringBuffer 對象作為 TreeSet 中的鍵。 我這樣做的原因是看是否可以將可變對象作為鍵。 我沒有收到任何編譯錯誤。 但是當我運行此代碼時,我收到代碼下方的錯誤。 特別是,我得到這個java.lang.StringBuffer cannot be cast to java.lang.Comparable
。 這個錯誤說明了什么?
從 javadoc 我看到 StringBuffer 類被聲明為 final ( public final class 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
StringBuffer
是public final class StringBuffer
的事實意味着你不能子類化它。 StringBuffer 是非常可變的(這就是重點,您可以修改緩沖區的內容。)
你不想使用可變的東西作為鍵,因為在對象被修改后,它的 equals() 和 hashcode() 方法將返回不同的結果,你將無法再在 Map 中找到它。
如果您真的想在 TreeSet 中使用 StringBuffer,則必須提供自己的 Comparator,因為 StringBuffer 沒有實現 Comparable。
只需添加一個比較器類,然后在您的 TreeSet 中使用它,如下所示:
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());
問題是TreeSet
對您放入其中的項目進行排序。 因為StringBuffer
沒有實現Comparable
,所以TreeSet
不知道如何對它們進行排序。 您應該在創建TreeSet
時傳入Comparator
。 您的比較器將告訴TreeSet
如何對StringBuffer
進行排序。 要么,要么您可以使用HashSet
,它不會對元素進行排序。
就不變性而言:類聲明中的 final 關鍵字意味着您不能對其進行子類化(擴展)。 就其本身而言,它不會使類不可變。 不可變意味着對象的狀態一旦創建就無法更改。 StringBuffer
肯定可以在創建后更改其狀態,因此它們不是不可變的。
聲明一個類final
並不意味着它是不可變的,這意味着不允許任何類對其進行子類化。 實際上, StringBuffer
是非常易變的; 這就是課程的重點。
因為StringBuffer
不是Comparable
,所以您的TreeSet
不知道如何對您的StringBuffers
進行排序。 但是,將可變對象作為任何類型的Set
(或Map
)中的鍵是一個壞主意。 如果您必須使用TreeSet
,則創建並使用自定義Comparator
對象來比較StringBuffer
對象。
TreeSet
只接受Comparable
對象,而StringBuffer
不是Comaprable
對象。
Throws-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);
你在問幾個問題:
你有什么困惑,我會幫你解決的
Java 中有兩種與 Maps 一起使用的識別策略(或多或少)。
散列:輸入“Foo”被轉換為盡可能好的嘗試,以生成唯一訪問數組索引的數字。 (純粹主義者,請不要辱罵我,我是故意簡化的)。 此索引是存儲您的值的位置。 有可能“Foo”和“Bar”實際上生成相同的索引值,這意味着它們都將被映射到相同的數組位置。 顯然這行不通,所以這就是“equals()”方法的用武之地; 它用於消除歧義
比較:通過使用比較方法,您不需要這個額外的消歧步驟,因為比較從一開始就不會產生這種沖突。 “Foo”等於的唯一鍵是“Foo”。 一個非常好的主意是,如果可以的話,將“equals()”定義為 compareTo() == 0; 為了一致性。 不是要求。
現在回答你的一般問題:
地圖的鍵可以是可變的。 回答:是的,非常非常糟糕和愚蠢。 示例:Map.put(k,v); k.modifyInternalHash(); Map.get(k) = null; // 這里不好
實際上,這是由於粗心散列而發生的。 盡管比較地圖可能會發生這種情況,但診斷問題要容易得多。
StringBuffer 可以用作 TreeMap/Set 的鍵嗎? 是的。 使用替代構造函數:TreeSet(Comparator<T>comparator) 並為 StringBuffer 定義您自己的比較方法
祝你好運
是的,您可以,但正如上述答案所述,您必須編寫一個比較器。
但真正的問題是你為什么要這樣做? StringBuffer 的目的是在創建字符串時修改狀態。 由於它是 SortedMap 中的一個鍵,因此您不應修改該鍵,因此保存 StringBuffer 毫無意義。 您想要做的是調用 StringBuffer.toString() ,它返回一個字符串並使用該字符串作為您的鍵。
我們依賴於默認的自然排序順序強制對象應該是同質的和可比較的,否則我們會得到運行時異常,說 Class cast 異常。 當且僅當 Corresopding 類實現了可比較的接口時,才說一個對象是可比較的。 String 類和所有包裝類已經實現了可比較的接口,但 String Buffer 類沒有實現可比較的接口。 因此它會在上面的代碼中給出類成本異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.