专栏首页时光笔记Java 对象的初始化过程_上

Java 对象的初始化过程_上

前言

本文主要以白话的形式 ‘简单’ 的描述在 java 中 new 对象的过程,之所以说是 ‘简单’ 的描述是因为,在本文中不会讲述底层的加载过程。

示例

首先认识几个知识点:

  • 静态代码块 它会在类初始化的时候执行一次,仅能初始化类变量, 即被static修饰的成员变量,如果有多个静态代码块时,会按照静态代码块的编写顺序执行。实际上编译后多个静态代码块中的代码,会按编写时的顺序整合到一个静态代码块。
  • 构造代码块 实际上源代码在被编译后,构造代码块中的代码就会被复制移动到构造方法代码的前面,也就会随着构造方法的运行而运行。如果存有多个构造方法时,将会在每个构造方法的代码之前都放置一遍 构造代码块中的代码 。所以也可以认为,构造代码块将在构造方法执行之前执行,如果存在有多个构造代码块时,那么就会按照构造代码块的编写顺序执行。由于构造代码块的代码是放到构造方法中执行的,所以作用也是初始化类实例变量。适用场景:
    • 一个类,它不管创建多少个实例对象,都需要执行相同的初始化代码。
    • 你的类有n个构造方法,而每个构造方法都需要执行相同的初始化代码。
  • 构造方法 构造方法将会在类实例化时执行,也就是在被 new 时执行,需要注意的是,构造方法可以存在多个,如果你没有显示声明,一个没写的话,那编译器就会帮你加一个默认的构造方法。构造方法可以初始化类成员变量。

知道以上三个知识点后,那么就先创建一个Person类,观察一下

Person.java

package cn.ttext.test.init;

public class Person {

    private String name;
    private int age;
    private String sex;


    static {
        System.out.println("静态代码块1");
    }

    {
        System.out.println("构造代码块1");
    }

    static {
        System.out.println("静态代码块2");
    }

    {
        System.out.println("构造代码块2");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

对其编译,使用IDEA的反编译功能查看class文件内容

Person.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package cn.ttext.test.init;

public class Person {
    private String name;
    private int age;
    private String sex;

    public Person() {
        System.out.println("构造代码块1");
        System.out.println("构造代码块2");
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return this.sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    static {
        System.out.println("静态代码块1");
        System.out.println("静态代码块2");
    }
}

首先观察到,编译后的代码,和咱写的代码有点区别:

  1. 编译器自动帮我曾加了一个默认的,空参数的构造函数。
  2. 编译器删除了构造代码块,并将被删除的构造代码块中的代码,有序的放置到了构造方法中。

下面再在Person类中,显示声明多个构造函数。

Person.java

package cn.ttext.test.init;

public class Person {

    private String name;
    private int age;
    private String sex;


    static {
        System.out.println("静态代码块1");
    }

    {
        System.out.println("构造代码块1");
    }

    public Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    static {
        System.out.println("静态代码块2");
    }

    {
        System.out.println("构造代码块2");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

查看编译后的内容

Person.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package cn.ttext.test.init;

public class Person {
    private String name;
    private int age;
    private String sex;

    public Person(String name) {
        System.out.println("构造代码块1");
        System.out.println("构造代码块2");
        this.name = name;
    }

    public Person(String name, int age) {
        System.out.println("构造代码块1");
        System.out.println("构造代码块2");
        this.name = name;
        this.age = age;
    }

    public Person(String name, int age, String sex) {
        System.out.println("构造代码块1");
        System.out.println("构造代码块2");
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return this.sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    static {
        System.out.println("静态代码块1");
        System.out.println("静态代码块2");
    }
}

看到编译后的结果说明几个问题:

  1. 显示声明构造函数后,编译器将不会帮我们创建默认的构造函数。
  2. 编译器删除了构造代码块,并将被删除的构造代码块中的代码,复制移动到每一个构造函数代码的最前面
  3. 编译器会将多个静态代码块中的代码,整合到一个静态代码块执行。

那现在看一下创建Person对象的控制台输出

Main.java

package cn.ttext.test.init;

public class Main {

    public static void main(String[] args) {
        new Person("张三",18,"女");
        System.out.println();
        new Person("李四",18,"男");
    }

}

因为静态代码块只会随着类的加载而运行,所以第二次创建对象时,静态代码块没有运行。 结合上边的知识点看,是不是更明白了呢。


转发请注明本文链接。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [转发] SpringCloud 应用场景

    原文链接: https://www.jianshu.com/p/5cdc0b0a6c74

    Melody132
  • 搭建Cloudreve云盘

    说到云盘,想来最初用到的其实是网吧的临时存储盘,临时存储盘其实就是网吧搭建的局域网云盘系统,可以通过网管软件进行访问。主要用途就是可以存储一下游戏存档,因为网吧...

    Melody132
  • Java 对象的初始化过程_下

    本文将继上一篇文章《Java 对象的初始化过程_上》进一步讲述Java 对象的初始化过程。

    Melody132
  • Springboot整合Websocket实现一对一消息推送和广播消息推送

    同时因为控制器有注解@SendTo所以会向@SendTo的地址广播消息,客户端订阅了广播地址所有控制台显示接收了消息

    业余草
  • java浅拷贝和深拷贝(基础也是很重要的)

    对于的github基础代码https://github.com/chywx/JavaSE

    陈灬大灬海
  • 照虎画猫写自己的Spring——依赖注入

    前言 上篇《照虎画猫写自己的Spring》从无到有讲述并实现了下面几点 声明配置文件,用于声明需要加载使用的类 加载配置文件,读取配置文件 解析配置文件,需要将...

    JackieZheng
  • Spring-IOC(2)

    scope <!--Spring使用scope标签来制定bean的作用域(默认为Singleton)--> <bean id="singletonBean" c...

    奋斗蒙
  • java基础06

    待你如初见
  • Spring Boot 构造器参数绑定,越来越强大了!

    前几天,Spring Boot 2.2.0 正式发布了:Spring Boot 2.2.0 正式发布,支持 JDK 13!,文中有提到基于构造器的参数绑定,那么...

    Java技术栈
  • [javaSE] IO流(对象序列化)

    获取ObjectOutputStream对象,new出来,构造参数:FileOutputStream对象目标文件

    陶士涵

扫码关注云+社区

领取腾讯云代金券