7

従業員クラスの親が抽象で、親クラスの clone() メソッドが抽象の場合に、このクローン メソッドを作成しました。各プリミティブ データをコピーする代わりに、このコードで従業員のオブジェクトのプリミティブ データ型をコピーしたかったのです。個別に入力しますが、このコードには clone() メソッドを呼び出す行に問題があります。(このコードは Employee クラスにあります)

public Object clone() {
    Object obj = new Object();
    Object object = obj.clone();  //Emphasis here
    return object;

}

エラー: Object 型のメソッド clone() が表示されません。

しかし、私の Employee クラスは、Object クラスの保護された clone() メソッドにアクセスできるクラス階層にあります。

これは私の単純な Employee クラスです:

public class Employee extends Person implements Cloneable {
private int ID;

public Employee() {
    ID = 0;
}

public void setID(int ID) {
    this.ID = ID;
}

public int getID() {
    return ID;
}

public Object clone1() throws CloneNotSupportedException {
    try {
        Object obj = new Object();

        Object object = obj.clone();
        return object;
    } catch (CloneNotSupportedException ex) {
        return null;
    }
}
4

9 に答える 9

11

クラスを複製可能にするための標準的なパターンは次のとおりです。

  1. 埋め込むCloneable
  2. メソッドをオーバーライドしclone()て公開する
  3. clone()呼び出し中super.clone()、可変オブジェクトの状態をコピーする

を使用して新しいオブジェクトを作成しないでくださいnewsuper.clone()適切な方法は、新しいインスタンスを呼び出すことです。Objectは特別で、オブジェクトのclone()新しいコピーを作成し、そのプリミティブ フィールドと参照をコピーします。

例えば:

public class Person implements Cloneable {
    protected String name;
    // Note that overridden clone is public
    public Object clone() {
        Person clone = (Person)super.clone();
        // No need to copy name as the reference will be
        // copied by Object's clone and String is immutable
        return clone;
    }
}

public class Employee extends Person {
    protected int id;
    protected java.awt.Point location;
    public Object clone() {
        Employee  clone = (Employee )super.clone();
        // No need to copy id as Object's clone has already copied it
        // Need to clone location as Point is mutable and could change
        clone.location = location.clone();
        return clone;
    }
}
于 2009-06-27T17:17:05.700 に答える
6

Java の複製メカニズムはやや扱いにくいものです。自分自身を複製できるようにするために、クラスは 2 つのことを行う必要があります。まず、Clonable を実装する必要があります。次に、 clone() をオーバーライドして公開する必要があります。

あなたの例では、 clone() をオーバーライドしましたが、 Employee クラスではなく、 clone() が保護されているだけの Object.class() で clone() を呼び出しています。

于 2009-06-27T08:09:05.333 に答える
4

Effective Java の Mister Bloch は、 の使用について興味深い言葉をいくつか述べていますclone

http://www.artima.com/intv/bloch13.html

一般に、クローンはエラーが発生しやすく誤解が多いため、コピー コンストラクターを実装するか、シリアライゼーションを使用してオブジェクトをディープ コピーするブルート フォース アプローチを使用するため、クローンの使用を避けるのが現在の考え方です。

于 2009-06-27T08:19:14.923 に答える
2

オブジェクトに Cloneable インターフェースを実装しましたか?

ただし、オブジェクトのコピーにクローンを使用するケースはほとんどありません。そのような安全な例の 1 つが array.clone() です。私はむしろコピーコンストラクターのイディオムを使用するか、手動で値をコピー/割り当てます。

背景問題については、 Effective Java (第 2 版) のItem#11 があります。Objectクローン可能インターフェイスは、クローンに関するクラスの動作を変更する特別な種類のインターフェイスです。基本的には、 Java でクラスインターフェイスを有効にする機能です。

編集:あなたの例に基づいて、一般的なケースでは、Clone() 呼び出しを CloneNotSupportedException の try-catch でラップする必要がある場合があります。

Edit2:私の答えを言い換えました

Edit3:コンテキストで clone() をオーバーライドしましたpublicか? あなたが与えたサンプルでは、​​Java.langパッケージにあるオブジェクトのクローンを作成しようとしました-コードが含まれているパッケージはほとんどありません.

Edit4:答えはすでに他の投稿にあると思いますが、根本的な問題を反映したかっただけです。

Edit5:これを試してください:

public Object clone1() throws CloneNotSupportedException {        
    return super.clone();        
}

Edit6public abstract Object copy()次に、たとえばメソッドに名前を付け、実装では、混乱を避けるために super.clone() を使用します。

Edit7私はいくつかの日食を行い、次の解決策を出しました:

public class Cloner {
    public static abstract class Person {
       protected abstract Object clone1() throws CloneNotSupportedException;
       public Object copy() throws CloneNotSupportedException {
           return clone1();
       }
    }
    public static class Employee extends Person implements Cloneable {
        @Override
        protected Object clone1() throws CloneNotSupportedException {
            return super.clone();
        }
    
    }
    public static void main(String[] args) throws Exception {
        new Employee().copy();
    }
}

ただし、基本的には、抽象メソッドの名前を clone() 以外の名前に変更するのと同じ概念です。

Edit8:サンプルを修正しました。例外なく動作するようになりました。

(しかし、実際の功績はGáborHargitaiに送られsuper.clone()ます)

于 2009-06-27T07:59:05.213 に答える
2

あなたは単に書くべきです

return super.clone(); 

clone メソッドで Clonable インターフェイスを実装します。

于 2009-06-27T08:11:02.070 に答える
0

適切なインターフェースを実装しましたか? あなたはすでにこれを説明しているかもしれませんが、それはそれと同じくらい簡単かもしれません.

詳細については、http: //java.sun.com/javase/6/docs/api/java/lang/Object.html#clone()を参照してください。

于 2009-06-27T07:58:51.470 に答える
0

私はJavaにあまり詳しくありませんが、これが役立つかもしれません: http://en.wikipedia.org/wiki/Clone_(Java_method)

投稿からの抜粋:

もう 1 つの欠点は、抽象型の clone() メソッドにアクセスできないことが多いことです。Java のほとんどのインターフェースと抽象クラスは public clone() メソッドを指定しません。その結果、クローン() メソッドを使用する唯一の方法は、オブジェクトの実際のクラスを知っている場合です。これは、可能な限り最も一般的な型を使用するという抽象化の原則に反しています。たとえば、Java に List 参照がある場合、List は public clone() メソッドを指定していないため、その参照に対して clone() を呼び出すことはできません。ArrayList や LinkedList などの List の実際の実装はすべて、一般に clone() メソッド自体を持っていますが、オブジェクトの実際のクラス型を持ち歩くのは不便で悪い抽象化です。

于 2009-06-27T08:08:27.503 に答える
-2

基本的に、適切に複製可能なオブジェクトを作成するには、そのクラスに public clone() メソッドを実装するだけで十分です。

Cloneable インターフェースはmarker、デフォルトの保護された clone() メソッドをフィールドごとのコピーとして安全に実装できることを VM に通知するために使用されるインターフェースです。

クラスの clone メソッドを適切に実装するには、this() のように public メソッド clone を宣言する必要があります。

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

適切に機能する実装では、新しいオブジェクトが作成され、ビジネス ロジックの要求に応じてフィールドが適切に割り当てられます。

public Object clone() {
   CurrentClass newObject = new CurrentClass();

   newObject.field1 = this.field1; // for simple types: int, long, etc
   newObject.referenceField = this.referenceField.clone(); // for agregate objects or references.
   return newObject;
}

結論: public clone メソッドを宣言します。デフォルトの実装をフィールドごとのコピーとして使用する場合は、super を呼び出し、クラスを Cloneable としてマークします。カスタム クローンのみが必要な場合は、Cloneable マークを無視できます。

于 2009-06-27T08:49:32.820 に答える