JAvaにおけるcloneソースの解析


Android開発ではcloneがよく使われていますが、実は最下層の実装実行を追及しなければ、これはよく理解できます.
まずcloneは深いコピーと浅いコピーに分けられます.これは簡単です.まず、次のコードを見てみましょう.
class User {
    String name;
    int age;
}
class Account implements Cloneable {
    User user;
    long balance;
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

Accountでcloneメソッドを実行すると、浅いコピーにすぎません.なぜですか.AccountにはUserタイプの参照があるため、cloneメソッドを使用して新しいオブジェクトをコピーします.Userタイプの参照も含まれていますが、この新しいオブジェクトと元のオブジェクトのUser参照は同じUserオブジェクトを指しています.ここでコピーしたのはUserの参照を新しいオブジェクトにコピーしただけなので、ただし、新しいUserオブジェクトは作成されていません.
深いコピーとは,参照をコピーするだけでなく,Account内のすべてのオブジェクトをコピーすることである.次のコードを再実装します.
class User implements Cloneable {
    String name;
    int age;
    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }
}
class Account implements Cloneable {
    User user;
    long balance;
    @Override
    public Account clone() throws CloneNotSupportedException {
        Account account = null;
        account = (Account) super.clone();
        if (user != null) {
            account.user = user.clone();
        }
        return account;
    }
}

実は上のUserの中にはStringの参照があり、それは浅いコピーを実現しただけです.Userの中のcloneメソッドがコピーした新しいオブジェクトの中のString参照が元の参照と同じオブジェクトを指しているからです.
また、クラスをカスタマイズしてcloneメソッドを使用して自己コピーを行う必要がある場合は、Cloneableインタフェースを継承する必要があります.なぜですか?Cloneableインタフェースコードを見てみましょう.
public interface Cloneable {
    // Marker interface
}

この中には何もありませんが、私たちのclone方法はどこから来たのですか?一般的にクラスをカスタマイズすると、デフォルトではObjectクラスが継承され、cloneメソッドが継承されることを知っています.このメソッドはObjectクラスにしか来ません.Objectオブジェクトのコードを直接見てみましょう.
public class Object {
    protected Object clone() throws CloneNotSupportedException {
        if (!(this instanceof Cloneable)) {
            throw new CloneNotSupportedException("Class " + getClass().getName() +
                                                 " doesn't implement Cloneable");
        }

        return internalClone();
    }

    /* * Native helper method for cloning. */
    private native Object internalClone();
}

上には一部のコードしかありません.Objectには確かにこの方法があることがわかります.また、この方法を使用する場合は、オブジェクトがCloneableのインスタンスでなければなりません.そうしないと、エラーが発生します.これは、カスタムクラスがこの空のインタフェースを継承しなければならない理由です.このインタフェースを継承すると、internalCloneメソッドを実行する機会があり、コピー作業を行うnativeメソッドであることがわかります.したがって、CloneableはSerializableと同様にタグ型インタフェースであり、内部にはメソッドと属性がなく、implements Cloneableはオブジェクトがクローン化され、Object.clone()メソッドが使用できることを示していることがわかります.
上のcloneメソッドはProtectedタイプであり、このメソッドを直接書き換えると、直接呼び出すこともできません.これもpublicのcloneメソッドを再作成する必要がある理由です.次に、Cloneableインタフェースを適用したクラスがpublicのclone()メソッドを書き直さなければならない理由についてまとめます.ここでは,(1)書き換えなければObject.clone()がproteced属性であるため,このclone()メソッドは外部で呼び出すことができず,より正確にはターゲットクラス以外のどこでも呼び出すことができない.これによりクローンは武力行使の場を失った.(2)Object.clone()は結局浅いコピーを提供しただけであり,基本タイプのフィールドについてはクローン化に成功したと言える.しかし、オブジェクト型フィールドでは、クローン機能は実装されず、割り当てられた値だけが作成されます.
参考記事:javaのcloneを深く理解する