[讨论] java编译生成字节码产生 <init>()与<clinit>()的方法疑问
zhdkn
2012-12-11
java在生成字节码时会将实例构造器 <init>() 方法和类构造器<clinit>()方法添加到语法树中,用javap -c 来查看一个有静态变量和实例变量的class文件只发现了<init>()方法,而没有<clinit>()方法,疑问是既然有静态变量,为什么找不到 <clinit>()方法 呢?
多谢大神能抽空给解惑。 |
|
qianhd
2012-12-11
有个static {}; 在构造函数前面
要不就是你的静态变量是final的吧? |
|
zhdkn
2012-12-12
qianhd 写道 有个static {}; 在构造函数前面
要不就是你的静态变量是final的吧? 是有static{},对于是否有<clinit>() 方法生成再找找资料瞅瞅 |
|
RednaxelaFX
2012-12-13
javap输出的结果里的static {}就是<clinit>()V。只是把名字“美化”了一下而已。
做这个处理的代码在: package sun.tools.java; public interface Constants extends RuntimeConstants { // ... Identifier idClassInit = Identifier.lookup("<clinit>"); // ... } package sun.tools.java; // ... public class MemberDefinition implements Constants { // ... public final boolean isInitializer() { return getName().equals(idClassInit); } public String toString() { if (isInitializer()) { return isStatic() ? "static {}" : "instance {}"; } else // ... } } ============================================== javap在显示成员时,遇到<init>会将其显示为对应的类名,同样也是“美化”显示结果而已,处理跟<clinit>的美化同在上面那个toString()里。 ============================================== javap在显示字节码细节的时候,确实会在对构造器调用的地方显示invokespecial然后是<init>这样的名字,类似: 12: invokespecial #12 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V 但是为啥在这里看不到对<clinit>()V的调用呢?因为这个特殊初始化方法是不能被Java代码调用的,没有任何一条invoke-*字节码可以调用它。它只能作为类加载过程的一部分由JVM直接调用。 |
|
zhdkn
2012-12-13
RednaxelaFX 写道 javap输出的结果里的static {}就是<clinit>()V。只是把名字“美化”了一下而已。
做这个处理的代码在: package sun.tools.java; public interface Constants extends RuntimeConstants { // ... Identifier idClassInit = Identifier.lookup("<clinit>"); // ... } package sun.tools.java; // ... public class MemberDefinition implements Constants { // ... public final boolean isInitializer() { return getName().equals(idClassInit); } public String toString() { if (isInitializer()) { return isStatic() ? "static {}" : "instance {}"; } else // ... } } ============================================== javap在显示成员时,遇到<init>会将其显示为对应的类名,同样也是“美化”显示结果而已,处理跟<clinit>的美化同在上面那个toString()里。 ============================================== javap在显示字节码细节的时候,确实会在对构造器调用的地方显示invokespecial然后是<init>这样的名字,类似: 12: invokespecial #12 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V 但是为啥在这里看不到对<clinit>()V的调用呢?因为这个特殊初始化方法是不能被Java代码调用的,没有任何一条invoke-*字节码可以调用它。它只能作为类加载过程的一部分由JVM直接调用。 谢谢 RednaxelaFX的回复,对于我们这些只看资料,没看源码的程序员确实很难自己理解,虽然回复不能完全明白,但终究是个靠谱的解释。 |
|
RednaxelaFX
2012-12-13
zhdkn 写道 谢谢 RednaxelaFX的回复,对于我们这些只看资料,没看源码的程序员确实很难自己理解,虽然回复不能完全明白,但终究是个靠谱的解释。
我也不是因为读过javap的源码才知道的,是知道它做了“美化”为了回复准确顺便去查了下源码而已。 具体有什么地方不明白的欢迎继续讨论 ![]() |
|
qianhd
2012-12-13
大胆推测 小心求证
|
|
zhdkn
2012-12-14
RednaxelaFX 写道 我也不是因为读过javap的源码才知道的,是知道它做了“美化”为了回复准确顺便去查了下源码而已。 具体有什么地方不明白的欢迎继续讨论 ![]() 对于这个解释已经很明白了,讲的很清晰了,源码都贴出来了,我同时也看看了那2个源码文件。不明白的地方可能扯的有点远,比如怎么知道javap对应的源码的。 |
|
zhdkn
2012-12-14
qianhd 写道 大胆推测 小心求证
![]() |
相关讨论
相关资源推荐
- Java中<init>方法与<clinit>方法
- java类初始化顺序及<init>()与<clinit>()的区别猜想
- 《JVM系列》深入浅出类加载机制中<init>和<Clinit>的区别【一篇即可搞懂初始化机制】
- 深入理解class字节码中的<init>,<clinit>
- <init>与<clinit> 与 类的初始化顺序
- <clinit>和<init>
- 构造器、构造函数、<init>和<clinit>解惑
- 【java】深入理解Java JVM虚拟机中init和clinit的区别
- Java的<init>,<cinit>与类的初始化顺序
- 从类文件分析Java类装载过程<clinit>方法的调用和<init>的调用