“動的” Javaでのキャスト
-
03-07-2019 - |
質問
Hullo all、
次のことがうまくいかない理由を教えてくれるJavaハッカーがあるかどうか疑問に思います:
public class Parent {
public Parent copy() {
Parent aCopy = new Parent();
...
return aCopy;
}
}
public class ChildN extends Parent {
...
}
public class Driver {
public static void main(String[] args) {
ChildN orig = new ChildN();
...
ChildN copy = orig.getClass().cast(orig.copy());
}
}
コードはコンパイルしても問題ありませんが、ランタイムD =でClassCastExceptionをスローすることにしました
編集:おっと、本当に迅速な返信。みんなありがとう!だから私はこの方法を使用してダウンキャストできないようです... Javaでダウンキャストを行う他の方法はありますか?各 ChildN
クラスが copy()
を上書きすることを考えましたが、余分な定型コードを追加することに熱心ではありませんでした。
解決
(コメントにコードを追加できないため、ここに追加します)
Cloneableについて:Cloneableを実装する場合は、次のように実装します。電話をかける方がずっときれいです...
public class Foo implements Cloneable {
public Foo clone() {
try {
return (Foo) super.clone();
} catch (CloneNotSupportedException e) {
return null; // can never happen!
}
}
[編集:他の人々が使用しているのを見た
throw new AssertionError("This should never happen! I'm Cloneable!");
catchブロック内。]
他のヒント
これをしようとするのは好きです:
public Object copy(){
return new Object();
}
そして、次のことを試みます:
String s = ( String ) copy();
Parent クラスと ChildN クラスは、 Object および String
と同じ関係にありますそれを機能させるには、以下を実行する必要があります:
public class ChildN extends Parent {
public Parent copy() {
return new ChildN();
}
}
つまり、「コピー」を上書きします。メソッドと正しいインスタンスを返します。
編集
編集に従って。それは実際に可能です。これは可能な方法の1つです。
public class Parent {
public Parent copy() {
Parent copy = this.getClass().newInstance();
//...
return copy;
}
}
この方法では、「コピー」をオーバーライドする必要はありません。各サブクラスのメソッド。これがプロトタイプのデザインパターンです。
ただし、この実装を使用する場合は、2つのチェック済み例外に注意する必要があります。コンパイルして問題なく実行できる完全なプログラムを次に示します。
public class Parent {
public Parent copy() throws InstantiationException, IllegalAccessException {
Parent copy = this.getClass().newInstance();
//...
return copy;
}
}
class ChildN extends Parent {}
class Driver {
public static void main(String[] args) throws InstantiationException , IllegalAccessException {
ChildN orig = new ChildN();
ChildN copy = orig.getClass().cast(orig.copy());
System.out.println( "Greetings from : " + copy );
}
}
キャストは事実上これを試みています:
ChildN copy = (ChildN) orig.copy();
(実行時に実行するキャストを実行していますが、それは orig.getClass()
が ChildN.class
になるためです。) code> orig.copy()はChildNのインスタンスを返さず、単なる Parent
のインスタンスを返すため、 ChildN
。
ChildNがcopy()をオーバーライドしてChildNのインスタンスを返さない場合、親タイプのオブジェクトを子タイプにダウンキャストしようとしています
java.lang.Class#cast(Object)は、Class#isInstance()がfalseを返すとClassCastExceptionをスローします。そのメソッドのjavadocから:
指定されたオブジェクトが オブジェクトとの割り当て互換性 このクラスによって表されます。この方法 Javaの動的な同等物です 言語instanceof演算子... 具体的には、この場合
Class
オブジェクトは、 宣言されたクラス、このメソッドはtrue
指定された場合Object
引数は 表現されたクラスのインスタンス(または そのサブクラスのいずれか);それは戻ります それ以外の場合はfalse
。
Parentは子のサブクラスではないため、isInstance()はfalseを返すため、cast()は例外をスローします。これは最小限の驚きの原則に違反する可能性がありますが、文書化された方法で機能しています-cast()はダウンキャストではなくアップキャストのみ可能です。
単にオブジェクトのコピー/クローンが必要なのでしょうか。
その場合、Cloneableインターフェースを実装し、必要に応じてclone()をオーバーライドします。
public class Parent implement Cloneable {
public Object clone() throws CloneNotSupportedException {
Parent aCopy = (Parent) super.clone();
...
return aCopy;
}
}
public class ChildN extends Parent {
...
}
public class Driver {
public static void main(String[] args) {
ChildN orig = new ChildN();
...
ChildN copy = orig.getClass().cast(orig.clone());
}
}
これは、あなたの" copy()"とまったく同じです。メソッドはJavaの方法で実行しようとしました。
(はい、あなたは凝ったイントロスペクションゲームもできますが、これらのメソッドはパブリックデフォルトコンストラクタがないとすぐに失敗するかorいものになります。クローンはどんなコンストラクタを使用しても動作します。)
ダウンキャストが機能しない理由は、親オブジェクトを子タイプにキャストすると、親オブジェクトで子タイプのメソッドを呼び出すことができないためです。しかし、それは他の方法で動作します...