[讨论] 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 写道
大胆推测 小心求证

  是一种很好的学习方法
Global site tag (gtag.js) - Google Analytics