我々はインナークラスのオブジェクトを作成するときに、なぜはgetClass()が呼ばれているのですか?

0ne0rZer0:

私は内部クラスの仕組みを勉強していますし、そのバイトコードの内部で、私は、スタックをトレースたとはgetClass()が呼び出された理由を理解できませんでしたか?
私が見つかりました。ラムダ関数の同様の質問を、それを理解することができませんでした。

私はそれがJDK 8の後にそれがrequiredNoNullという静的関数によって置き換えられています、ノーヌルチェックのために必要であることを理解しようとしました。

コード:

class Outer{
      class Inner{
      }
      public static void main(String args[]){
            Outer.Inner obj = new Outer().new Inner();
      } 
}

バイトコード:

 public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class Outer$Inner
       3: dup
       4: new           #3                  // class Outer
       7: dup
       8: invokespecial #4                  // Method "<init>":()V
      11: dup
      12: invokevirtual #5                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
      15: pop
      16: invokespecial #6                  // Method Outer$Inner."<init>":(LOuter;)V
      19: astore_1
デフォルトロケール:

私の知る限り理解し、ユージンの答え@絶対に正しいです。私は簡単な言葉で説明を追加することにしました。うまくいけば、それが誰かを助けます。

回答:への呼び出しObject.getClass、必要に応じてNullPointerExceptionsがを生成するJDK8にコンパイラによって使用されたが。あなたの例では、このチェックは、不要であるnew Outer()nullにすることはできませんが、コンパイラはそれを決定するために、スマート十分ではありませんでした。

JDKのそれ以降のバージョンでは、ヌルのチェックはして使用するように変更され、より読みやすいしObjects.requireNotNullコンパイラはまた、離れた冗長ヌルチェックを最適化するために、改善されました。

説明:

このようなコードを考えてみましょう:

class Outer{
      class Inner{
      }
      public static void main(String args[]){
            Outer.Inner obj = ((Outer) null).new Inner();
      } 
} 

それが必要として、このコードは、NullPointerExceptionがスローされます。

問題は、NPEは、ビューのJavaの点からだけ論理的である、です。コンストラクタは、バイトコードレベルで存在していません。コンパイラは、多かれ少なかれ同等以下の疑似コードにバイトコードを生成します。

class Outer {
    public static void main(String[] args) {
         Outer tmp = (Outer) null;
         Outer.Inner obj = new; //object created
         tmp."<init>"(tmp);
    }
}
class Outer$Inner {
    //generated field
    private final Outer outer;
    //generated initializer
    void "<init>"(Outer outer) {
         this.outer = outer;
    }    
}

あなたが見ることができるように、コンストラクタはメソッドに置き換えられました。そしてこの方法は、それ自体で、例外がスローされません、したがって、ヌルのためにそれの引数をチェックしません。

そのため、コンパイラは生成するために、追加のnullチェックを追加する必要がありますNullPointerExceptionJavaの8の前に、これを達成するために迅速かつ汚い方法は、呼び出しを発するようにしましたgetClass

Outer tmp = (Outer) null;
tmp.getClass(); //generates an NPE

どのように、これは、確かに、その理由であることを確認することができます。

  1. コンパイルOuterJDK 8を使用して、上記クラスを。
  2. それを実行し、それがNPEをスローする必要があります。
  3. 呼び出しを削除するObject.getClassからOuter.class(例えば任意のバイトコード・エディタを使用してJBE)。
  4. もう一度プログラムを実行し、それが正常に完了します。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=226128&siteId=1