问题
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:
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.
来源:https://stackoverflow.com/questions/64095091/why-java-bytecode-from-a-class-have-come-code-for-new-staic-inner-class-appear-j