2017-06-26 12 views
3

Javaの動的変数と動的変数の解決のダイナミック/静的型の混乱が少しあります。Javaのようなstaticlly型言語の動的メソッド解決の背後にある理由

は考えてみましょう:

public class Types { 

    @Override 
    public boolean equals(Object obj){ 
     System.out.println("in class Types equals()"); 
     return false;//Shut-up compiler! 
    } 

    public static void main(String[] args){ 
     Object typ = new Types(); 
     typ.equals("Hi");//can do this as String is a subclass of Object 
    } 
} 

まず:参照変数typが型タイプのものであり、そうではありません!

ので静的な型オブジェクトとダイナミック型オーバーライドのためのタイプを持つ標準の背後にある理由は何ですか?

2番目:コンパイラに正しいequals()を呼び出すのに十分な情報がありませんか?

クラスの型にequals()がオーバーライドされていない場合は、Object.equals()メソッドを呼び出すことができます。

このケースでは、Typesクラスがあり、コンパイラはそれを知っています。

なぜこれはオーバーロードのような早期バインディングではありませんか?なぜそれをJVMに任せますか?

+0

申し訳ありませんが、静的に間違っています。 –

+0

参照変数 'typ'は静的型' Object'と実行時型 'Types'です。コンパイラは 'typ'が' Object'であることしか知りません。 – RealSkeptic

答えて

2

参考変数typは、Objectです。

それが参照するオブジェクトは、タイプがTypesです。

オブジェクトが実際にTypesであり、Type.equals(Object)を使用していることを知るには、コンパイラに十分な情報がありません。

これは混乱する可能性があります。あなたはその後、確かに

Object typ = new Types(); 

を記述する場合、コンパイラは typにそこにあるもの Typesであることを知っています。その情報をコードにコンパイルしただけです!

しかし、何を

Object type = new ObjectFactory().choose(choice).use(decision).build(); 

にその行を変更することにした場合さて、今、あなたは実際にbuildが思い付くだろうかわかりません。これは、ObjectFactoryがchoicedecisionの値で何をすべきかを決定した後、実行時にのみ認識されます。

したがって、この場合、コンパイラは認識しません。利用できる唯一の情報は、変数の静的型です。上記のようなファクトリを使用したときよりもnewを使用したときにコンパイラが異なる動作をすると、非常に悪いことになります。

は今、このシナリオを見て:

public class Types { 
    public boolean equals(Object obj) { 
     // something 
    } 

    public boolean equals(String str) { 
     return false; 
    } 
} 

public class Main { 

    public static void main(String[] args) { 
     Object typ = new Types(); 
     System.out.println(typ.equals("foo")); 
    } 
} 

さて、この場合には、TypesMainは、2つの別々のコンパイル単位(など異なるファイル)があります。コンパイラがtypTypesという事実に従うことに決めたとします。その後、Types.equals(String)を使用します。

ただし、Typesを編集し、equals(String)を削除して、Typesのみを再コンパイルすることができます。プログラムを実行すると、コンパイラはTypesequals(String)メソッドがあると仮定しているため、 "このようなメソッドの例外はありません"というメッセージが表示されます。したがって、が完全に法的であるにもかかわらず、あなたのプログラムは失敗します Javaプログラムで、適切な一致方法がありますが、equals(Object)が新しいTypesにあります。

実際のコンパイラは、静的型を使用して、メソッドが存在し、指定された静的パラメータで合法であるかどうかを判断します。実行時にのみ、JVMは実際の型が何であるかを調べ、その方法の

5

これは、本物のオブジェクト指向プログラミングの基礎です。

多形に沸騰します。詳細は、hereを参照してください。

サブクラスは動作を上書きできます。これにより、クライアントコードを変更しないでください。それでもあなたは新しい/異なる行動を導入することができます。 の別のオブジェクトをそのクライアントコードに渡すだけです。

クライアントコードはどのメソッドを呼び出すかを知っています。 ディスパッチは実行時に発生する必要があります。単に、コンパイラがではなく、が(ほとんどの場合)正確なタイプの着信パラメータを知ることができるからです。

0

コンパイラは、vriableのStatic Typeを知っていて、それを使ってjavaの制約をチェックします。

拳:

参照変数の標準タイプの種類のものであり、そうではありません!私は、コンパイラはObjectとして変数typを考えると思います

は、もちろんtypがあるため、すべてのクラスのObjectのサブタイプであるので、それは変数typに割り当てることができ、Typesオブジェクトへの本当のポイントです。

第二:

は、コンパイラが)(右の等号を呼び出すための十分な情報を持っていませんか?

No.Theコンパイラだけでプログラムが変数typの方法equals()を呼び出す知っているが、それはtypTypesインスタンスまたは実際のメソッドが呼び出されますどのようなinstance.So他のタイプのポイントであるかわからないではなく、コンパイル時に確認してください。次のコード

ルック:

Object typ = new Main(); 
    Object o=new Object(); 
    typ.equals("Hi");//can do this as String is a subclass of Object 
    o.equals("Hi"); 

とJVMの命令セットを参照してください。

16: aload_1 
    17: ldc   #42     // String Hi 
    19: invokevirtual #43     // Method java/lang/Object.equals:(Ljava/lang/Object;)Z 
    22: pop 
    23: aload_2 
    24: ldc   #42     // String Hi 
    26: invokevirtual #43     // Method java/lang/Object.equals:(Ljava/lang/Object;)Z 

お知らせ

19: invokevirtual #43 // Method java/lang/Object.equals (Ljava/lang/Object;)Z

26: invokevirtual #43 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z

typ.equals("Hi")o.equals("Hi")は、同じ命令セットをコンパイルします。しかし、どのメソッドが呼び出されるかは、実際のインスタンスのメソッド参照テーブルによって異なります。

#43 = Methodref   #41.#132  // java/lang/Object.equals:(Ljava/lang/Object;)Z 

#43は、JVM内の実method.Everyインスタンスへのポイントは、クラスOverrideその継承された方法のいくつかの方法table.Ifメソッド参照を有する方法基準である、方法基準はoverrideに変更します方法。

関連する問題