Java 类加载过程之初始化

类初始化

字节码角度分析类初始化过程

init 方法

看看空的类的

package com.chi.jvm.clazz;
public class InitTest1 {
}

0 aload_0
1 invokespecial #1 <java/lang/Object.<init> : ()V>
4 return

编译器会自动为类加上一个无参构造器,并调用Object父类的无参构造方法

package com.chi.jvm.clazz;

public class InitTest1 {
    private  int a = 1;
}

// 调用父类构造器
0 aload_0
1 invokespecial #1 <java/lang/Object.<init> : ()V>
// 初始化实例成员属性
4 aload_0
5 iconst_1
6 putfield #2 <com/chi/jvm/clazz/InitTest1.a : I>
9 return

成员变量在默认的构造器方法中初始化,但可以注意到调用父类方法的指令始终放在前面

package com.chi.jvm.clazz;

public class InitTest1 {
    private  int a;
    public InitTest1(){
        a = 2;
    }
}


// 调用父构造
 0 aload_0
 1 invokespecial #1 <java/lang/Object.<init> : ()V>
 
 // 初始化为 1
 4 aload_0
 5 iconst_1
 6 putfield #2 <com/chi/jvm/clazz/InitTest1.a : I>

 // 赋值为 2
 9 aload_0
10 iconst_2
11 putfield #2 <com/chi/jvm/clazz/InitTest1.a : I>
14 return
package com.chi.jvm.clazz;
public class InitTest1 {
    private  int a;
    public InitTest1(){
        System.out.println(a);	// 输出 0
        a = 2;
    }
}

 0 aload_0
 1 invokespecial #1 <java/lang/Object.<init> : ()V>
 4 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
 7 aload_0
 8 getfield #3 <com/chi/jvm/clazz/InitTest1.a : I>
11 invokevirtual #4 <java/io/PrintStream.println : (I)V>
14 aload_0
15 iconst_2
16 putfield #3 <com/chi/jvm/clazz/InitTest1.a : I>
19 return

如果实例属性字段声明阶段没有初始化,在字节码层面上不会添加默认的初始值,但是通过sout能够正常打印,说明默认值是硬编码到字节码文件中的。

clinit 方法

package com.chi.jvm.clazz;
public class ClinitTest1 {
    private static int a;
}

// 无clint方法

静态字段

package com.chi.jvm.clazz;
public class ClinitTest1 {
    private static int a = 1;
}

// clint
0 iconst_1
1 putstatic #2 <com/chi/jvm/clazz/ClinitTest1.a : I>
4 return

静态代码块

package com.chi.jvm.clazz;

public class ClinitTest1 {
    private static int a = 1;
    static {
        a = 2;
    }
    static {
        a = 3;
    }
}

// clinit 方法
 0 iconst_1
 1 putstatic #2 <com/chi/jvm/clazz/ClinitTest1.a : I>
 4 iconst_2
 5 putstatic #2 <com/chi/jvm/clazz/ClinitTest1.a : I>
 8 iconst_3
 9 putstatic #2 <com/chi/jvm/clazz/ClinitTest1.a : I>
12 return
package com.chi.jvm.clazz;

public class ClinitTest2 {

    static {
        System.out.println("1");
    }

    static {
        System.out.println("2");
    }

    public ClinitTest2(){
        System.out.println(3);
    }

    public static void main(String[] args) {
        new ClinitTest2();
        new ClinitTest2();
    }
}

/*
1
2
3
3
*/

静态属性和静态代码块只会初始化一次

final 关键字修饰的字段

  • 修饰实例属性:必须在声明时初始化,或在构造方法中初始化
  • 修饰静态属性:必须在声明时初始化,或在static静态代码块中初始化

在构造方法中调用其他构造方法

  • 调用自己:this()
  • 调用父类:super()
    无论调用哪个构造器,必须放在所有语句之前

总结

  • 编译器会提供默认的构造方法,用于调用父类构造方法和初始化实例属性
  • 编译器会提供clinit方法初始化静态属性、按顺序执行静态代码块
  • 在构造器中调用其他构造器方法必须放在第一句
  • final修饰的属性必须进行初始化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值