2

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
4

8 に答える 8

4
  1. つまり、サブクラス化できないということですStringBufferpublic final class StringBufferStringBuffer は非常に可変です (ここがポイントです。バッファの内容を変更できます)。

  2. オブジェクトが変更された後、 equals() メソッドと hashcode() メソッドが異なる結果を返し、 Map でそれを見つけることができなくなるため、変更可能なものをキーとして使用したくありません。

  3. 本当に TreeSet で StringBuffer を使用したい場合は、StringBuffer が Comparable を実装していないため、独自の Comparator を提供する必要があります。

于 2013-08-22T19:37:02.940 に答える
2

問題は、TreeSet入れたアイテムをソートすることです。StringBufferは を実装していないため、ComparableそれらTreeSetを並べ替える方法がわかりません。Comparatorを作成するときに a を渡す必要がありますTreeSet。コンパレーターは、sTreeSetをソートする方法を教えてくれStringBufferます。それかHashSet、要素をソートしない を使用できます。

不変性に関する限り、クラス宣言の final キーワードは、それをサブクラス化 (拡張) できないことを意味します。それ自体は、クラスを不変にするわけではありません。不変とは、オブジェクトが作成されると、その状態を変更できないことを意味します。StringBuffers は作成後に確実に状態を変更できるため、不変ではありません。

于 2013-08-22T19:36:05.110 に答える
1

クラスを宣言するfinalことは、それが不変であることを意味するのではなく、どのクラスもそれをサブクラス化できないことを意味します。実際、StringBuffer非常に可変です。それがクラスのポイントです。

StringBufferではないので、ComparableあなたはあなたTreeSetの をソートする方法を知りませんStringBuffersSetただし、変更可能なオブジェクトを任意の種類の(または)のキーにすることはお勧めできませんMap。を使用する必要がある場合は、オブジェクトを比較TreeSetするカスタム オブジェクトを作成して使用します。ComparatorStringBuffer

于 2013-08-22T19:36:27.807 に答える
0

はい、できますが、上記の回答が示すように、 Comparator を作成する必要があります。

しかし、本当の問題は、なぜそうしたいのですか? StringBuffer の目的は、文字列の作成中に状態を変更することです。これは SortedMap のキーであるため、キーを変更するべきではありません。そのため、StringBuffer を保存しても意味がありません。あなたがしたいことは、文字列を返す StringBuffer.toString() を呼び出し、その文字列をキーとして使用することです。

于 2013-08-22T20:16:10.520 に答える
0

TreeSetComparableas がオブジェクトでStringBufferはないオブジェクトのみを取りComaprableます。

TreeSet#add

Throws-ClassCastException - 指定されたオブジェクトを、現在このセット内にある要素と比較できない場合。

オブジェクトの代わりにオブジェクトを使用でき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);
于 2013-08-22T19:37:23.350 に答える
0

あなたはいくつかの質問をしています:

  1. 一般的な質問: 「ハッシュの変更可能なキーを使用できますか?」
  2. 具体的な質問: 「StringBuffer を TreeSet のキーとして使用できますか」

あなたは何か混乱していて、私はあなたがそれらを整理するのを手伝います

Maps in Java で使用される識別戦略は 2 つあります (多かれ少なかれ)。

  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 > comparison) を使用し、StringBuffer の独自の比較メソッドを定義します。

幸運を

于 2013-08-22T19:47:52.323 に答える