継承:スーパークラスからのコードは実質的にサブクラスに「コピー」されますか、それともサブクラスによって参照されますか?


10

Class SubはclassのサブクラスですSup。それは実際にはどういう意味ですか?言い換えれば、「継承」の実際的な意味は何ですか?

オプション1: Supのコードが仮想的にSubにコピーされます。( 'copy-paste'と同じですが、コピーされたコードがサブクラスで視覚的に表示されていません)。

例:methodA()はもともとSupにあったメソッドです。SubはSupを拡張するのでmethodA()、(事実上)Subにコピーペーストされます。これで、Subにはという名前のメソッドがありmethodA()ます。コードのすべての行でSupと同じですmethodA()が、完全にSubに属しており、Supに依存していないか、何らかの方法でSupに関連しています。

オプション2: Supからのコードは実際にはSub にコピーされません。それはまだスーパークラスだけにあります。ただし、そのコードはサブクラスを介してアクセスでき、サブクラスで使用できます。

例:methodA()は、Supのメソッドです。SubはSupを拡張するのでmethodA()、Subから次のようにアクセスできますsubInstance.methodA()。しかし、実際methodA()にはスーパークラスで呼び出されます。つまり、methodA()は、サブクラスによって呼び出された場合でも、スーパークラスのコンテキストで動作します。

質問:2つのオプションのどちらが実際に機能するのですか?どれもない場合は、これらが実際にどのように機能するかを説明してください。


これは自分でテストするのが簡単です。コードを記述し、クラスファイルを調べ(チェックサムでも実行できます)、スーパークラスを変更し、再度コンパイルして、クラスファイルをもう一度確認します。また、JVM仕様の第3章「Java仮想マシン用のコンパイル」を読んで理解すると役立ちます(特にセクション3.7)。

@MichaelT「仮想コピー」がキーワードです。また、コードが文字通りコピーされていたとしても、これはクラスのロード後にのみ発生する可能性があります。

@delnan Hotspot(または他のランタイムオプティマイザ)がコードをインライン化する場合は不思議ですが、これはJVMごとに異なる可能性があるため、JVMの実装の詳細になり、正しく応答できません。実行できる最善の方法は、コンパイルされたバイトコード(および実際に何が発生するかを説明するinvokespecialオペコードの使用法)を確認することです

回答:


13

オプション2。

バイトコードは実行時に動的に参照されます。これが、たとえばLinkageErrorsが発生する理由です。

たとえば、2つのクラスをコンパイルするとします。

public class Parent {
  public void doSomething(String x) { ... }
}

public class Child extends Parent {
  @Override
  public void doSomething(String x) {
    super.doSomething(x);
    ...
  }
}

次に、子クラスを変更または再コンパイルせずに、親クラスを変更して再コンパイルします。

public class Parent {
  public void doSomething(Collection<?> x) { ... }
}

最後に、子クラスを使用するプログラムを実行します。NoSuchMethodErrorを受け取ります:

アプリケーションがクラス(静的またはインスタンス)の指定されたメソッドを呼び出そうとし、そのクラスにそのメソッドの定義がなくなった場合にスローされます。

通常、このエラーはコンパイラーによってキャッチされます。このエラーは、クラスの定義が非互換に変更された場合にのみ実行時に発生します。


7

2つの単純なクラスから始めましょう。

package com.michaelt.so.supers;

public class Sup {
    int methodA(int a, int b) {
        return a + b;
    }
}

その後

package com.michaelt.so.supers;

public class Sub extends Sup {
    @Override
    int methodA(int a, int b) {
        return super.methodA(a, b);
    }
}

methodAをコンパイルして、取得するバイトコードを確認します。

  methodA(II)I
   L0
    LINENUMBER 6 L0
    ALOAD 0
    ILOAD 1
    ILOAD 2
    INVOKESPECIAL com/michaelt/so/supers/Sup.methodA (II)I
    IRETURN
   L1
    LOCALVARIABLE this Lcom/michaelt/so/supers/Sub; L0 L1 0
    LOCALVARIABLE a I L0 L1 1
    LOCALVARIABLE b I L0 L1 2
    MAXSTACK = 3
    MAXLOCALS = 3

そして、SupクラスmethodA()に対してルックアップを行うinvokespecialメソッドですぐに確認できます。

invokespecialオペコードは、以下の論理があります。

  • Cに、解決されたメソッドと同じ名前と記述子を持つインスタンスメソッドの宣言が含まれている場合、このメソッドが呼び出されます。検索手順は終了します。
  • それ以外の場合で、Cにスーパークラスがある場合、この同じルックアップ手順は、Cの直接スーパークラスを使用して再帰的に実行されます。呼び出されるメソッドは、このルックアップ手順の再帰的な呼び出しの結果です。
  • それ以外の場合、AbstractMethodErrorが発生します。

この場合、クラスに同じ名前と記述子を持つインスタンスメソッドがないため、最初の弾丸は発火しません。ただし、2番目の弾丸は、スーパークラスがあり、スーパーのmethodAを呼び出します。

コンパイラーはこれをインライン化せず、クラスにSupのソースのコピーはありません。

しかし、物語はまだ終わっていません。これはコンパイルされたコードです。コードがJVMに到達すると、 HotSpotが関与できるようになります。

残念ながら、それについてはあまり知りませんので、この件について当局に訴え、Javaのインライン化にアクセスします。ここでは、HotSpot メソッド(非最終メソッドも)をインライン化できると言われています。

行くドキュメントサブmethodAに)効果的燮methodAからコードを(コピー() -それはその特定のメソッドの呼び出しではなく、それぞれの時間を検索、この情報はインライン化できることをやってのホットスポットとなる場合が注目されます。

これは、アプリケーションがどのように動作しているか、およびパフォーマンスを高速化するために必要な最適化に基づいて、実行時にメモリ内で行われます。

OpenJDKのHotSpot内部で述べられているように、「メソッドはしばしばインライン化されます。静的、プライベート、最終、および/または「特別な」呼び出しは簡単にインライン化できます。」

JVMオプションを掘り下げる-XX:MaxInlineSize=35と、インライン化できる最大バイト数であるオプション(35がデフォルト)が見つかります。Javaが簡単にインライン化できるので、Javaが多くの小さなメソッドを好むのはこのためです。これらの小さなメソッド、インライン化できるため、より多く呼び出されると高速になります。そして、その数を試して大きくすることはできますが、他の最適化の効果が低下する可能性があります。(関連するSOの質問:HotSpotが行っていることのインライン化の内部を覗くための他の多くのオプションを指摘するHotSpot JITインライン化戦略)。

したがって、いいえ-コードはコンパイル時にインライン化されません。そして、はい-パフォーマンスの最適化が必要であれば、コードは実行時にインライン化される可能性が非常に高いです。

そして、私がHotSpotインライン化について書いたものはすべて、Oracleが配布したHotSpot JVMにのみ適用されます。ウィキペディアのJava仮想マシンのリストを見ると、HotSpot以外にも多くのものがあり、これらのJVMがインライン化を処理する方法は、上で説明した方法とはまったく異なる場合があります。Apache Harmony、Dalvik、ART-状況によって動作が異なる場合があります。


0

コードはコピーされず、参照によってアクセスされます。

  • サブクラスはそのメソッドとスーパークラスを参照します
  • スーパークラスはそのメソッドを参照します

コンパイラはこれがメモリ内でどのように表現/実行されるかを最適化しますが、それは基本的には構造です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.