2

Javaでのコピー構築について質問があります。次のクラスを検討してください。

コピー コンストラクターでは、コンストラクターに渡される新しい整数オブジェクトを取得するために new(Integer(other.id)) と言うことができますが、コンパイラーが型をインスタンス化できないと言うので、 new T(other.data) とは言えません。 T.ジェネリックアイテムがコピー構築されているときに、2つのオブジェクトが基になるデータを共有するように参照を渡すだけではないことを確認するにはどうすればよいですか。

また、getLinksメソッドでは、リストの新しいオブジェクトを作成して新しいオブジェクトを作成していますが、リストに含まれるアイテムの新しいオブジェクトをディープコピーして作成するか、既存のオブジェクトリストアイテムへの参照を含むだけですか?両方が同じデータを指している 2 つのリストがあること。コメント/コードの下を参照してください。あなたの専門知識を前もって感謝します。

class DigraphNode<T>  
{
    Integer id;
    T data;
    ArrayList<DigraphNode<T> > links;

    public DigraphNode(Integer i) 
    {
        id = i; 
        links = new ArrayList<DigraphNode<T> >();
    }
    public DigraphNode(Integer i, T d) 
    { 
        id = i; data = d; 
        links = new ArrayList<DigraphNode<T> >();
    }

    public DigraphNode(DigraphNode<T> other)
    {
        other.id = new Integer(other.id);
        other.data = other.data; // line in question
        this.links=other.getLinks(); // also will create a new list with references
                                     // or will it deep copy the items contained in the list?
                                     // see getLinks() method below
    }

    public void setData (T d ) { data =  d; }
    public void addLink (DigraphNode<T> n) { links.add(n); }
    public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }

    public ArrayList<DigraphNode<T> > getLinks()
    {
        return new ArrayList<DigraphNode<T> >(links); 
    }

    public void printNode()
    {
        System.out.print("Id: " + id + " links: ");
        for ( DigraphNode<T> i : links )
        {
            System.out.print(i.id + " ");
        }
        System.out.println();
    }
}
4

3 に答える 3

1

  1. new T(other.data)試したようにインスタンス化することはできませんがclone()T implements Cloneable
  2. を呼び出すたびに、getLinks()に含まれるオブジェクトを参照して新しいリストが作成されますlinks。内部で同じ参照を持つ別のリストが必要です (したがって、1 つの参照オブジェクト プロパティを変更すると、同じオブジェクトであるため、他のリスト オブジェクトに反映されます)。
  3. ArrayList<> links = new ArrayList<>();オラクルのドキュメントから:

    インスタンス変数の初期化ブロックは静的初期化ブロックと同じように見えますが、 static キーワードがありません:
    {
    // 初期化に必要なコードはすべてここに記述します
    }
    Java コンパイラは初期化ブロックをすべてのコンストラクタにコピーします。したがって、このアプローチを使用して、複数のコンストラクター間でコードのブロックを共有できます。

編集:可能なすべての戦略を使用して汎用オブジェクトをコピーしようとする
静的メソッド ( ) を定義できます。copy最善のアプローチは、独自のインターフェースを定義して独自の戦略を分離し、一種のコピーコンストラクターをシミュレートすることです (必要にcopy応じてメソッドを再利用できます)。それ以外の場合は、シリアル化を介して、または最後の試みとして、クローニングを使用します (ただしclone()、落とし穴がいっぱいです)。 .
次のライブラリも使用できます。


interface MyCloneableInterface<T> {
  T duplicate(T object) throws CopyException;
}
public static <T> T copy(T data) throws CopyException  {
  if(data == null) return null;
  if(data instanceof MyCloneableInterface) {
    return ((MyCloneabeInterface)data).duplicate(data);
  }
  if(data instanceof Serializable) {
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(baos);
      oos.writeObject(this);

      ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(bais);
      return (CloneExample) ois.readObject();
    }
    catch(...) {//rethrow}
  }
  if(data instanceof Cloneable) {
    try {
      return (T)data.clone();
    }
    catch(CloneNotSupportedException e) {//rethrow}
  }
  // else you can look for copy-constructor via reflection or
  // cloning object field-by-field via reflection...
}
于 2013-08-17T23:38:53.367 に答える
1

最初の質問: ジェネリック インスタンスをインスタンス化することはできません (つまり、Tのコンストラクターを呼び出します)。が常に制御下にある場合は、独自の別のインターフェイスを定義T implements Cloneableして呼び出すか、使用する必要があります。このメソッドには多くの落とし穴があります。最初にこのインターフェースについて読んで、落とし穴に慣れることをお勧めします (「Effective Java」ブックで、これに関するすばらしい章を見つけることができます)。また、このクラスがである型を使用することを常に保証できるとは限りません。cloneTTCloneable

についてlinks- 最初にインスタンス化してから、コンストラクターでオーバーライドしています - なぜですか? 初期化を削除します。あなたのやり方getLinksは、ディープコピーを作成することではありません。つまり、新しいリストを取得します。リスト自体は元のリストとは異なりますが、アイテムは浅いコピーになります。

あなたの最後の質問について - 私がすでに言ったように、それは冗長です。最初の初期化を削除します。オブジェクトを作成しています。決して使用せず、ガベージ コレクションに残してください。すべてのコンストラクターでこれを呼び出さないようにするためにできることは、次のようなものです。

public DigraphNode() {
    links = new ArrayList<DigraphNode<T> >();
}

そして、他のコンストラクターがこのコンストラクターを呼び出すようにします。次に例を示します。

public DigraphNode(T val) {
    this();
    this.data = val;
}
于 2013-08-17T23:39:23.323 に答える
0

すべての役立つ回答に賛成票を投じましたが、更新されたコードを示す以下の自分の質問に答えています。誰かがジェネリックのコピーを実装する方法を見たかったのですが、そのためのコードを投稿した人は誰もいなかったので、自分で作成しました。以下の私の答えを参照してください。

import java.lang.reflect.*;
import java.util.*;

class MissingDigraphNodeException extends Exception 
{
    private static final long serialVersionUID = 1000L;
    public MissingDigraphNodeException(String message)
    {
        super(message);
    }
}

class CopyException extends Exception 
{
    private static final long serialVersionUID = 2000L;
    public CopyException(String message)
    {
        super(message);
    }
}

class DigraphNode<T>  
{
    Integer id;
    T data;
    ArrayList<DigraphNode<T> > links;

    public DigraphNode(Integer i) 
    {
        id = i; 
        links = new ArrayList<DigraphNode<T> >();
    }
    public DigraphNode(Integer i, T d) 
    { 
        id = i; data = d; 
        links = new ArrayList<DigraphNode<T> >();
    }

    public DigraphNode(DigraphNode<T> other)
    {
        try
        {
            this.data = copy(other.data);
        }
        catch (CopyException e)
        {
            e.printStackTrace();
        }
        this.links=other.getLinks();
        this.id = new Integer(other.id);
    }

    // is there a better way to copy a generic?
    @SuppressWarnings("unchecked")
    public T copy( T source ) throws CopyException
    {
        Class<?> clzz = source.getClass();
        Method meth;
        Object dupl = null;
        try {
            meth = clzz.getMethod("clone", new Class[0]);
            dupl = meth.invoke(source, new Object[0]);
        } catch (Exception e) 
        {
            e.printStackTrace();
            throw new CopyException("Error: Copying Generic of T");
        }   
        return (T) dupl;
    }

    public void setData (T d ) { data =  d; }
    public void addLink (DigraphNode<T> n) { links.add(n); }
    public void addLinks (ArrayList<DigraphNode<T> > ns) { links.addAll(ns); }

    public ArrayList<DigraphNode<T> > getLinks()
    {
        // return a new copy of the list
        ArrayList<DigraphNode<T> > l = new ArrayList<DigraphNode<T> >(); 
        for ( DigraphNode<T> i : links )
        {
            i.links.add(new DigraphNode<T>(i)); // use copy constructor
        }
        return l;
    }

    public void printNode()
    {
        System.out.print("Id: " + id + " links: ");
        for ( DigraphNode<T> i : links )
        {
            System.out.print(i.id + " ");
        }
        System.out.println();
    }
}
于 2013-08-18T08:01:41.537 に答える