Javaのオブジェクトのクローンについて

Javaのオブジェクトのクローンについて

このページでは、Javaでオブジェクトをクローンする方法について解説します。各セクションにジャンプできるリンクを以下に用意しています。

オブジェクトをクローンする理由

Javaプログラムでは、あるオブジェクトをそのままコピーしたい場合があります。その目的は以下の通りです。

  • オリジナルのオブジェクトを変更せず、別のオブジェクトを生成して独立して操作する。
  • データ構造の複製やバックアップを作成する。
  • オブジェクトの状態を保存し、元に戻せるようにする。

Cloneable インターフェースの役割

Javaでは、java.lang.Cloneable インターフェースを使用してオブジェクトをクローンできます。このインターフェースを実装することで、オブジェクトのクローンを許可する意図を示します。

重要なポイント:

  • Cloneable はマーカーインターフェースであり、メソッドを提供しません。
  • Object クラスの clone() メソッドをオーバーライドする必要があります。

使用例


class Example implements Cloneable {
    public int value;

    public Example(int value) {
        this.value = value;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Main {
    public static void main(String[] args) {
        try {
            Example original = new Example(10);
            Example clone = (Example) original.clone();
            System.out.println("Original value: " + original.value);
            System.out.println("Cloned value: " + clone.value);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
    

浅いコピー(Shallow Cloning)

浅いコピーは、オブジェクトのフィールドをそのままコピーしますが、参照型フィールドは新しい参照先を作成せず、元のオブジェクトの参照を保持します。

例:


class Person implements Cloneable {
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person original = new Person("Alice", 30);
        Person clone = (Person) original.clone();
        clone.name = "Bob";

        System.out.println("Original name: " + original.name); // Alice
        System.out.println("Cloned name: " + clone.name); // Bob
    }
}
    

深いコピー(Deep Cloning)

深いコピーでは、オブジェクトの全てのフィールドが再帰的にクローンされます。これにより、参照型フィールドも新しいオブジェクトとして生成されます。

例:


class Address implements Cloneable {
    public String city;

    public Address(String city) {
        this.city = city;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

class Employee implements Cloneable {
    public String name;
    public Address address;

    public Employee(String name, Address address) {
        this.name = name;
        this.address = address;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Employee cloned = (Employee) super.clone();
        cloned.address = (Address) address.clone();
        return cloned;
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("Tokyo");
        Employee original = new Employee("John", address);
        Employee clone = (Employee) original.clone();
        clone.address.city = "Osaka";

        System.out.println("Original city: " + original.address.city); // Tokyo
        System.out.println("Cloned city: " + clone.address.city); // Osaka
    }
}
    

クローンの実例

  • オブジェクトの履歴管理: 変更前の状態を保持。
  • データのシミュレーション: 元データを変更せずに実験。
  • 設計パターン: Prototypeパターンでの活用。

クローンの制限と課題

  • Cloneable インターフェースの柔軟性が低い。
  • 深いコピーはコードが複雑になる。
  • クローンの動作が予測しにくい場合がある。

クローンの代替方法

  • コピーコンストラクタを使用。
  • シリアライズとデシリアライズを使用。
  • 外部ライブラリ(Apache Commons LangのSerializationUtilsなど)を使用。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です