コンパイル時型対実行時の型


私は2を含む紙のオブジェクトを持っているequals メソッド.
class Paper{
    private int height;
    private int width;

    Paper(int height, int width){
            this.height= height;
            this.width = width;
        }
    @Override
    public boolean equals(Object obj){
        System.out.println("A");
            return this == obj;
    }
      //Overload
    public boolean equals(Paper p){
        System.out.println("B");
        return this == p; 
    }
}
何が次の6のために印刷されますかequals メソッド呼び出し?
//set up
Paper paper = new Paper(297, 140);
Object object = paper;
// 1 to 3
object.equals( object );
object.equals( (Paper) object );
object.equals( paper );
// 4 to 6 
paper.equals( object );
paper.equals( (Paper) object );
paper.equals( paper );

次のように答える.
// 1 to 3
object.equals( object );         // A
object.equals( (Paper) object ); // A
object.equals( paper );          // A
// 4 to 6 
paper.equals( object );           // A
paper.equals( (Paper) object );   // B
paper.equals( paper );            // B
分析しましょう.私が間違っているならば、私を正してください.

基礎知識


コンパイル時間
実行時間
種類
割り当ての左側、宣言時に固定
プログラムの実行によって代入の右側が異なる
結合
静的
ダイナミック
コントロール
コンパイル時の型に基づいて呼び出すことができるメソッドを制限します
実行するメソッドは実行時に決定されます
チェックする
メソッドのオーバーロード
メソッドのオーバーライド
3つの異なる出力があります.
  • None ( JavaオブジェクトのデフォルトEqualsメソッドが呼び出されます)
  • A紙equals オーバーライドメソッドを呼び出します)
  • 紙のequals オーバーロードメソッドを呼び出します)
  • 何が起こっているかの適切な精神モデルを描きましょう.

    セットアップの説明
    //set up
    Paper paper = new Paper(297, 140);
    Object object = paper;
    
  • 変数名paper が作成され、コンパイル時の型Paper . 変数はまた、新しいPaper を使用して作成したオブジェクトPaper クラスコンストラクタ.変数の実行時型もPaper .
  • 変数名object が作成され、コンパイル時の型Object . この変数は、Paper オブジェクト.変数の実行時型object is Paper .
  • 第1から第3のメソッド呼び出しの説明
    // 1 to 3
    object.equals( object );         // A
    object.equals( (Paper) object ); // A
    object.equals( paper );          // A
    
    コンパイル時にコンパイル時の型を見ます.したがって、上記の3つのケースでは、変数名object コンパイル時にObject . この事実は、変数がメソッドが含まれる限り、どんな変数も実行できると私たちに言いますObject クラス.
    同時に、2つ以上のメソッドが同じ名前を持っているが、異なるメソッドシグネチャがあるメソッドオーバーロードがあるかどうかを確認します.メソッドオーバーロードがあれば、そのクラスの中で最も具体的なメソッドを探します.静的結合です.
    ランタイム中に、特定のオブジェクトがコンパイル時に比べて異なる型を持っている可能性があることを知っています.したがって、メソッドがオーバーライドされたかどうかを確認し、コンパイル時に行われた決定を変更し、代わりにオーバーライドメソッドを実行します.これは動的結合としても知られています.
    上の我々の精神モデルから、我々はそれを見ることができますObject クラスは1つだけequals メソッド.それで
  • メソッド呼び出し1は安全です.コンパイル時には、メソッド呼び出し1を(Object) object.equals( (Object) object ) . 私たちにはequals メソッドObject クラス、我々は少なくとも知っている.equals メソッドはObject クラス.実行時に来ると、オブジェクトがランタイム型Paper . これでオーバーライドをチェックします.そして、オーバーライドがあることがわかりますequals 子のメソッドPaper そして、したがって、そのメソッドは起動されて、「A」を印刷しました.
  • メソッドコール2は安全です.私たちは、タイピングによってそれを見ることができますPaper オブジェクトがequals メソッド.我々には特定がありませんequals で取得するオブジェクトクラスのメソッドPaper , パラメータとして扱うことができますObject . これはPaper のサブクラスですObject (デフォルトでは、JavaのすべてのオブジェクトはObject ). したがって、メソッド呼び出し1の同じ論理的推論の後でequals メソッドPaper クラスを起動して"a "を出力します.
  • メソッド呼び出し3は安全です.推論はメソッドCall 2に続く.
  • 追加注意:
  • 親クラスでオーバーライドされたメソッドの代わりにサブクラスでオーバーライドメソッドを呼び出す機能は、多型をサポートします.これは、同じ親のオブジェクトを与えられたことを意味し、特定のメソッドを呼び出し、それぞれの子クラス内でそのメソッドの実装を実装します.
  • 第4から第6のメソッド呼び出しの説明
    // 4 to 6 
    paper.equals( object );           // A
    paper.equals( (Paper) object );   // B
    paper.equals( paper );            // B
    
    最初の3つのメソッド呼び出しからの知識で、それは残りを理解するのが非常に簡単です.
  • メソッドコール4は安全です.私たちはequals 内のメソッドPaper クラスとメソッドシグネチャを見て、我々は我々が具体的に入るものを呼ぶということを知っていますObject , はaを出力する.
  • メソッド呼び出し5は安全です.(Paper)object オブジェクトを使用したい信号Paper このメソッドが実行されるとき.コンパイル時には、パラメータはPaper , そこで、これにマッチする特定のメソッドコールを探します.我々は2番目のequals メソッドPaper これはPaper そして、Bを出力する.
  • メソッドの呼び出しは安全です.推論はメソッドコール5と同様です.
  • 追加注意:
  • オーバーロードされた方法の唯一の時間equals(Paper) 変数のコンパイル時の型がPaper .
  • 結論


    ランタイム間の異なる結果を理解し、遺伝と多形のため、わずかに混乱する可能性があります.しかし、この知識により、後にOPEC指向のデザインをより良く理解できるようになります.つの例は、多形とダイナミックな結合がコードの拡張を容易にするということです.