ポリモーフィズム
| 日本語 | 多態性、多相性 |
| 英語 | polymorphism |
| ふりがな | ぽりもーふぃずむ |
| フリガナ | ポリモーフィズム |
サブクラスの参照をスーパークラスの参照型変数に格納できる機能。
あるクラスのインスタンスを作成した時に返される、そのインスタンスへの参照は、そのクラスのスーパークラスの参照型変数にも格納することができる。
この「サブクラスの参照型からスーパークラスの参照型への変換」は「アップキャスト」と呼ばれ、明示的なキャストを必要としない。
この変換時に、インスタンスそのものには全く変化は起こらない点に注意。つまり「参照の入れ物」が変わっただけで、インスタンスは作った時のクラスそのままである。
格納する参照型をスーパークラスにすることで、プログラムの見た目上は「スーパークラスのメソッド」が呼ばれるように見える。
だが、「オーバーライド」されているメソッドがある場合、メソッドは「インスタンスを作成した時点でのメソッド」が呼ばれるため、実際に呼ばれるのは「スーパークラスのメソッド」ではなく「インスタンスを作成したクラスのメソッド」ということになる。
この機能により、特にメソッドの引数でスーパークラスの参照型変数を持つ場合、その参照型変数に格納されているのが「スーパークラスのインスタンスへの参照」か「サブクラスのインスタンスへの参照」かはプログラム上ではわからない。
スーパークラスの参照型を使用していても、実際には「どのクラスのどのメソッドが呼ばれる」のかはわからない。そのため、同じスーパークラスの参照型を使用しても、実際のインスタンスによって振る舞い・結果が異なるということを意味する。
これは、スーパークラスを扱う側は「インスタンスがどのクラスかを考えるべきではない」ことを意味する。スーパークラスが持つメソッド・ルールを守って使用するだけで、その結果、様々な結果が返されても問題ないようにプログラムを組むべきである。
また逆に、サブクラスを作りオーバーライドする場合には、スーパークラスの「オーバーライドされるメソッド」の結果を大きく逸脱しない結果を返さなければならない。この決まりを守らなければ、スーパークラスを引数に持つメソッドにサブクラスを渡して、そのメソッド内でオーバーライドしたメソッドが呼ばれた場合に、望む結果(=スーパークラスのメソッドが返すのに近い結果)が返らず、うまく動かない場合がある。
「ポリモーフィズム」という言葉は、「ポリ-モーフィズム(poly-morphism)」と分け、「ポリ」は「ポリゴン」の「ポリ」=「多」、「モーフィズム」は「モーフィング」という言葉でおなじみ「姿形を変える」、つまりポリモーフィズムとは「様々な姿を見せる」という意味となる。
スーパークラスが実際には様々なサブクラスとして振る舞う、これこそがポリモーフィズムの意味である。
あるクラスのインスタンスを作成した時に返される、そのインスタンスへの参照は、そのクラスのスーパークラスの参照型変数にも格納することができる。
この「サブクラスの参照型からスーパークラスの参照型への変換」は「アップキャスト」と呼ばれ、明示的なキャストを必要としない。
この変換時に、インスタンスそのものには全く変化は起こらない点に注意。つまり「参照の入れ物」が変わっただけで、インスタンスは作った時のクラスそのままである。
格納する参照型をスーパークラスにすることで、プログラムの見た目上は「スーパークラスのメソッド」が呼ばれるように見える。
だが、「オーバーライド」されているメソッドがある場合、メソッドは「インスタンスを作成した時点でのメソッド」が呼ばれるため、実際に呼ばれるのは「スーパークラスのメソッド」ではなく「インスタンスを作成したクラスのメソッド」ということになる。
この機能により、特にメソッドの引数でスーパークラスの参照型変数を持つ場合、その参照型変数に格納されているのが「スーパークラスのインスタンスへの参照」か「サブクラスのインスタンスへの参照」かはプログラム上ではわからない。
スーパークラスの参照型を使用していても、実際には「どのクラスのどのメソッドが呼ばれる」のかはわからない。そのため、同じスーパークラスの参照型を使用しても、実際のインスタンスによって振る舞い・結果が異なるということを意味する。
これは、スーパークラスを扱う側は「インスタンスがどのクラスかを考えるべきではない」ことを意味する。スーパークラスが持つメソッド・ルールを守って使用するだけで、その結果、様々な結果が返されても問題ないようにプログラムを組むべきである。
また逆に、サブクラスを作りオーバーライドする場合には、スーパークラスの「オーバーライドされるメソッド」の結果を大きく逸脱しない結果を返さなければならない。この決まりを守らなければ、スーパークラスを引数に持つメソッドにサブクラスを渡して、そのメソッド内でオーバーライドしたメソッドが呼ばれた場合に、望む結果(=スーパークラスのメソッドが返すのに近い結果)が返らず、うまく動かない場合がある。
「ポリモーフィズム」という言葉は、「ポリ-モーフィズム(poly-morphism)」と分け、「ポリ」は「ポリゴン」の「ポリ」=「多」、「モーフィズム」は「モーフィング」という言葉でおなじみ「姿形を変える」、つまりポリモーフィズムとは「様々な姿を見せる」という意味となる。
スーパークラスが実際には様々なサブクラスとして振る舞う、これこそがポリモーフィズムの意味である。
参考サイト
// Sample.java
public class Sample
{
public static void main( String[] args )
{
// Stringクラスのインスタンスを作り、
// Objectクラスの参照型変数に格納します。
Object object = new String( "A" );
// ObjectクラスはStringクラスのスーパークラスなので、
// アップキャストに当たるので何もせずに代入できます。
// この際、ただ単に「参照値が代入される」だけで、
// Stringクラスのインスタンスは何も変化しません。
// ただ単に「参照値を入れる器が変わっただけ」です。
System.out.println( object.hashCode() );
// 65
// Object#hashCode()メソッドは「インスタンスの参照の値」を返しますが、
// String#hashCode()メソッドでオーバーライドされているため、
// 「文字列を元にして作られたハッシュコード」が返されます。
// つまり、見た目としてはObjectクラスですが、実際の振る舞いは
// Stringクラスということです。
}
/**
* メソッドの引数でポリモーフィズムを利用する場合。
*/
private void printHashCode( Object object )
{
// 引数にObject型を使用しているため、
// すべてのクラスが引数として渡せます。
System.out.println( object.hashCode() );
// つまり、このhashCode()メソッドが、実際にはどの
// クラスのhashCode()メソッドを呼び出すのか、
// 全くわからないということです。
// そのため、多くのサブクラスを持つクラスを
// 引数に使う場合には「実際のクラスを限定できない」
// ことを踏まえる必要があります。
// また、サブクラスを作りオーバーライドをするということは
// このような理由から「スーパークラスの振る舞いを
// 踏襲した結果」を返すようにしなければならないという
// ことです。
}
}
public class Sample
{
public static void main( String[] args )
{
// Stringクラスのインスタンスを作り、
// Objectクラスの参照型変数に格納します。
Object object = new String( "A" );
// ObjectクラスはStringクラスのスーパークラスなので、
// アップキャストに当たるので何もせずに代入できます。
// この際、ただ単に「参照値が代入される」だけで、
// Stringクラスのインスタンスは何も変化しません。
// ただ単に「参照値を入れる器が変わっただけ」です。
System.out.println( object.hashCode() );
// 65
// Object#hashCode()メソッドは「インスタンスの参照の値」を返しますが、
// String#hashCode()メソッドでオーバーライドされているため、
// 「文字列を元にして作られたハッシュコード」が返されます。
// つまり、見た目としてはObjectクラスですが、実際の振る舞いは
// Stringクラスということです。
}
/**
* メソッドの引数でポリモーフィズムを利用する場合。
*/
private void printHashCode( Object object )
{
// 引数にObject型を使用しているため、
// すべてのクラスが引数として渡せます。
System.out.println( object.hashCode() );
// つまり、このhashCode()メソッドが、実際にはどの
// クラスのhashCode()メソッドを呼び出すのか、
// 全くわからないということです。
// そのため、多くのサブクラスを持つクラスを
// 引数に使う場合には「実際のクラスを限定できない」
// ことを踏まえる必要があります。
// また、サブクラスを作りオーバーライドをするということは
// このような理由から「スーパークラスの振る舞いを
// 踏襲した結果」を返すようにしなければならないという
// ことです。
}
}
// Sample.java
public class Sample
{
public static void main( String[] args )
{
// Stringクラスのインスタンスを作り、
// Objectクラスの参照型変数に格納します。
Object object = new String( "A" );
// ObjectクラスはStringクラスのスーパークラスなので、
// アップキャストに当たるので何もせずに代入できます。
// この際、ただ単に「参照値が代入される」だけで、
// Stringクラスのインスタンスは何も変化しません。
// ただ単に「参照値を入れる器が変わっただけ」です。
System.out.println( object.hashCode() );
// 65
// Object#hashCode()メソッドは「インスタンスの参照の値」を返しますが、
// String#hashCode()メソッドでオーバーライドされているため、
// 「文字列を元にして作られたハッシュコード」が返されます。
// つまり、見た目としてはObjectクラスですが、実際の振る舞いは
// Stringクラスということです。
}
/**
* メソッドの引数でポリモーフィズムを利用する場合。
*/
private void printHashCode( Object object )
{
// 引数にObject型を使用しているため、
// すべてのクラスが引数として渡せます。
System.out.println( object.hashCode() );
// つまり、このhashCode()メソッドが、実際にはどの
// クラスのhashCode()メソッドを呼び出すのか、
// 全くわからないということです。
// そのため、多くのサブクラスを持つクラスを
// 引数に使う場合には「実際のクラスを限定できない」
// ことを踏まえる必要があります。
// また、サブクラスを作りオーバーライドをするということは
// このような理由から「スーパークラスの振る舞いを
// 踏襲した結果」を返すようにしなければならないという
// ことです。
}
}




