Javaジェネリッククラスにパラメーターとしてクローン可能なタイプを使用する方法
質問
パラメータータイプのオブジェクトをクローン化できる必要がある汎用クラスがあります。非常に簡単な例を以下に示します。コンパイラは、タイプオブジェクトからclone()が表示されないと主張します。
public class GenericTest<T extends Cloneable>
{
T obj;
GenericTest(T t)
{
obj = t;
}
T getClone()
{
// "The method clone() from the type Object is not visible."
return (T) obj.clone();
}
}
オブジェクトの完全性を維持するためにたまたま他のことがあるので、発信者にクローンをさせないことを好みません。上記のコードは、クローンされたオブジェクトに関連する他のデータのノイズのない問題の単なる例です。
これを回避する方法はありますか、それともJavaの設計者がその欠点を合理化していると考えている場合、これは他の1つですか?
解決
Java側の間違い。反射は正しい方法です
static Method clone = Object.class.getMethod("clone");
static public <T extends Cloneable>
T clone(T obj)
return (T) clone.invoke(obj);
他のヒント
この方法はとしてマークされているためです protected
に Object
クラスでは、一般的に任意のオブジェクトでこのメソッドを呼び出すことはできません。個人的に私はこれが最初は問題になるとは思わなかった(ねえ、私はのサブクラスだ Object
, 、だから私はその保護された方法を呼び出すことができるはずですよね?)、しかし、コンパイラはあなたがのサブクラスであることを知る必要があります ターゲットオブジェクト保護されたメソッドを呼び出すために(またはそのパッケージ内)のクラス(またはそのパッケージ内)。どちらもここでは適用されません。
背後にあるアイデア clone()
方法は、それをサポートしたクラスがメソッドをオーバーライドし、それをとして宣言することです public
.
完全な機能を保持する唯一の実際のソリューションは、反射を使用してメソッドにアクセスし、アクセス修飾子を回避することです。別の方法は、あなた自身を書くことです MyCloneable
a 公衆 clone()
その上に宣言された方法。これは、あなたが独自のドメインクラスを通過するだけである場合に機能するかもしれませんが、外部クラスで使用できないことを意味します( java.util.String
また java.util.ArrayList
)あなたは彼らにあなたのインターフェイスを実装するように強制することができないので。
の回答に従って リンクされた質問, 、これは非常に疑わしいデザインです。
フィールドが入ったポジョをクローンする必要がありました。仕事は次のとおりでした:
public static Object clone(Object o)
{
Object clone = null;
try
{
clone = o.getClass().newInstance();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
// Walk up the superclass hierarchy
for (Class obj = o.getClass();
!obj.equals(Object.class);
obj = obj.getSuperclass())
{
Field[] fields = obj.getDeclaredFields();
for (int i = 0; i < fields.length; i++)
{
fields[i].setAccessible(true);
try
{
// for each class/suerclass, copy all fields
// from this object to the clone
fields[i].set(clone, fields[i].get(o));
}
catch (IllegalArgumentException e){}
catch (IllegalAccessException e){}
}
}
return clone;
}