为什么java字节码来自一个类,而新的staic内部类的代码出现在jvm指令ACONST_NULL中

为什么java字节码来自一个类,而新的staic内部类的代码出现在jvm指令ACONST_NULL中,java,jvm,bytecode,jvm-bytecode,Java,Jvm,Bytecode,Jvm Bytecode,我试图新建一个内部staic类,但我发现字节码出现在jvm指令ACONST\u NULLbwteennew,DUP和INVOKE\u SPECIAL, 但我知道有一门课是新的 新的 重复 调用特殊 package com.hoho.api; /** *@作者linuxea */ 公共班机{ 私有静态类InnerMain{ //无场 } 公共静态void main(字符串[]args){ InnerMain=新的InnerMain(); } } //类版本52.0(52) //访问标志0x2

我试图新建一个内部staic类,但我发现字节码出现在jvm指令
ACONST\u NULL
bwteen
new
DUP
INVOKE\u SPECIAL
, 但我知道有一门课是新的

  • 新的
  • 重复
  • 调用特殊
package com.hoho.api;
/**
*@作者linuxea
*/
公共班机{
私有静态类InnerMain{
//无场
}
公共静态void main(字符串[]args){
InnerMain=新的InnerMain();
}
}
//类版本52.0(52)
//访问标志0x21
公共类com/hoho/api/Main{
//编译自:Main.java
//访问标志0xA
私有静态INNERCLASS com/hoho/api/Main$InnerMain com/hoho/api/Main InnerMain
//访问标志0x1008
静态合成内部类com/hoho/api/Main$1 null
//访问标志0x1
公共()V
L0
6号线L0
阿洛德0
调用特定的java/lang/Object。()V
返回
L1
本地变量此Lcom/hoho/api/Main;L0 L1 0
MAXSTACK=1
最大局部数=1
//访问标志0x9
公共静态main([Ljava/lang/String;)V
//参数参数
L0
线路号13 L0
新com/hoho/api/Main$InnerMain
重复
空的
调用特殊com/hoho/api/Main$InnerMain(Lcom/hoho/api/Main$1;)V
阿斯托尔1号
L1
行号14 L1
返回
L2
LOCALVARIABLE args[Ljava/lang/String;L0
本地变量innerMain Lcom/hoho/api/Main$innerMain;L1 L2 1
MAXSTACK=3
最大局部数=2
}
为什么

L0
线路号13 L0
新com/hoho/api/Main$InnerMain
重复
空的
调用特殊com/hoho/api/Main$InnerMain(Lcom/hoho/api/Main$1;)V
阿斯托尔1号

什么是
ACONST\u NULL

这就是
javac
在JDK 11之前解决私有成员访问问题的方法

InnerMain
声明为私有,并且它具有私有默认构造函数:

private InnerMain() {
}
根据JVM规范,任何类都不能访问其他类的私有成员,但是根据Java语言规则,
Main
应该能够访问
InnerMain
的私有成员。为了解决这个问题,
javac
生成一个合成包私有桥构造函数。为了确保这个构造函数不是t直接从用户代码调用,编译器在签名中添加一个伪类
Main$1

// Real constructor
private InnerMain() {
}


// Synthetic bridge constructor (package private, so Main can call it)
InnerMain(Main$1 dummy) {
    this();
}
编写
new InnerMain()
时,编译器实际上会调用此桥构造函数。伪参数的实际值无关紧要,因此它只是设置为
null
-因此
ACONST\u null
指令:

public static void main(String[] args) {
    InnerMain innerMain = new InnerMain(null);
}
注意,当内部类是公共类或包私有类时,不需要桥接方法


自JDK 11以来,引入了一种全新的机制,请参见。现在,如果使用JDK 11或更新版本编译主类,
Main
InnerMain
将成为嵌套对象,并且能够访问彼此的私有成员,而无需桥接方法和合成类。

私有嵌套类放置在不同的中ode>.class文件,但同一顶级上下文中的类必须具有相互交互的方式;这就是合成内部类的原因。编译器创建该类是为了允许访问规则禁止的通信。我怀疑
null
来自嵌套类为s的事实静电(因此没有
外部。此
)。尝试从嵌套类中删除
static
修饰符,看看会得到什么。请注意,您可以找到答案。是的,当我使内部类默认构造函数的可见性高于private时,合成桥构造函数将消失。嗯。我问了另一个问题。'Main应该能够访问InnerMain的私有成员。为了解决这个问题,javac生成了一个合成包私有桥构造器。“为什么桥构造器可以使Main能够访问InnerMain的私有成员?@Linuxea,因为
Main
访问包私有桥构造器而不是私有的原始构造器。桥构造器反过来委托给t同一个类的原始私有构造函数。但是仅仅为了有一个伪参数来区分原始构造函数和合成构造函数而生成整个类是相当繁重的。我认为,即使它从未实例化(因此未初始化),必须加载它才能调用将其作为参数类型的构造函数。Eclipse只是将内部类本身用于伪参数,而不是生成另一个伪参数,而且它也可以工作。但在任何一种情况下,添加伪参数都可能会产生有趣的后果(当参数数量达到最大值时);当我们从嵌套类添加调用方时,以前正确接受的私有构造函数可能会被拒绝,因为现在它有“太多的参数”。然而,删除
private
修饰符会使编译器错误消失。谢天谢地,这已经过去了。
public static void main(String[] args) {
    InnerMain innerMain = new InnerMain(null);
}