<clinit>与<init>方法
程序员文章站
2022-03-05 15:39:00
...
这两个方法是由java编译器自动生成,当java类中存在用static修饰的静态类型字段,或者存在使用static{}快包裹的逻辑时,编译器会自动生成方法。而当java类定义了构造函数或者其非static类成员变量被赋予初始值时,编译器会自动生成方法
init方法详解
public class ClinitTest extends MyClass{
private Integer a = 3 ;
public ClinitTest() {
short b=8;
}
public ClinitTest(int c) {
c=20;
}
{
int d=33;
}
}
class MyClass{
protected int e=33;
public MyClass(){
int f=44;
}
public MyClass(int e){
e=55;
}
}
- 无论一个java类有无定义构造函数,编译器都会自动生成一个默认的构造函数init()
- init()主要完成java类的成员变量的初始化逻辑,同时执行被{}所包裹的快逻辑。如果java类中的成员变量没有被赋初值,则在init方法不会对其进行初始化
- 如果为java类显示定义了多个构造函数,无论是否是默认的无参构造函数,java编译器都会将java类成员变量的初始化逻辑嵌入到每一个构造函数中,并且嵌入的位置是在自生逻辑之前。
- 当java类显示继承了父类,则Java编译器会让子类的各个构造函数调用父类的默认构造函数init().,从而在子类实例化时完成父类成员变量的初始化逻辑
- 当父类中定义了多个构造函数时,子类构造函数会调用父类默认构造函数
- 子类构造函数对父默认构造函数的调用顺序,位于子类各个构造函数自生逻辑之前
Constant pool:
#1 = Methodref #5.#27 // com/picc/java/MyClass."<init>":()V
#2 = Methodref #28.#29 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#3 = Fieldref #4.#30 // com/picc/java/ClinitTest.a:Ljava/lang/Integer;
#4 = Class #31 // com/picc/java/ClinitTest
#5 = Class #32 // com/picc/java/MyClass
#6 = Utf8 a
#7 = Utf8 Ljava/lang/Integer;
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 LocalVariableTable
#13 = Utf8 d
#14 = Utf8 I
#15 = Utf8 this
#16 = Utf8 Lcom/picc/java/ClinitTest;
#17 = Utf8 b
#18 = Utf8 S
#19 = Utf8 (I)V
#20 = Utf8 c
#21 = Utf8 main
#22 = Utf8 ([Ljava/lang/String;)V
#23 = Utf8 args
#24 = Utf8 [Ljava/lang/String;
#25 = Utf8 SourceFile
#26 = Utf8 ClinitTest.java
#27 = NameAndType #8:#9 // "<init>":()V
#28 = Class #33 // java/lang/Integer
#29 = NameAndType #34:#35 // valueOf:(I)Ljava/lang/Integer;
#30 = NameAndType #6:#7 // a:Ljava/lang/Integer;
#31 = Utf8 com/picc/java/ClinitTest
#32 = Utf8 com/picc/java/MyClass
#33 = Utf8 java/lang/Integer
#34 = Utf8 valueOf
#35 = Utf8 (I)Ljava/lang/Integer;
{
public com.picc.java.ClinitTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=1
0: aload_0
1: invokespecial #1 // Method com/picc/java/MyClass."<init>":()V
4: aload_0
5: iconst_3
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: putfield #3 // Field a:Ljava/lang/Integer;
12: bipush 33
14: istore_1
15: bipush 8
17: istore_1
18: return
LineNumberTable:
line 6: 0
line 5: 4
line 13: 12
line 7: 15
line 8: 18
LocalVariableTable:
Start Length Slot Name Signature
15 0 1 d I
0 19 0 this Lcom/picc/java/ClinitTest;
18 1 1 b S
public com.picc.java.ClinitTest(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: aload_0
1: invokespecial #1 // Method com/picc/java/MyClass."<init>":()V
4: aload_0
5: iconst_3
6: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
9: putfield #3 // Field a:Ljava/lang/Integer;
12: bipush 33
14: istore_2
15: bipush 20
17: istore_1
18: return
LineNumberTable:
line 9: 0
line 5: 4
line 13: 12
line 10: 15
line 11: 18
LocalVariableTable:
Start Length Slot Name Signature
15 0 2 d I
0 19 0 this Lcom/picc/java/ClinitTest;
0 19 1 c I
}
clinit方法详解
public class ClinitTest extends MyClass{
private static int bb = 55;
static {
int uu=23;
}
public static void main(String[] args) {
}
}
class MyClass{
protected static int ee = 26;
static {
int ff=90;
}
}
可以看到static方法只完成了成员变量bb和局部变量uu的初始化,由此可见clinit不具备继承性,因为clinit只在类加载过程中被调用,而父类和子类是分别加载的,当父类加载完成之后,static成员变量初始化和static代码快中的逻辑已经执行完成,没必要在子类在执行一次
Constant pool:
#1 = Methodref #4.#22 // com/picc/java/MyClass."<init>":()V
#2 = Fieldref #3.#23 // com/picc/java/ClinitTest.bb:I
#3 = Class #24 // com/picc/java/ClinitTest
#4 = Class #25 // com/picc/java/MyClass
#5 = Utf8 bb
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/picc/java/ClinitTest;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 args
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 <clinit>
#19 = Utf8 uu
#20 = Utf8 SourceFile
#21 = Utf8 ClinitTest.java
#22 = NameAndType #7:#8 // "<init>":()V
#23 = NameAndType #5:#6 // bb:I
#24 = Utf8 com/picc/java/ClinitTest
#25 = Utf8 com/picc/java/MyClass
{
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: bipush 55
2: putstatic #2 // Field bb:I
5: bipush 23
7: istore_0
8: return
LineNumberTable:
line 5: 0
line 7: 5
line 8: 8
LocalVariableTable:
Start Length Slot Name Signature
8 0 0 uu I
}
clinit和init的执行顺序
clinit是在类第一次被jvm加载时调用,而init是在实例化时调用。类的加载一定是在实例化之前,init每次实例化都会被调用
上一篇: Java语言USB接口程序设计