質問
Javaで3つのクラスがあり、CがBから拡張し、Aから拡張すると仮定します。
class X {
interface A {}
interface B extends A {}
interface C extends B {}
void f(A a) {}
void test() {
C c = new C()
B b = (B) c;
f(b);
}
}
上記の test()
に示されているように、このようなことをした場合:
C c = new C()
B b = (B) c;
f(b);
f()
は、 C
および B
であるため、タイプ C
として b
を受け入れます。両方とも A
から拡張されます。私は f()
に b
を C
ではなく B
型として受け取りたいと思いました。
このアップキャストを強制する方法はありますか?
解決
f()
は常にAとして入力されたものを 受け取ります(実際にはBまたはCであり、適切にダウンキャストできます)。
追加のf()を定義できます
f(B b);
および必要に応じて
f(C c);
引数のクラスに応じて、正しいものが呼び出されます。つまり、コンパイラーは、引数のタイプに応じて、どの関数が呼び出されるかを決定します。これは、実行時に発生する動的ディスパッチ(またはポリモーフィズム)とは異なります。
質問のキャストは冗長であることに注意してください。次のように書くことができます:
C c = new C()
B b = c;
f(b);
CはBから拡張されるため、Cは a Bです。
他のヒント
コンパイル時タイプとランタイムタイプの違いについて混乱しているようです。
タイプCのオブジェクト(参照cおよびbで示される)を作成していますが、オブジェクトのランタイムタイプを変更することはできず、したがって動作を変更することはできないため、Cをそのまま保持します。キャストすることで、コンパイル時のタイプを変更するだけで済み、コンパイラーによる処理方法に影響します。
解決しようとしている具体的な問題について、さらに情報を提供できますか?ほとんどの場合、設計を変更することで目標を達成する方法があります。
fにbをタイプCとしてではなくタイプBとして受け取らせたい
A C
は B
は A
です。
f
の内部では、 f
はパラメーター a
の部分のみを参照します a
If f
は C
でオーバーライドされるパブリック A
関数を呼び出し、 C
オーバーライドが呼び出されます。
これが仮想関数の仕組みです。つまり、参照されるオブジェクトは実際には C
であるため、 C
の動作を示すはずです。 B
の動作が必要な場合は、 C
インスタンスではなく、 B
インスタンスを渡します。
「C」と「quote」の動作が同じ場合、 C
でその動作を無視しないでください。
なぜこれを行うのですか?
あなたの質問は意味がありません。 「fはbをタイプCとして受け入れます」とはどういう意味ですか?
fは、メソッドシグネチャに「A」と記述されているため、タイプAとしてbを受け入れます。 bでメソッドを呼び出す場合、Cがメソッドをオーバーライドすると、Cでメソッドが呼び出されます。ただし、これはJavaの標準的な動作であり(すべてのメソッドはC ++の仮想メソッドに似ています)、変更する方法はありません。
実際の問題を説明していただければ、お手伝いできる場合があります。
Aのサブクラスをf(A a)のパラメーターとして渡すことができるという事実は、Javaのオブジェクト指向に固有のものであり、これを回避する方法はありません。 CがAを拡張する場合、Aが期待される場所で常に使用することができます。
リフレクションを使用して、パラメーターがクラスAであるかどうかを確認できます:
public void f(A a) {
if (a.getClass() == A.class) {
// ok, go on
}
else {
System.err.println("The parameter is not of class A!");
}
}
それがあなたの望むものかどうかわからないが、役に立つかもしれない。
REFERENCEタイプとINSTANCEタイプの違いを理解することで問題を解決できます。 CオブジェクトをBとしてキャストするとき、参照タイプを変更するだけです-オブジェクトの実際のインスタンスはまだCオブジェクトです-デバッグモードでオブジェクトを見ると、これは明らかです。参照タイプの変更は、コンパイラがコードを処理/認識する方法にのみ影響します。実行時の動作は影響を受けません。 Cオブジェクトのメソッド呼び出しは、常にCのメソッドを呼び出します(オブジェクトが他のオブジェクトにキャストされているかどうかに関係なく)。 Bからメソッドを上書きし、Bのバージョンのメソッドを呼び出す場合は、Bインスタンスを作成する必要があります。
コードがAへの参照を持っているという事実は、ポイントされているオブジェクトもAであることを意味しません。Cである場合、Cのままです。キャストが必要なのは、異なる型のメソッドが必要な場合があり、型をキャストするためにキャストのメソッドを使用できるようにコンパイラをだます必要があるためです。当然、試行が無効な場合、実行時にキャストが失敗する可能性があります。
In upcasting and downcasting the object first upcast then downcastenter
class A
{
}
class B extends A
{
}
Class M
{
psvm(String ar[])
{
A a1= new B();
B b2=(B)a1;
}