『Javaプログラミング思想』ノート8.多態
5903 ワード
ブログにアクセス
オブジェクト向けのプログラム設計言語では,マルチステートはデータ抽象(カプセル化)と継承に続く3番目の基本的特徴である.マルチステートは,何をするか,どのようにするかを分離することによって,インタフェースと実装を別の角度から分離する.多状態の役割はタイプ間の結合関係を除去することである.
8.1再論の向上
オブジェクトは、独自のクラスとしても、ベースクラスとしても使用できます.
8.1.1忘れ物の種類
特別なエクスポートクラスではなく、ベースクラスをパラメータとして受け入れる簡単な方法だけを書きます.
8.2乗り継ぎ
8.2.1メソッド呼び出しバインディングバインド:1つのメソッド呼び出しが同じメソッドボディに関連付けられていることをバインドと呼ぶ. 前期バインド:プログラム実行前にバインドする(コンパイラと接続プログラムによって実現される)ことを前期バインドと呼ぶ. 後期バインド(ダイナミックバインド、ランタイムバインド):実行時にオブジェクトのタイプに応じてバインドされます. Javaでは、 は、
8.2.2正しい行為を生む
コンパイル時に、コンパイラは特別な情報を得る必要がなく、正しい呼び出しを行うことができます.
8.2.3拡張性
良好なOOPプログラムでは、ほとんどの方法またはすべての方法がベースクラスのモデルに従い、ベースクラスインタフェースとのみ通信します.このようなプログラムは、汎用ベースクラスから新しいデータ型を継承できるため、拡張可能である.マルチステートはプログラマーに「変化するものと変わらないものを分離させる」重要な技術である.
8.2.4欠陥:「プライベートメソッドの上書き」親のプライベートメソッドサブクラスは再ロードできません.すなわち、サブクラスのメソッドは新しいメソッド です.非privateメソッドのみが を上書きできる下記のプログラムが呼び出すのは依然として親の対応方法 である.約束:子の中の方法は親の中の
8.2.5欠陥:ドメインと静的方法 通常のメソッドの呼び出しのみがマルチステートの である.サブクラスオブジェクトが親オブジェクトに変換されると、どのドメインアクセス操作もコンパイラによって解析されるため、マルチステートの ではない.ある方法が静的であれば、彼は多態の ではない.
8.3コンストラクタとマルチステート
コンストラクタは、
8.3.1コンストラクタの呼び出し順序ベースクラスのコンストラクタは、常にクラスをエクスポートするコンストラクタ中に呼び出され、継承階層に従ってそのリンクを徐々に考え、各ベースクラスのコンストラクタが呼び出されるようにします. ベースクラスのコンストラクタのみが自分の要素を初期化するために適切な方法と権限を持っているため、すべてのコンストラクタが呼び出されなければ、オブジェクトが正しく構築されません. は、ベースクラスコンストラクタを明確に指定する、すなわちデフォルトコンストラクタ を呼び出す.
オブジェクト呼び出しコンストラクタ順序ベースクラスコンストラクタ(ルートコンストラクタから) を呼び出す.宣言順にメンバーを呼び出す初期化方法 は、導出クラスのコンストラクタ を呼び出す.
8.3.2継承と整理メソッドを組み合わせて新しいクラスを作成する場合、オブジェクトのクリーンアップの問題を心配する必要はありません.サブオブジェクトは通常GCに残して処理されます. 確かにクリーンアップの問題に遭遇した場合、クリーンアップ方法ではサブクラスのクリーンアップロジックを先に書き、親クラスのクリーンアップ方法を呼び出す.すなわち、クリーンアップ順序は初期化順序とは逆であるべきである.
8.3.3コンストラクタ内部のマルチステートメソッドの動作
コンストラクタの内部で構築中のオブジェクトの動的バインドメソッドを呼び出すと、どうなりますか?
初期化の実際の手順:は、他のことが起こる前に、オブジェクトに割り当てられた記憶領域をバイナリのゼロに初期化する. は、8.3.1のようにベースクラスコンストラクタを呼び出す.ベースクラスコンストラクタでは は、宣言された順序でメンバーの初期化方法を呼び出す. は、エクスポートクラスのコンストラクタボディを呼び出す.
コンストラクタガイドラインの作成:は、可能な限り簡単な方法でオブジェクトを正常な状態にし、できれば他の方法の呼び出しを避ける. がコンストラクタで唯一安全に呼び出すことができるのは、これらの方法が上書きされないため、ベースクラスの
8.4コヒーレント戻りタイプ
子クラスが親クラスを上書き(書き換え)する方法では、親クラスが返すタイプの子クラスを返すことができます.これはJSE 5以降に追加された機能で、以下のようになります.
8.5継承による設計
準則:継承表現動作間の差異を用い、フィールドで状態上の変化を表す.
8.5.1純継承と拡張
じゅん継承は、ベースクラスで確立された方法のみが、純粋な
拡張 のような欠点は、拡張部分がベースクラスにアクセスできないことであり、主にアップグレードされたときである.
8.5.2ダウンシフトとランタイムタイプ識別(RTTI)のアップグレードは、ベースクラスがエクスポートクラスよりも大きなインタフェースを持たないため、安全です. ダウンシフト時にランタイムタイプ識別(Run-Time Type Identification)メカニズムがタイプをチェックし、シフトに失敗した場合、ランタイム異常が放出されます( RTTIのコンテンツには、トランスフォーム処理だけでなく、オブジェクトタイプも表示されます.
オブジェクト向けのプログラム設計言語では,マルチステートはデータ抽象(カプセル化)と継承に続く3番目の基本的特徴である.マルチステートは,何をするか,どのようにするかを分離することによって,インタフェースと実装を別の角度から分離する.多状態の役割はタイプ間の結合関係を除去することである.
8.1再論の向上
オブジェクトは、独自のクラスとしても、ベースクラスとしても使用できます.
8.1.1忘れ物の種類
特別なエクスポートクラスではなく、ベースクラスをパラメータとして受け入れる簡単な方法だけを書きます.
public class Test {
public static void main(String[] args) {
func(new Unicycle());
func(new Bicycle());
func(new Tricycle());
}
public static void func(Cycle cycle) {
cycle.ride();
}
}
class Cycle {
void ride() {}
}
class Unicycle extends Cycle {
void ride() {
System.out.println("Unicycle");
}
}
class Bicycle extends Cycle {
void ride() {
System.out.println("Bicycle");
}
}
class Tricycle extends Cycle {
void ride() {
System.out.println("Tricycle");
}
}
8.2乗り継ぎ
func(Cycle cycle)
はCycle
の参照を受け入れます.では、コンパイラはどのようにしてこのCycle
の参照がどの具体的なオブジェクトを指しているかを知ることができますか?実際、コンパイラは知らない.8.2.1メソッド呼び出しバインディング
static
メソッドとfinal
メソッド(private
メソッドはfinal
メソッドに属する)を除いて、他のすべてのメソッドが後期バインドされています.final
キーワードを説明するときに、final
キーワードが動的バインドを閉じることができ、前期バインドが必要であるため、実行効率を向上させることができると述べた.8.2.2正しい行為を生む
コンパイル時に、コンパイラは特別な情報を得る必要がなく、正しい呼び出しを行うことができます.
Cycle cycle = new Tricycle();
cycle.ride();
8.2.3拡張性
良好なOOPプログラムでは、ほとんどの方法またはすべての方法がベースクラスのモデルに従い、ベースクラスインタフェースとのみ通信します.このようなプログラムは、汎用ベースクラスから新しいデータ型を継承できるため、拡張可能である.マルチステートはプログラマーに「変化するものと変わらないものを分離させる」重要な技術である.
8.2.4欠陥:「プライベートメソッドの上書き」
private
の方法と同名ではなく、名前をつけて解決できる問題はそんなに複雑にしないでください.public class Test {
public static void main(String[] args) {
Test test = new TestDemo();
test.func();
// Output: Test
}
private void func() {
System.out.println("Test");
}
}
class TestDemo extends Test {
public void func() {
System.out.println("TestDemo");
}
}
8.2.5欠陥:ドメインと静的方法
8.3コンストラクタとマルチステート
コンストラクタは、
static
と暗黙的に宣言されているため、多態性を有しない.8.3.1コンストラクタの呼び出し順序
オブジェクト呼び出しコンストラクタ順序
8.3.2継承と整理
8.3.3コンストラクタ内部のマルチステートメソッドの動作
コンストラクタの内部で構築中のオブジェクトの動的バインドメソッドを呼び出すと、どうなりますか?
初期化の実際の手順:
func()
が呼び出されるため、実際にはカバーされるfunc()
メソッドである.public class Test {
public static void main(String[] args) {
new Child(100);
}
}
class Child extends Parent {
private int i;
void func() {
System.out.println("Child func, i = " + i);
}
public Child(int i) {
this.i = i;
System.out.println("Before Child constructor, i = " + i);
func();
System.out.println("After Child constructor, i = " + i);
}
}
class Parent {
void func() {
System.out.println("Parent func");
}
public Parent() {
System.out.println("Before Parent constructor");
func();
System.out.println("After Parent constructor");
}
}
Output:
Before Parent constructor
Child func, i = 0
After Parent constructor
Before Child constructor, i = 100
Child func, i = 100
After Child constructor, i = 100
コンストラクタガイドラインの作成:
final
またはprivate
の方法である.上記のコードでParent
のfunc()
をprivate
にすると、異なる結果が得られます.8.4コヒーレント戻りタイプ
子クラスが親クラスを上書き(書き換え)する方法では、親クラスが返すタイプの子クラスを返すことができます.これはJSE 5以降に追加された機能で、以下のようになります.
Child
のfunc()
は、親戻りタイプList
の子ArrayList
を返します.class Child extends Parent {
@Override
ArrayList func() {
return null;
}
}
class Parent {
List func() {
return null;
}
}
8.5継承による設計
準則:継承表現動作間の差異を用い、フィールドで状態上の変化を表す.
8.5.1純継承と拡張
じゅん継承
“is-a”
の関係を導出クラスでカバーすることができる.拡張
extends
キーワードの意味から分かるように,ベースクラスに存在しないメソッドを増やすことをベースクラスに拡張したいようであり,これを“”is-like-a“”
の関係と呼ぶことができる.8.5.2ダウンシフトとランタイムタイプ識別(RTTI)
ClassCastException
).