2005年5月20日

悩ましきポリモーフィズム。

昨日は学校デー。
英会話に行ってから、その後Java学校へ。
一気に疲れる日ですな。

てな訳で、久々に「堂々として」ビールを飲みつつ
Java学校を振り返ってメモっときます(笑)

さて、メインテーマは、
ポリモーフィズムとカプセル化でした。

今回は説明が長くなっちゃうんで、
ポリモーフィズムだけメモります。

・ポリモーフィズム

呼び出すメソッド名は同じなのに
振る舞いが違う状態のこと。

perlやPHPでは 正直使った事ないんで、
ようわからんのですが(笑)
どっちも実装できるらしいです。
※PHPは ver.5から

- 「メソッド名が同じなのに振る舞いが違う」状態とは?

前回習ったインターフェースや抽象クラスで使った
抽象メソッドを継承したクラスがいくつかある事で
「同じ名前なのに実装内容が違う」メソッドが
クラス毎にある事になる模様。

例)


// インターフェース
public interface TestInterface {
 public void open(); // 抽象メソッド
}

// 継承クラス1
public class TestClass1 implements TestInterface {
 public void open() {
   // TestClass1内でのopenを実装
   System.out.println( "こちらはTestClass1でっせ" );
 }
}

// 継承クラス2
public class TestClass2 implements TestInterface {
 public void open() {
   // TestClass2内でのopenを実装
   System.out.println( "こちらはTestClass2なんどすえ" );
 }
}

// 実行クラス内
public static void main( Strings[] args ) {
 TestClass1 test1 = new TestClass1(); // インスタンス化
 TestClass2 test2 = new TestClass2(); // インスタンス化

 test1.open(); // TestClass1のopenを実行
 test2.open(); // TestClass2のopenを実行
 // ↑2つともメソッド名が同じなのに振る舞いが違う
}

-「メソッド名が同じなのに振る舞いが違う」と何が便利なのか?

同じ抽象メソッドを継承しているクラスなら、
同じメソッド名で、実行が可能。
だから、いちいちそれぞれのクラスにあわせた
メソッド名を覚えなくてもOK!


- 不思議な動きの動的束縛

Javaだけの特性なんだか、
不思議な動きがある事を知りました(^^;

例)


// スーパークラス
public class SuperClassTest {
 int SID;

 public void testMethod() {
   // SuperClassTest内でのtestMethod
   System.out.println( "こちらはSuperClassTestのtestMethodです" );
 }
}

// 継承クラス
public class SubClassTest extends SuperClassTest {
 int age;
 String name;

 public void testMethod() {
   // ↓SuperClassTest.testMethodのオーバーライド
   // SubClassTest内でのtestMethod
   System.out.println( "こちらはSubClassTestのtestMethodです" );
 }
}


こんなクラス達がいたとして
普通、継承クラスTestをインスタンス化するには…

 SubClassTest test = new SubClassTest();

…とするところですが、
自分より上のクラスをデータ型の所に設定する事が出来るそうで、

 SuperClassTest test = new SubClassTest();

…として使う事も出来るそうな。

スーパークラスの型に、継承クラスでオブジェクト化???
・・・・・なんだこりゃ(汗)

雰囲気的に、
スーパークラス内のメンバ変数やメソッドは動きそうだけど、
継承クラス内のメンバ変数やメソッドは
一体どうなっちゃうのさ?

せっかく、スーパークラス内のtestMethodメソッドを
継承クラス内で、オーバーライドもしたってーのにさぁ。

危うし、継承クラス!
どうなる継承クラスーーーっ!

…と思ったら(^^;

継承クラス内のメンバ変数やメソッドは
外部から参照したり呼び出す事ができなくなるんだけど
水面下では、ちゃんと存在しているそうな。

あら、ちゃんといたんだ。継承クラス。

でも、水面下で存在してても、
外部から使えないメンバ変数とメソッドって
何も意味がないんじゃ?

…と思ってたら(^^;;

スーパークラス内のメソッドで
継承クラスでオーバーライドされた物だけは
外部から実行できるんだってさ。
なんてやねん。

そういう訳で(^^;;;;;

上記の例で言うと…

 SuperClassTest test = new SubClassTest();

…で、インスタンス化された、test参照変数を用いて…

  test.testMethod();

…と、testMethodメソッドを呼び出すと
スーパークラス内のtestMethodメソッドじゃなくて、
唐突に継承クラスTest内のtestMethodが実行されるそうです。。。

これをふまえて。

さっきのインターフェースを
ちょいと書き足して持ってきまして…

例)


// インターフェース
public interface TestInterface {
 public void open(); // 抽象メソッド
 public void exec(); // 抽象メソッド
 public void close(); // 抽象メソッド
}

// 継承クラス1
public class TestClass1 implements TestInterface {
 public void open() {
   // TestClass1内でのopenを実装
   System.out.println( "こちらはTestClass1のopenでっせ" );
 }
 public void exec() {
   // TestClass1内でのexecを実装
   System.out.println( "こちらはTestClass1のexecでっせ" );
 }
 public void close() {
   // TestClass1内でのcloseを実装
   System.out.println( "こちらはTestClass1のcloseでっせ" );
 }
}

// 継承クラス2
public class TestClass2 implements TestInterface {
 public void open() {
   // TestClass2内でのopenを実装
   System.out.println( "こちらはTestClass2のopenなんどすえ" );
 }
 public void exec() {
   // TestClass2内でのexecを実装
   System.out.println( "こちらはTestClass2のexecなんどすえ" );
 }
 public void close() {
   // TestClass2内でのcloseを実装
   System.out.println( "こちらはTestClass2のcloseなんどすえ" );
 }
}

…という状態で、
両継承クラスのメソッドを次々に実行したい場合、
それぞれのメソッドを、コツコツ書いていくと面倒なんで
以下のように書けるのだそうな。

// 実行クラス内
public static void method( TestInterface obj ) {
 obj.open();
 obj.exec();
 obj.close();
}

public static void main( Strings[] args ) {
 TestInterface obj = {
new TestClass1(), // インスタンス化
new TestClass2() // インスタンス化
 };

 for ( int num = 0; num < obj.length; num++ ) {
  method( obj[num] );
 }
}

結果)
こちらはTestClass1のopenでっせ
こちらはTestClass1のexecでっせ
こちらはTestClass1のcloseでっせ
こちらはTestClass2のopenなんどすえ
こちらはTestClass2のexecなんどすえ
こちらはTestClass2のcloseなんどすえ

なるほどねぇ…。確かに便利だわ。
今のところ、使うあてが思い浮かばないけど(^^;

Posted by anigon at 12:20 AM

「LidlでDBチケット。」へ戻る | 「ダニエル違い。」へ進む

上へ戻る