両方a1
とa2
タイプA
のオブジェクトを参照すると宣言。変数の「宣言された型」と、それが参照するオブジェクトの実際の型(変数がnullでない場合)を区別することが重要です。
あなたは
I1 a1 = <anything>;
か、単に
I1 a1;
を宣言すると、コンパイラはおよそa1
を知っている唯一のものは、それがI1
を実装し、いくつかのオブジェクトを参照しなければならないということです。したがって、I1
インターフェイス(またはスーパーインターフェイス、またはObject
)に対してメソッドが宣言されている場合にのみ、メソッドa1.method(...)
を呼び出すことができます。また、a1
はI1
(またはスーパーインタフェース、またはObject
)として宣言別の変数に割り当てることができ、そしてあなたは、パラメータ
x.someOtherMethod(a1);
としてそれを使用する場合には、パラメータの型I1
である場合にのみ法的ですスーパーインタフェース、またはObject
です。
new A()
に初期化しても差はありません。 「コンパイラが変数について知ることができるもの」の目的のために、最初の式は考慮されていません。 (異なるタイプのオブジェクトにa1
を割り当てるコードがあるかもしれませんが、変数がfinal
であっても同じルールが適用されます)。
ただし、キャストによって別のタイプとして扱うコンパイラを得ることができます。インターフェイス変数を他のインターフェイスにキャストすることは常に正当です。なぜなら、あるクラスが両方のインターフェイスを実装できる可能性が常にあるからです。したがって、これは合法である:
I2 x = (I2)a1;
実行時に、コンパイラはa1
もI1
に加えてI2
を実装するオブジェクトを参照するかどうかをチェックします。そうであれば、キャストは成功する。そうでない場合、例外がスローされます。例外がないと仮定すると、(I2)a1
は他のどのような方法でも使用できます。I2
したがって、I2
は方法methodOfI2
を定義している場合、あなたは
((I2)a1).methodOfI2(...parameters...)
出典
2017-08-06 03:46:05
ajb
a1とa1の間に違いはありません。 a1とa2の間には、どのメソッドを呼び出すことができるかという違いがあります。 – MaxZoom
常にキャストすることは、ビューをオブジェクトに縮小する**ことに注意してください。実際に**オブジェクトのタイプを変更する**ではありません。たとえば、 'System.out.println(a1.getClass())'のようなことをした場合、 'I1'にキャストしたとしても' class A'のようなものが読み込まれます。しかし、 'I1'だけを必要とすれば、将来的に' I1'の別の実装といつも簡単にオブジェクトを交換することができるので、ビューを減らすことはモジュール性には良いことです。またコンパイラは 'I1'にキャストした後に' I2'のメソッドを呼び出すのを防ぎます。コンパイル時に 'I1'も' I2'です。 – Zabuza
コンパクトでは: 'a1'と' a2'は、キャスティングの後でさえ、 'A'、' I1'、 'I2'のままです。しかし、キャスト後*の実数型*は隠され、コンパイラーはキャストバックせずに安全でない*メソッド呼び出しを行うのを防ぎます。 – Zabuza