1. タイプキャスト

参照型(クラス)を格納する変数も別の型に変換できます。ただし、これは単一の型階層内でのみ機能します。簡単な例を見てみましょう。次のクラス階層があり、下のクラスが上のクラスを継承しているとします。

タイプキャスト

参照型およびプリミティブ型の型キャストも、拡張と縮小のいずれかに分類されます。

Cat クラスが Pet クラスを継承し、さらに Pet クラスが Animal クラスを継承していることがわかります。

次のようなコードを書くと:

Animal kitten = new Cat();

これは拡張型変換です。暗黙的キャストとも呼ばれます。catオブジェクトを参照するようにcat参照を拡張しました。このような型変換を行うと、子猫参照を使用して、 Catクラスには存在するがAnimalクラスには存在しないメソッドを呼び出すことができなくなります。

縮小変換 (または明示的なキャスト) は逆方向に発生します。

Cat cat = (Cat) kitten;

kitten変数 (型はAnimal )に格納されている参照をCat型にキャストすることを明示的に示しました。



2. オブジェクトの種類を確認する

しかし、ここでは非常に注意する必要があります。これを行う場合:

Animal beast = new Cat();
Wolf grayWolf = (Wolf) beast;

コンパイラはこのコードを許可しますが、プログラムを実行するとエラーが発生します。JVM は例外をスローします。

Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to a Wolf

Catオブジェクトへの参照は、型が Cat クラスの祖先である Pet、Animal、または Object である変数にのみ保存できます。

何故ですか?

ここで重要なのは、オブジェクト参照がそのオブジェクトのメソッドと変数を参照するために使用されるということです。そして、Animal 変数を使用して Cat オブジェクトへの参照を保存する場合、何の問題もありません。Cat型には常に Animal 型の変数とメソッドがあり、それらは継承されています。

しかし、JVM で Cat オブジェクトへの参照を Wolf 変数に格納できる場合は、 grayWolf変数を使用して、その変数に格納されている Cat オブジェクトに存在しないメソッドを呼び出そうとする状況が発生する可能性があります。。だからこそ、この取り決めは許されません。

instanceofJava には、オブジェクトが特定の型であるかどうか、したがって特定の型の変数に格納できるかどうかを確認できる特別な演算子があります。とてもシンプルに見えます:

variable instanceof Type

例:

Animal beast = new Cat();
if (beast instanceof Wolf)
{
   Wolf grayWolf = (Wolf) beast;
}

このコードは実行時であってもエラーを引き起こしません。

状況を説明する例をさらにいくつか示します。

拡張型変換 説明
Cow cow = new Whale();

これは古典的な拡張変換であり、型変換演算子は必要ありません。これで、クラス内で定義されたメソッドのみがオブジェクトCowに対して呼び出すことができますWhale

cow変数では、コンパイラはその型 (Cowクラス) が持つメソッドのみを呼び出すことができます。

ナローイング型変換
Cow cow = new Whale();
if (cow instanceof Whale)
{
   Whale whale = (Whale) cow;
}
従来の絞り込み変換:型チェックとキャスト演算子を追加する必要があります。
変数にはオブジェクトCow cowへの参照が格納されますWhale
これが当てはまることを確認し、(絞り込み) 型変換を実行します。または、次のようにも呼ばれます。
キャスト

Cow cow = new Cow();
Whale whale = (Whale) cow; // Exception
オブジェクトの型を確認せずに参照型を絞り込むことができます。 変数が ではないオブジェクトを参照している
場合、 が生成されます。 cowWhaleInvalidClassCastException


3. 元のメソッドの呼び出し:superキーワード

親クラスのメソッドをオーバーライドするとき、独自のメソッドに置き換えるのではなく、わずかに補足するだけでよい場合があります。

私たちのメソッド内で親クラスのメソッドを使用して、独自のコードの一部を実行できれば素晴らしいでしょう。あるいは、最初に独自のコードを実行してから、親クラスのメソッドを呼び出すこともできます。

Java ではまさにそれが可能です。親クラスのメソッドを呼び出すには、次のようにします。

super.method(arguments);

例:

class PeaceTime
{
   public double getPi()
   {
      return 3.14;
   }
}

class WarTime extends PeaceTime
{
   public double getPi()
   {
      return super.getPi()*2;  // 3.14*2
   }
}

戦時には、 の値がPi6 より大きくなる可能性があります。もちろん冗談ですが、この例はこれがどのように機能するかを示しています。

もう少しわかりやすくするために、さらにいくつかの例を示します。

コード 説明
class Cow
{
   public void printAll()
   {
      printColor();
      printName();
   }

   public void printColor()
   {
      System.out.println("I'm a white whale");
   }

   public void printName()
   {
      System.out.println("I'm a cow");
   }
}

class Whale extends Cow
{
   public void printName()
   {
      System.out.print("This is incorrect: ");
      super.printName();
      System.out.println("I'm a whale");
   }
}
CowそしてWhaleクラス
public static void main(String[] args)
{
   Whale whale = new Whale();
   whale.printAll();
}
画面出力は次のようになります。
I'm a white whale
This is incorrect: I'm a cow
I'm a whale

これは大変なことです。正直に言うと、これはOOPで最も難しいことの 1 つです。そうは言っても、それを知り、理解する必要があります。