2017-10-20 10 views
1

コンパイル時に静的バインディングが実行され、実行時に動的バインディングが発生するという原則があります。私はいくつかの関連する質問を読んだ。私はそれらの多くの思考の電車に従うことができるが、私は台無しにし、それは以下のような具体的な質問を私に来るとき、再び私のロジックを失った:Java動的バインディングとメソッドオーバーライドプロセス

class Cake { 
    public void taste (Cake c) { 
     System.out.println("In taste of Cake class"); 
    } 
} 

class ChocolateCake extends Cake { 
    public void taste(Cake c) { 
     System.out.println("In taste (Cake version) of ChocolateCake class"); 
    } 
    public void taste(ChocolateCake cc) { 
     System.out.println("In taste (ChocolateCake version) of ChocolateCake class"); 
    } 
} 

class BirthdayCake extends ChocolateCake { 
    public void taste(Cake c) { 
     System.out.println("In taste (Cake version) of BirthdayCake class"); 
    } 
    public void taste (ChocolateCake cc) { 
     System.out.println("In taste (ChocolateCake version) of BirthdayCake class"); 
    } 
    public void taste(BirthdayCake bc) { 
     System.out.println("In taste (BirthdayCake version) of BirthdayCake class"); 
    } 
} 

次のオブジェクトが作成されています:

Cake c1 = new Cake(); 
ChocolateCake cc = new ChocolateCake(); 
Cake c2 = new ChocolateCake(); 
Cake c3 = new BirthdayCake(); 

出力は以下の通りである:

c1.taste(cc);//Output: In taste of Cake class 
cc.taste(cc);//Output: In taste (ChocolateCake version) of ChocolateCake class 
c2.taste(cc);//Output: In taste (Cake version) of ChocolateCake class 
((BirthdayCake) c3).taste(cc);//Output: In taste (ChocolateCake version) of BirthdayCake class 
((BirthdayCake) c3).taste((BirthdayCake) c3);//Output: In taste (BirthdayCake version) of BirthdayCake class 

基本的に、私の質問は、なぜc2.taste(cc)クラスChocolateCaketaste(Cake c)メソッドを呼び出していますか? c2の静的な型がCakeのメソッドが呼び出されることがつもりであると判断Cakeです:

は、ここに私の考えです。実行時になると、動的タイプのc2、つまりChocolateCakeが、ChocolateCakeでメソッドを決定し、ケーキが呼び出されます。パラメータの型はChocolateCakeと決定され、最終的にはtaste(ChocolateCake cc)と呼ばれます。

明らかに、この考えは間違っています。そして、静的型がc2Cakeであり、クラスCakeのメソッドが1つしかないので、メソッドのシグネチャがコンパイル時に解決されたとします。実行時には、クラスのオーバーライドメソッドを呼び出すことになります。私の混乱は、それが前のやり方ではなくこのように機能する理由です。

ChocolateCake cc = new Cake();

私は理解していないもう一つは、我々はそれがコンパイルエラーになるだろうとして、以下のような声明を書くことができていないということです。

しかし、ChocolateCaketaste(Cake c)メソッドを呼び出す必要があるので、ChocolateCake型参照が最終的にCakeオブジェクトを渡すことが可能なのはなぜですか?

私はまだオブジェクト参照のメソッドを呼び出すプロセス全体を理解していないと思います。コンパイル時に最良のマッチング方法を決定するときと、それ以降に起こることは、実行時としましょう(このプロセスでは他の段階があるかどうかはわかりません)。

誰でもこのプロセスを説明できますか? ありがとう!

+1

パラメータバインディングが動的ではないという問題があります。パラメータはコンパイル時に 'Cake.cake(Cake c)'にバインドされているため、実行時に 'Cake'になりますが、メソッド呼び出し(動的である)は' ChocolateCake.cake(Cake c) 'になります。 。おそらくこの質問には重複していることがあります。見つけられるかどうかを見てみましょう。 – Kayaman

+0

ありがとうございます、あなたの答えは私の質問をほぼ解決しました。しかし、私は最後のいくつかの部分で述べたように、パラメータ渡しのものとまだ混乱しています。つまり、ChocolateCake cc = new Cake();という文は許可されないのに対し、最終的に 'Cake'オブジェクトを渡す' ChocolateCake'型参照はなぜ可能ですか? –

+1

これは単なる基本的な継承です。すべてのケーキは「ケーキ」ですが、「ケーキ」は「チョコレートケーキ」ではありません(それは可能ですが、それは決定的ではありません)。あなたは 'Woman w = new Human();'と書くべきではありません。なぜならそれは必ずしも真実ではないからです。 – Kayaman

答えて

0

例を簡略化し、手順を実行してみましょう。わかりやすくするために@Overrideも追加しました。あなたがcake.taste(param);を呼び出すと

class Cake { 
    public void taste (Cake c) { 
     System.out.println("In taste of Cake class"); 
    } 
} 

class ChocolateCake extends Cake { 
    @Override 
    public void taste(Cake c) { 
     System.out.println("In taste (Cake version) of ChocolateCake class"); 
    } 
    public void taste(ChocolateCake cc) { 
     System.out.println("In taste (ChocolateCake version) of ChocolateCake class"); 
    } 
} 

ChocolateCake param = new ChocolateCake();  
Cake cake = new ChocolateCake(); 
cake.taste(param); 

は、Javaコンパイラではなく、実際のオブジェクト参照がポイントしている入力メソッドは、参照の種類に基づいて、callledされるコンパイル時に選択します。

cakeの参照型はCakeので、コンパイラはtasteと呼ばれ、パラメータとしてCake受け付ける方法の基本クラスCakeに見えます。ChocolateCakeCake(継承を使用)なので、コンパイラは一致するものを見つけます。

本質的に動的ディスパッチの実行起因中、塩基tasteメソッドのオーバーライドを有するので、JVMは、ChocolateTypeあり、既に選択されたメソッドのオーバーライドを呼び出すcake参照の実際の型を解決します。

関連する問題