Why is getClass() called when we create an object for Inner class?

0ne0rZer0 :

I am studying the workings of Inner Class and inside its bytecode, I was tracing the stack and couldn't understand why is the getClass() called?
I found a similar question for Lambda function but couldn't understand it.

I did try to understand that is required for no null check, after JDK 8 it's been replaced by a static function called requiredNoNull.

Code :

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

ByteCode:

 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
default locale :

As far as I understand, @Eugene's answer is absolutely correct. I decided to add an explanation in simple words. Hopefully, it will help someone.

Answer: Calls to Object.getClass were used by the compiler in JDK8 to generate NullPointerExceptions where necessary. In your example, this check is unnecessary, as new Outer() can't be null, but the compiler wasn't smart enough to determine it.

In later versions of JDK, null checks were changed to use a more readable Objects.requireNotNull. The compiler was also improved to optimize away redundant null checks.

Explanation:

Consider code like this:

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

This code throws a NullPointerException, as it should.

The problem is, NPE is only logical from the Java point of view. Constructors do not exist on the byte code level. The compiler generates a byte code more or less equivalent to the following pseudocode:

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;
    }    
}

As you can see, the constructor was replaced with a method. And the method, by itself, will not check it's argument for null and, thus, will not throw an Exception.

For that reason, compiler has to add an additional null check to generate a NullPointerException. Before Java 8, the quick and dirty way to achieve this was to emit a call to getClass:

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

How can you check that this is, indeed, the reason:

  1. Compile the Outer class above using JDK 8.
  2. Run it, it should throw an NPE.
  3. Remove the call to Object.getClass from Outer.class using any bytecode editor (e.g. JBE).
  4. Run the program again, it should complete successfully.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=120747&siteId=1