Why java bytecode from a class have come code for new staic inner class appear jvm instruction ACONST_NULL

459 views Asked by At

I try to new a inner staic class, But I find that bytecode appear the jvm instruction ACONST_NULL bwteen NEW,DUP and INVOKE_SPECIAL, But I know about a class new is

  • NEW
  • DUP
  • INVOKE_SPECIAL
package com.hoho.api;

/**
 * @author linuxea
 */
public class Main {

    private static class InnerMain {
        // no field
    }

    public static void main(String[] args) {
        InnerMain innerMain = new InnerMain();
    }

}

// class version 52.0 (52)
// access flags 0x21
public class com/hoho/api/Main {

  // compiled from: Main.java
  // access flags 0xA
  private static INNERCLASS com/hoho/api/Main$InnerMain com/hoho/api/Main InnerMain
  // access flags 0x1008
  static synthetic INNERCLASS com/hoho/api/Main$1 null null

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 6 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/hoho/api/Main; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
    // parameter  args
   L0
    LINENUMBER 13 L0
    NEW com/hoho/api/Main$InnerMain
    DUP
    ACONST_NULL
    INVOKESPECIAL com/hoho/api/Main$InnerMain.<init> (Lcom/hoho/api/Main$1;)V
    ASTORE 1
   L1
    LINENUMBER 14 L1
    RETURN
   L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    LOCALVARIABLE innerMain Lcom/hoho/api/Main$InnerMain; L1 L2 1
    MAXSTACK = 3
    MAXLOCALS = 2
}

Why

 L0
    LINENUMBER 13 L0
    NEW com/hoho/api/Main$InnerMain
    DUP
    ACONST_NULL
    INVOKESPECIAL com/hoho/api/Main$InnerMain.<init> (Lcom/hoho/api/Main$1;)V
    ASTORE 1

What is the ACONST_NULL?

1

There are 1 answers

5
apangin On

This is the way how javac solves private member access problem before JDK 11.

InnerMain is declared private, and it has private default constructor:

private InnerMain() {
}

According to the JVM specification, no class may access private members of other classes, but according to Java language rules, Main should be able to access private members of InnerMain. To solve this problem, javac generates a synthetic package private bridge constructor. To ensure this constructor is not called directly from user code, compiler adds a dummy class Main$1 in the signature:

// Real constructor
private InnerMain() {
}


// Synthetic bridge constructor (package private, so Main can call it)
InnerMain(Main$1 dummy) {
    this();
}

When you write new InnerMain(), the compiler actually calls this bridge constructor. The actual value of the dummy argument does not matter, so it's just set to null - hence ACONST_NULL instruction:

public static void main(String[] args) {
    InnerMain innerMain = new InnerMain(null);
}

Note that bridge methods are not needed when the inner class is public or package private.

Since JDK 11, a fundamentally new mechanism was introduced, see JEP 181: Nest-Based Access Control. Now, if you compile your Main class with JDK 11 or newer, Main and InnerMain will become nestmates and will be able to access private members of each other without bridge methods and synthetic classes.