右のクラス図のように、Recoed2クラスを継承したRecord3のクラスがあるとします。  | 
		![]()  | 
	
import rec.Record2;
import rec.Record3;
public class Test{
	public static void main(String[] arg){
		Record2 a, b;
		
		a = new Record2("A01", 10);
		b = new Record3("B02", 20, 200);
		a.display(1);
		b.display(2);
	}
}		 | 
		
D:\java>java Test                
   1番目レコード
        商品コード:A01
        数量:10
   2番目レコード
        商品コード:B02
        数量:20
        単価:200
D:\\java>
		 | 
	
a.display(1);実行は、a の参照しているオブジェクトがRecord2で、
Record2クラスのdisplayメソッドが呼び出されています。 
そして、b.display(2);実行は、b の参照しているオブジェクトがRecord3で、
変数の型がRecord2であっても、
Record3クラスのdisplayメソッドが呼び出されていることに注目ください。 
つまり、参照しているオブジェクトの内容によって、自動的にメソッドが選ばれて実行しています。
このように
参照しているオブジェクトよって、呼び出し操作(メソッド)が定まる特性をポリモーフィズム(Polymorphism 日本訳⇒多態性、多相性、多様性)とよばれます。
そして、
このポリモーフィズムを実現するためには、スーパークラスとサブクラス間において、
同じ名で、同じ種類で同じ数の引数のメソッドが必要です。
サブクラスにおいて、このメソッドはオーバーライド(override)されたメソッドと呼びます。
つまりオーバーライドとは、
スーパークラスで定義されたメソッドをサブクラスで定義し直す(上書きする)ことです。
上記Record3クラスでは、display(int n)がオーバーライドしたメソッドになります。
では、initメソッドはどうでしょうか? Record3で、単価用引数を追加して3つの引数にしたinitメソッドを
オーバーロードしていますが、もともとあった引数2つのinitをオーバーライドしてはいません。
Record2の型の a や b は、Record2にある引数が2つの init を実行できます。
しかしRecord2の型の b は、参照しているのがRecord3のオブジェクトであっても
引数が3つinitメソッドは使えません。(オーバーロードされたメソッドでもありません)
次のようなコンパイルエラーになります。
import rec.Record2;
import rec.Record3;
public class Test{
	public static void main(String[] arg){
		Record2 a, b;
		
		a = new Record2();
		b = new Record3();
		a.init("A01", 10);
		b.init("B02", 20, 200);//コンパイルエラー
		
		a.display(1);
		b.display(1);
	}
}		 | 
		
		
D:\java>javac Test.java                
Test.java:12: シンボルを見つけられません。
シンボル: メソッド init(java.lang.String,int,int)
場所    : rec.Record2 の クラス
                b.init("B02", 20, 200);
                 ^
エラー 1 個
D:\\java>
		 | 
	
b.init("B02", 20, 200)でエラーの指摘があって
こそのコンパイラ言語です。
bは、変数宣言よりRecoed2のクラスであり、引数が3つあるメソッドを持っていないので、
間違った使い方をしています。
この間違いを指摘している訳で、
これが可能になってしまうと、コンパイラ言語としての利便性が失われます。
(型宣言をしない言語で、オーバーロードしなくてもこのようなポリモーフィズムを
可能とする言語もあります。例⇒VbScriptなど)
Java言語は変数を宣言する時に、型を明確にする言語なので、その型に存在しないメソッドを、
直接実行させることがでないというわけです。
ですが、そのメソッドが存在する型の変数に参照(管理)し直せば可能になります。
上記のb.init("B02", 20, 200)を次のように直せば可能になります。
     		Record3 r = (Record3) b;
     		r.init("B02", 20, 200); 
上記では、(Record3)でキャストして、変数rに、代入(参照設定)し、そのrでメソッドを実行しています。
また、少し式が長くなりますが、優先順位を理解できれば、次のような1行で書くこともできます。
     		((Record3) b).init("B02", 20, 200); 
( )のカッコがない
(Record3) b.init("B02", 20, 200); 
では、
b.init("B02", 20, 200); 
の処理が先行して、それに対してキャスト演算する指示表現で、正しいない表現となります。
あるクラスの変数があるとすると、それでそのクラスのサブクラスオブジェクトも管理(参照)できる規則を上記で説明しました。
しかしその逆に、あるスーパークラスのオブジェクトを、
そのサブクラスの変数に管理(参照)させることはできません。以下でそのコンパイルエラーの例を示します。
		Record3 a;
		
		a = new Record2();	 | 
		
: 互換性のない型
   a = new Record2();		
        ^          			 | 
	
上記のa = new Record2();は、無理やりキャストして、
a = (Record3)new Record2();と書くと、
コンパイルエラーを無くすことができます。
しかし、その場合は実行時に次のエラーが発生します。
java.lang.ClassCastException: rec.Record2 cannot be cast to rec.Record3
つまり結局、変数に対して代入できるオブジェクトは、変数と同じクラスか、またはそのサブクラスのオブジェクトしか
代入できないということです。
また、キャスト演算を使っても、この代入可能な型への型変換しかできないということです。
Record2の配列に、Record2とRecord3の要素を混在して管理させている例と、その実行結果を示します。
これを表示するa[i].display(i)の実行は、ポリモーフィズムによって、
対応する表示メソッドが自動的に選択実行されています。
(ポリモーフィズムが使えない言語では、ifで分岐してそれぞれの表示命令を実行させる必要があります)
import rec.Record2;
import rec.Record3;
public class Test{
	public static void main(String[] arg){
		Record2[] a = new Record2[]{ 
			new Record2("A01", 1),
			new Record3("A02", 2, 200),
			new Record2("A03", 3),
			new Record2("A04", 4),
			new Record3("B01", 10,1000),
			new Record3("B02", 20,2000),
			new Record2("B02", 30),
			new Record3("B03", 30,300),
		};
		// 配列全体を表示
		for (int i = 0; i &kt; a.length; i++){
			a[i].display(i);
		}
	}
}
	 | 
		
D:\java>java Test                
   0番目レコード
        商品コード:A01
        数量:1
   1番目レコード
        商品コード:A02
        数量:2
        単価:200
   2番目レコード
        商品コード:A03
        数量:3
   3番目レコード
        商品コード:A04
        数量:4
   4番目レコード
        商品コード:B01
        数量:10
        単価:1000
   5番目レコード
        商品コード:B02
        数量:20
        単価:2000
   6番目レコード
        商品コード:B02
        数量:30
   7番目レコード
        商品コード:B03
        数量:30
        単価:300
D:\\java>
 |