英文:
Why java bytecode from a class have come code for new staic inner class appear jvm instruction ACONST_NULL
问题
我尝试创建一个内部静态类,但我发现在字节码中,在<code>NEW</code>、<code>DUP</code>和<code>INVOKE_SPECIAL</code>之间出现了JVM指令<code>ACONST_NULL</code>,但我知道一个类的新建过程应该是:
- NEW
- DUP
- INVOKE_SPECIAL
为什么会出现下面这段代码:
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
<code>ACONST_NULL</code>是什么意思?
英文:
I try to new a inner staic class, But I find that bytecode appear the jvm instruction <code>ACONST_NULL</code> bwteen <code>NEW</code>,<code>DUP</code> and <code>INVOKE_SPECIAL</code>,
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 <code>ACONST_NULL</code>?
答案1
得分: 5
这是 javac
在 JDK 11 之前解决私有成员访问问题的方式。
InnerMain
被声明为私有,并且它有一个私有的默认构造函数:
private InnerMain() {
}
根据 JVM 规范,任何类都不能访问其他类的私有成员,但根据 Java 语言规则,Main
应该能够访问 InnerMain
的私有成员。为了解决这个问题,javac
生成了一个合成的包私有桥接构造函数。为了确保这个构造函数不能直接从用户代码中调用,编译器在签名中添加了一个虚拟类 Main$1
:
// 真正的构造函数
private InnerMain() {
}
// 合成的桥接构造函数(包私有,所以 Main 可以调用它)
InnerMain(Main$1 dummy) {
this();
}
当你写 new InnerMain()
时,编译器实际上调用了这个桥接构造函数。虚拟参数的实际值并不重要,因此它被设置为 null
,因此会有 ACONST_NULL
指令:
public static void main(String[] args) {
InnerMain innerMain = new InnerMain(null);
}
请注意,当内部类是公共的或包私有的时候,不需要桥接方法。
自 JDK 11 开始,引入了一种全新的机制,详见 JEP 181: 基于嵌套的访问控制。现在,如果你使用 JDK 11 或更新版本编译你的 Main
类,Main
和 InnerMain
将成为嵌套关系,将能够在没有桥接方法和合成类的情况下访问彼此的私有成员。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论