欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

<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;
    }
}

  1. 无论一个java类有无定义构造函数,编译器都会自动生成一个默认的构造函数init()
  2. init()主要完成java类的成员变量的初始化逻辑,同时执行被{}所包裹的快逻辑。如果java类中的成员变量没有被赋初值,则在init方法不会对其进行初始化
  3. 如果为java类显示定义了多个构造函数,无论是否是默认的无参构造函数,java编译器都会将java类成员变量的初始化逻辑嵌入到每一个构造函数中,并且嵌入的位置是在自生逻辑之前。
  4. 当java类显示继承了父类,则Java编译器会让子类的各个构造函数调用父类的默认构造函数init().,从而在子类实例化时完成父类成员变量的初始化逻辑
  5. 当父类中定义了多个构造函数时,子类构造函数会调用父类默认构造函数
  6. 子类构造函数对父默认构造函数的调用顺序,位于子类各个构造函数自生逻辑之前
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每次实例化都会被调用

相关标签: jvm