『Javaプログラミング思想』第8章多態

2428 ワード

第8章マルチステート
1、オブジェクト向けのプログラミング言語では、マルチステートはデータ抽象と継承に続く3番目の基本的な特徴である.ダイナミックバインド(後期バインドまたは実行時バインド)により、ベースオブジェクトを使用できますが、関数を呼び出すときに実際のサブオブジェクトの機能を実現できます.
2、多態の使用上の注意事項:多態は普通の方法でしか機能しない
  • privateメソッドまたはfinalメソッドでは、継承は存在しないため、このようなメソッドはコンパイル時に直接バインドされます.サブクラスで同じメソッドを再記述しても、コンパイラはサブクラスの新しいメソッドであり、マルチステートの特徴を実現することはできないと考えています.
  • 静的方法は、特定のオブジェクトではなく対応するクラスに関連付けられているため、マルチステートを示すこともできない.
  • ドメイン:サブクラスにはベースクラスオブジェクトが含まれていると理解できるため、対応するサブクラスとベースクラスのドメインは空間に異なるストレージ空間を割り当て、thisとsuperでそれぞれ参照することができる.同時に、サブクラスをベースクラスに渡し、ベースクラスオブジェクトを使用してドメインにアクセスすると、ベースクラスのドメインも返されます.

  • 3、コンストラクタとマルチステート
    class Glyph{
    	void draw(){System.out.println("Glyph.draw");}
    	Glyph(){
    		System.out.println("Glyph() before draw()");
    		draw();
    		System.out.println("Glyph() after draw()");
    	}
    }
    
    class RoundGlyph extends Glyph{
    	private int radius = 1;
    	RoundGlyph(int r){
    		radius = r;
    		System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
    	}
    	void draw(){
    		System.out.println("RoundGlyph.draw(), radius = " + radius);
    	}
    }
    
    public class PloyConstructors{
    	public static void main(String[] args){
    		new RoundGlyph(5);
    	}
    }/*Output
    Glyph() before draw()
    RoundGlyph.draw(), radius = 0
    Glyph() after draw()
    RoundGlyph.RoundGlyph(), radius = 5
    *///:~

    ベースクラスコンストラクタではマルチステートのためにサブクラスのdraw関数を呼び出す必要があるが、このときサブクラスの通常ドメインは初期化されていないが、「他の何かが発生する前にオブジェクトに割り当てられたストレージスペースをバイナリゼロに初期化する」ため、当時「radius=0」であった.ドメイン内の初期化文はまだ実行されていないが、対応する空間は初期化されていると理解できる.
    コンストラクタを作成する際に有効なガイドラインがあります.「可能な限り簡単な方法でオブジェクトを正常な状態にし、できれば他の方法を呼び出さないでください」.
    4、ダウンシフト:ランタイムタイプ識別(Runtime Type Identification,RTTI)
    場合によっては、実質的にサブクラスオブジェクトであり、サブクラスにないベースクラスの言い訳を呼び出したいベースクラスオブジェクトが1つしかない場合があります.通常、ベースクラスオブジェクトを下に変換する必要があります.ただし、Javaでは実行時にタイプが常にチェックされるため、ベースクラスであるオブジェクトの強制タイプをサブクラスオブジェクトに変換すると、ベースクラスのインタフェースのみにアクセスしても実行時に例外が放出されます.
    class TestMain{
    	void draw(){}
    }
    
    public class Test extends TestMain{
    	void draw(){System.out.println("draw");}
    	void drawTest(){System.out.println("drawTest");}
    	public static void main(String[] args){
    		TestMain t1 = new Test();
    		//t1.drawTest(); // method not found
    		((Test)t1).drawTest();
    		TestMain t2 = new TestMain();
    		((Test)t2).draw();
    	}
    }/*Output
    drawTest
    Exception in thread "main" java.lang.ClassCastException: TestMain cannot be cast to Test
    	at Test.main(Test.java:14)
    *///:~