<init>()方法

<init>()方法,是虚拟机自己调用的,不在我们的程序中显性表示。

      那么<init>()的作用是什么?在什么时候被调用?

实际上,JVM为每一个类的每一个构造方法都创建一个<init>()方法,用于初始化实例变量。

我们用一个例子来进行分析:

public class Test{
	private String name;
	private int age;
	
	public Test(){
	}
	
	public Test(String name){
		this.name=name;
	}	
	
	public Test(int age){
		this.age = age;
	}
	
	public int getAge(){
		return age;
	}
}
对这个类进行编译之后

利用指令:javap -verbose TestClass对其进行分析:

F:\java_cmd>javap -verbose Test
Classfile /F:/java_cmd/Test.class
  Last modified 2016-10-22; size 461 bytes
  MD5 checksum c2357af595833a04fc4d51146c91def8
  Compiled from "Test.java"
public class Test
  SourceFile: "Test.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #5.#20         //  java/lang/Object."<init>":(
   #2 = Fieldref           #4.#21         //  Test.name:Ljava/lang/String
   #3 = Fieldref           #4.#22         //  Test.age:I
   #4 = Class              #23            //  Test
   #5 = Class              #24            //  java/lang/Object
   #6 = Utf8               name
   #7 = Utf8               Ljava/lang/String;
   #8 = Utf8               age
   #9 = Utf8               I
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               (Ljava/lang/String;)V
  #15 = Utf8               (I)V
  #16 = Utf8               getAge
  #17 = Utf8               ()I
  #18 = Utf8               SourceFile
  #19 = Utf8               Test.java
  #20 = NameAndType        #10:#11        //  "<init>":()V
  #21 = NameAndType        #6:#7          //  name:Ljava/lang/String;
  #22 = NameAndType        #8:#9          //  age:I
  #23 = Utf8               Test
  #24 = Utf8               java/lang/Object
{
  public Test();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object.
":()V
         4: return
      LineNumberTable:
        line 5: 0
        line 6: 4

  public Test(java.lang.String);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object.
":()V
         4: aload_0
         5: aload_1
         6: putfield      #2                  // Field name:Ljava/lang/St
         9: return
      LineNumberTable:
        line 8: 0
        line 9: 4
        line 10: 9

  public Test(int);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object.
":()V
         4: aload_0
         5: iload_1
         6: putfield      #3                  // Field age:I
         9: return
      LineNumberTable:
        line 12: 0
        line 13: 4
        line 14: 9

  public int getAge();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #3                  // Field age:I
         4: ireturn
      LineNumberTable:
        line 17: 0
}

我们可以从Class文件中发现,对于Test类中的每一个构造方法,JVM都有一条调用<init>()方法的指令存在
### Java `<init>` 和 `<clinit>` 的区别 #### 定义 `<init>()` 方法是实例初始化方法,在每次创建对象时都会调用此方法来完成实例变量的初始化工作。每个构造函数对应一个 `<init>()` 方法[^1]。 相比之下,`<clinit>()` 是类初始化方法,用于执行静态初始化过程。如果一个类中没有任何静态代码块以及对静态成员的赋值操作,则编译器可以选择不为此类生成 `<clinit>()` 方法[^3]。 #### 使用场景 当程序首次使用某个特定方式访问某类或接口的静态成员(包括静态字段和静态方法),且该类尚未被初始化过,此时会触发 `<clinit>()` 执行。这通常发生在以下几种情况之一: - 创建新实例; - 调用静态方法; - 访问/设置静态字段(除了通过数组下标形式访问枚举类型的常量列表外); - 反射调用; 而对于 `<init>()` 来说,每当有新的对象实例化时就会被执行,负责给定的新对象分配内存空间并对其属性进行必要的初始化处理。 #### 区别说明 以下是两者之间的一些重要差异点: | 特性 | `<init>()` | `<clinit>()` | |-------------|------------------------------------|-----------------------------------| | **作用范围** | 实例级别 | 类级别 | | **触发条件** | 对象实例化 | 第一次主动使用到该类 | | **数量特性** | 每个构造器都有对应的版本 | 整个生命周期内最多只会有一个 | | **执行时机** | 构造过程中 | 加载完成后立即运行 | ```java // 示例代码展示 <init> 和 <clinit> public class Example { // 静态块, 将会被放入 <clinit>() static { System.out.println("Static block executed"); } // 成员变量定义 private final String message; /** * 构造函数, 编译后成为 <init>() */ public Example(String msg){ this.message = msg; System.out.printf("Constructor called with message '%s'%n",msg); } } ``` 上述例子展示了如何区分这两个特殊的方法。当第一次加载 `Example` 类时,将会打印 `"Static block executed"` 字样,表示 `<clinit>()` 正在执行。之后每当我们创建一个新的 `Example` 对象时,相应的消息也会随之显示出来,表明相应构造器所关联的那个具体的 `<init>()` 已经启动了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值