総称型を利用したオブジェクトの複製

# はじめに

同一でないオブジェクトを複製させるために、Cloneableインターフェースを実装して`Object#clone`をオーバーライドさせるやり方があります。

ただ、次のコードのように総称型を利用したオブジェクトの複製をしたいときに、直接`Object#clone`にアクセスできずにもどかしい思いをしたので、総称型を利用してもオブジェクトの複製ができるように色々と工夫することとしました[^best]。

```Java:
class GenericsSample {
    @SuppressWarnings("unchecked")
	static <T> T cloneSample(T obj) {
        return (T) obj.clone(); // コンパイルエラー（不可視なcloneメソッド）
    }
}
```

# インターフェースの導入

```Java:
public interface CloneablePublicly<T> {
    T clone();
}
```

`Object#clone`の代わりに外部から複製するためのメソッドを呼び出すためのインターフェースを作りました。総称型を利用するオブジェクトのクラスに対し、こいつを実装させます。

```Java:実装例
class Sample implements Cloneable, CloneablePublicly<Sample> {
    int value;
    public Sample(int value) {
        this.value = value;
    }
    @Override public Sample clone() {
        try {
            return (Sample) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
    }
}
```

勿論、Cloneableインターフェースも同時に実装させます。これが実装されていないと、`CloneNotSupportedException`を吐きます。

# オブジェクトの複製

あとは、例えば次のようにメソッドを修正すれば、総称型を利用したオブジェクトの複製が可能となります。

```Java:
class GenericsSample {
    @SuppressWarnings("unchecked")
    static <T> T cloneSample(T obj) {
        if (obj instanceof Cloneable && obj instanceof CloneablePublicly) {
            return ((CloneablePublicly<T>) obj).clone();
        }
		return null;
    }
}
```

```Java:使用例
Sample samp1 = new Sample(1);
Sample samp2 = GenericsSample.cloneSample(samp1);
System.out.println(samp1.value);    // 1
System.out.println(samp2.value);    // 1
System.out.println(samp1 == samp2); // false（同一でないオブジェクトの複製）
```

## おまけ

nullを返したくない場合は、次のようにオプショナルを返します[^コスト]。これにより、オブジェクトを複製できない場合は何もしないようにすることもできます。

```Java:
class GenericsSample {
    @SuppressWarnings("unchecked")
    static <T> Optional<T> cloneSample(T obj) {
        return Optional.ofNullable(obj)
            .filter(Cloneable.class::isInstance)
            .filter(CloneablePublicly.class::isInstance)
            .map(o -> ((CloneablePublicly<T>) obj).clone());
    }
}
```

```Java:使用例
Sample samp1 = new Sample(1);
GenericsSample.cloneSample(samp1).ifPresent(samp2 -> {
    System.out.println(samp1.value);    // 1
    System.out.println(samp2.value);    // 1
    System.out.println(samp1 == samp2); // false（同一でないオブジェクトの複製）
});

// Sample samp1 = null; のときは、何もしない。
```

# 追記

@saka1029 さんのコメントより、インターフェースの継承と境界型パラメータを用いた実装をご紹介いただきました。ありがとうございます！

```Java:Cloneableインターフェースの継承
interface CloneablePublicly<T> extends Cloneable {
    T clone();
}
```

こうすればわざわざ総称型を利用するオブジェクトのクラスに対しCloneableインターフェースを実装せずに済みますね。~~インターフェースの継承機能をすっかり忘れていました。~~

```Java:実装例
class Sample implements CloneablePublicly<Sample> {
    ... // 同じ
}
```

```Java:
class GenericsSample {
    static <T extends CloneablePublicly<T>> T cloneSample(T obj) {
        return Objects.isNull(obj) ? null : obj.clone();
    }
}
```

境界型パラメータを用いて型安全性を確保すれば、手書きでキャスト検査する必要もなくなります。
オプショナルも、一行で済んでしまいました。

```Java:
class GenericsSample {
    static <T extends CloneablePublicly<T>> Optional<T> cloneSample(T obj) {
        return Optional.ofNullable(obj).map(CloneablePublicly::clone);
    }
}
```

[^best]: 色々と調べたのですが、良さそうな資料が見つからなかったので自作しました。ベストプラクティスな方法やご指摘などございましたら、恐れ入りますがご教示いただけますと幸いです。
[^コスト]: 「Effective Java 第3版」によればOptionalを頻繁に用いるとコストがかかるとのことなので、パフォーマンスが気になる場合は控えたほうが良いかもしれません。