0

非常に具体的に行う必要があるプロジェクトがあり、助けが必要です。私は基本的にどこでも答えを探しましたが、スタックオーバーフローでも見つけることができません。ハッシュテーブルのクローン作成に関係しています。(浅いところも深いところも)

以下にコードを貼り付けましたが、要するに、Hashtable を拡張する EHashtable というクラスがあります。次に、さまざまなカスタム クラス タイプの文字列キーと値をいくつか追加します。EHashtable クラスには、Clone() および dClone() というメソッドがあります。Clone() は、その Hashtable の浅い複製を作成することになっています。つまり、Hashtable は複製されますが、その値は複製されません。dClone() は、新しい Hashtable を作成し、元のハッシュテーブルの各値をそれに複製することになっています (各値が最初のものとは異なるメモリ参照を指すことを意味します)。カスタムメイドのオブジェクトが複製可能でない場合にも、例外をスローすることになっています。

現在、浅いクローン (Clone() メソッド) でも、1 つの Hashtable の 1 つの値を変更し、もう 1 つの値は変更しません。各値が異なる参照を指しているように見えます。Clone() メソッドと dClone() メソッドに、2 つの異なる処理を実行させる方法がわかりません。もう1つ、ハッシュテーブルにはジェネリックを含めることはできません。である必要がHashtableありHashtable<K, V>ます。

ハッシュテーブルを for ループする方法を調べました。これはオブジェクト型でのみ機能し、オブジェクト型はメソッドの保護ステータスのために clone() できません。以下は、メインメソッドから始まる私のコードです。これは非常に具体的であり、すべての助けに感謝します。

import java.util.Hashtable;
import java.util.Iterator;

public class _Test {
    public static void main(String[] arguments) {
        Circle cr1 = new Circle(1);
        Circle cr2 = new Circle(2);
        Point po1 = new Point(10, 10);
        Point po2 = new Point(20, 20);
        PlaneCircle pcr1 = new PlaneCircle(po1, 11f);
        PlaneCircle pcr2 = new PlaneCircle(po2, 12f);

        EHashtable eh = new EHashtable(20);
        eh.add(new String("C1"), cr1);
        eh.add(new String("C2"), cr2);
        eh.add(new String("PC1"), pcr1);
        eh.add(new String("PC2"), pcr2);

        try {
            EHashtable ehCloned = (EHashtable) eh.Clone();

            System.out.println("/***--Before Alteration--***/");
            System.out.println("eh:");
            System.out.println(eh);
            System.out.println();
            System.out.println("ehCloned:");
            System.out.println(ehCloned);
            System.out.println();

            Circle cr3 = new Circle(99);
            Point po3 = new Point(99, 99);
            PlaneCircle pcr3 = new PlaneCircle(po3, 9999f);

            eh.add(new String("C1"), cr3);
            eh.add(new String("PC1"), pcr3);

            System.out.println("/***--After Alteration--***/");
            System.out.println("eh:");
            System.out.println(eh);
            System.out.println();
            System.out.println("ehCloned:");
            System.out.println(ehCloned);
            System.out.println();
        }

        catch (CloneNotSupportedException e) {
            System.out.println(e.toString());
        } 

        catch (ClassCastException e) {
            System.out.println(e.toString());
        }

        catch (Exception e) {
            System.out.println("\nError Message:" + e.getMessage());
        }
    }
}


import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

public class EHashtable extends Hashtable {
    public EHashtable() {

    }

    public EHashtable(int capacity) {

    }

    // Done
    public boolean add(Object key, Object value) {
        if (!(containsKey(key) && containsValue(value))) {
            put(key, value);
            return true;
        }

        else {
            return false;
        }
    }

    // Done
    public void Clear() {
        clear();
    }

    // Done
    public Object Clone() throws CloneNotSupportedException {
        EHashtable eh = (EHashtable) this.clone();
        return eh;
    }

    public Object dClone() {
        EHashtable eh = new EHashtable();
        for (Object key : keySet())
            eh.put(key, get(key));
        return eh;
    }

    // Done
    public boolean isNotEmpty() {
        return !isEmpty();
    }

    // Done
    public Iterator iterate() {
        return entrySet().iterator();
    }
}


public class Point {
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public String toString() {
        return "[x=" + x + ", y=" + y + "]";
    }
}


public class PlaneCircle {
    private Point p;
    private float radius;

    public PlaneCircle (Point p, float radius) {
        this.p = p;
        this.radius = radius;
    }

    public String toString() {
        return "[p=" + p.toString() + ", radius=" + radius + "]";
    }
}


public class Circle {
    private float radius;

    public Circle(float radius) {
        this.radius = radius;
    }

    public String toString() {
        return "[radius=" + radius + "]";
    }
}
4

5 に答える 5

0

最も簡単な方法は、HashMap をシリアライズおよびデシリアライズすることです。ただし、これには、すべてのキー クラスと値クラスに Serializable を実装する必要があります。ただし、Cloneable であるか Serializable であるかに関係なく、オブジェクト グラフをディープ コピーするには、いくつかの作業が必要です。

http://code.google.com/p/fast-serialization/ :-)のような高速シリアライザーを使用することをお勧めします。この方法でパフォーマンスは問題ないはずです

于 2013-11-02T16:45:48.623 に答える
0

効果的なJavaでこれを見つけました

public class HashTable implements Cloneable {
    private Entry[] buckets = ...;

    private static class Entry {
        final Object key;
        Object value;
        Entry next;
        Entry(Object key, Object value, Entry next) {
            this.key = key;
            this.value = value;
            this.next = next;
        }

        // Recursively copy the linked list headed by this Entry
        Entry deepCopy() {
            return new Entry(key, value,
                    next == null ? null : next.deepCopy());
        }
    }
    @Override public HashTable clone() {
        try {
            HashTable result = (HashTable) super.clone();
            result.buckets = new Entry[buckets.length];
            for (int i = 0; i < buckets.length; i++)
                if (buckets[i] != null)
                    result.buckets[i] = buckets[i].deepCopy();
            return result;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

もう1つの方法は次のとおりです。

SerializationUtils.clone() は、Map によって参照されるオブジェクトグラフ全体をシリアライズおよびデシリアライズするため、時間がかかります。ただし、これは真のディープ コピーを作成します (クラスでおかしなシリアライゼーションが行われていない場合)。

于 2013-11-02T16:34:34.217 に答える
0

大文字と小文字のみが異なるメソッド (clear、Clear、clone、Clone) を使用することはお勧めできません。superキーワードを使用してメソッドのスーパークラス実装を呼び出すことができるため、これは必要ありません。

Hashtable 自体は複製可能であるため、複製をオーバーライドする必要はありません。既存のクローン メソッドは、浅いクローンに必要なことを既に実行していますが、便宜上、それをオーバーライドして、オブジェクトの代わりに EHashtable の戻り値の型を与えることができます。

public EHashtable clone() {
    return (EHashtable)super.clone();
}

ディープ クローンの場合、その通りです。Object.clone は保護されているため、呼び出すことはできません。これは Java の歴史的な設計ミスです。それには厄介な方法があります(シリアル化、リフレクション、またはActuallyCloneableメソッドを公開するインターフェースの定義)が、これらのことを行う必要はないと思います(質問を貼り付けるときに簡潔にするためにミューテーターメソッドを省略しない限り)テーブルに格納しているすべての型は不変のようです。それらが変更できない場合、それらを複製しても意味がありません。

実際のコードでそれらが不変でない場合、それらを不変にすることは、これらの単純な値型にとって実際には非常に良い考えです。いつコピーする必要があるかを気にする必要がないため、他のコードを単純化できます。

現在、浅いクローン (Clone() メソッド) でも、1 つの Hashtable の 1 つの値を変更し、もう 1 つの値は変更しません。

あなたは価値観を変えていません。あなたは新しいものを入れています。値を変更すると、次のようになります。

cr1.radius = 123;

オブジェクトが不変の場合、これは不可能ですが、元のハッシュテーブルとその浅いクローンの両方から見たオブジェクトが変更されます。

いくつかのマイナーな提案: (1)toString()例外の出力は、その名前とメッセージのみを出力します。スタックトレース情報が失われます。スタックトレースも取得するには、printStackTrace()メソッドを使用します。これには、stdout ではなく stderr に確実に出力されるという利点もあります (これにより、より見やすくなる可能性があります。Eclipse では明るい赤です)。例えば、

catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

または、特定のチェック済み例外で実行できる有用なことが何もない場合は、単純に未チェック例外として再スローすることをお勧めします。これにより、エラーが発生しても周囲のコードが処理されなくなります。

catch (CloneNotSupportedException e) {
    throw new RuntimeException(e);
}

(2) 実行eh.add(new String("C1"), cr1);(新しい文字列の作成) は愚かなアンチパターンであり、利点がなく、不要なオブジェクトの作成と入力のオーバーヘッドが追加されます。に変更できますeh.add("C1", cr1);

于 2013-11-02T17:26:01.553 に答える
0

シリアライゼーションのアイデアに加えて、ファイル、データベース、XML/json などとの間でマップを永続化する既存のコードがある場合、それは「迅速かつ汚い」オプションになります。パフォーマンスは速くありませんが、コーディングは迅速です。

于 2013-11-02T17:34:59.097 に答える