簡體   English   中英

StringBuffer 對象可以是 Java 中 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
  1. StringBufferpublic final class StringBuffer的事實意味着你不能子類化它。 StringBuffer 是非常可變的(這就是重點,您可以修改緩沖區的內容。)

  2. 你不想使用可變的東西作為鍵,因為在對象被修改后,它的 equals() 和 hashcode() 方法將返回不同的結果,你將無法再在 Map 中找到它。

  3. 如果您真的想在 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對象。

樹集#add

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);

你在問幾個問題:

  1. 一般問題:“你能有一個可變的哈希鍵嗎”
  2. 具體問題:“StringBuffer 可以用作 TreeSet 的鍵嗎”

你有什么困惑,我會幫你解決的

Java 中有兩種與 Maps 一起使用的識別策略(或多或少)。

  1. 散列:輸入“Foo”被轉換為盡可能好的嘗試,以生成唯一訪問數組索引的數字。 (純粹主義者,請不要辱罵我,我是故意簡化的)。 此索引是存儲您的值的位置。 有可能“Foo”和“Bar”實際上生成相同的索引值,這意味着它們都將被映射到相同的數組位置。 顯然這行不通,所以這就是“equals()”方法的用武之地; 它用於消除歧義

  2. 比較:通過使用比較方法,您不需要這個額外的消歧步驟,因為比較從一開始就不會產生這種沖突。 “Foo”等於的唯一鍵是“Foo”。 一個非常好的主意是,如果可以的話,將“equals()”定義為 compareTo() == 0; 為了一致性。 不是要求。

現在回答你的一般問題:

  1. 地圖的鍵可以是可變的。 回答:是的,非常非常糟糕和愚蠢。 示例:Map.put(k,v); k.modifyInternalHash(); Map.get(k) = null; // 這里不好
    實際上,這是由於粗心散列而發生的。 盡管比較地圖可能會發生這種情況,但診斷問題要容易得多。

  2. 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.

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