【Java18】初始化块

初始化块构造器、成员变量、成员方法一起,是唯四能在类中出现的成员。

  • 初始化块的作用和构造器类似,目的是对对象进行初始化操作;
  • 一个类中可以有多个初始化块;
  • 初始化块只有两种修饰方式:staticdefault。用static修饰的叫类初始化块,没有修饰符的叫实例初始化块
  • 类初始化块先于实例初始化块执行。同样的修饰符,位置在前的初始化块先执行。

虽然但是,同样修饰符的代码块没必要分成一个个小块块。因为代码块就是在创建Java对象的时候隐式执行的,而且总是全部执行。所以分成小块块和合并成一个大块块,没有区别。

实例初始化块
public class Person
{
  // 实例初始化块
  {
    var a = 6;
    if (a > 4)
    {
      System.out.println("Person实例初始化块:局部变量a的值大于4");
    }
    System.out.println("Person的实例初始化块");
  }
  // 第二个实例初始化块
  {
    System.out.println("Person的第二个实例初始化块");
  }
  public Person()
  {
    System.out.println("Person的无参数构造器");
  }
  public static void main(String[] args)
  {
    new Person();
  }
}

初始化块没有名字,所以无法通过显式手段调用它。它就在创建Java对象的时候隐式执行。

  1. 实例初始化块只在创建Java对象的时候隐式执行,且在构造器之前执行;
  2. 类初始化块在类初始化阶段隐式执行。
public class InstanceInitTest
{
    // 实例初始化块
    {
        a = 6;
    }
    int a = 9;
    public static void main(String[] args)
    {
        System.out.println(new InstanceInitTest().a);
    }
}

最终输出结果是9.

Why?

  1. 代码没有报错,第5行中的a的类型由第7行决定,这是编译时确定的,a是InstanceInitTest类的成员变量;
  2. 实力初始化块在其他语句之前执行。因此,a首先赋值为6,然后执行成员变量声明语句,再次被赋值为9。

Java创建对象的过程

  1. 第一次创建某个类的对象时,要先加载类(为类成员变量、类方法,以及类代码块分配内存);
  2. 其余时刻,首先为该对象的所有实例变量分配空间;
  3. 接着,对实例变量进行初始化。
  4. 初始化顺序是:
    1. 实例初始化块或声明实例变量时指定的初始值;
    2. 构造器中指定的初始值。

对上面的代码,如果调换初始化块和成员变量声明语句的顺序,结果会改变:

public class InstanceInitTest
{
    int a = 9;
    // 实例初始化块
    {
        a = 6;
    }
        public static void main(String[] args)
    {
        System.out.println(new InstanceInitTest().a);
    }
}

输出结果会变成6.

初始化块和构造器的异同

  1. 实力初始化块总是在构造器执行之前执行;
  2. 实例初始化块没法接受外部参数,因此它所能执行的初始化处理对于该类的所有对象都只能是相同的。

由此可以倒推出实例初始化块的作用:当有一段实例变量初始化代码完全相同,且不需要外部传参时,可以把这段代码放到实力初始化块中,方便代码阅读;

此外,多个构造器中不需要外部传参的操作,如果有相同的,也可以提取出来放到实例代码块中,以提升代码复用水平。

实例初始化块其实是个假象。使用javac编译Java类后,该类中的实例初始化块会消失:里面的代码会“回归”到每个构造器中,且位于构造器中代码的最前面。

在这里插入图片描述

类初始化块

类初始化块通常用于对类变量执行初始化处理。类初始化块不能对实例变量进行初始化。

类初始化块回向上追溯,先执行父类的类初始化块,依次往下。

class Root
{
    static{
        System.out.println("Root的类初始化块");
    }
    {
        System.out.println("Root的实例初始化块");
    }
}

class Mid extends Root
{
    static {
        System.out.println("Mid的类初始化块");
    }
    {
        System.out.println("Mid的实例初始化块");
    }
    public Mid()
    {
        System.out.println("Mid的无参数构造器");
    }
    public Mid(String msg)
    {
        // 通过this调用无参数构造器
        this();
        System.out.println("Mid的带参数构造器,参数值: " + msg);
    }
}

class Leaf extends Mid
{
    static {
        System.out.println("Leaf的类初始化块");
    }
    {
        System.out.println("Leaf的实例初始化块");
    }
    public Leaf()
    {
        // 通过super调用父类中有一个String参数的构造器
        super("疯狂Java讲义");
        System.out.println("执行Leaf的构造器");
    }
}

public class InstanceInitTest
{
    public static void main(String[] args)
    {
        new Leaf();
        new Leaf();
    }
}
  • 这段代码描述了三个类的继承关系,从父类到子类依次是:Root–>Mid–>Leaf
  • main中,第一次执行new Leaf(),是第一次加载类。此时系统中不存在Leaf类,所以要先加载并初始化Leaf类。这是就会
    • 先执行类初始化块。这部分又会遵循回溯机制,先执行父类的类初始化块,再往下依次执行。因此会出现先执行Root的类初始化块,然后是Mid的类初始化块,最后是Leaf的类初始化块。
    • 接着,执行实例初始化块和构造器。注意,前面说过实例初始化块其实就是构造器的一部分。所以这里会先执行Root的实例初始化块+构造器,然后是Mid的实例初始化块+构造器,最后是Leaf的实例初始化块+构造器。
  • 第二次执行new Leaf()时,就不会再进行类初始化了。

类初始化块和声明类变量(static修饰)的初始化代码和上面说过的实例初始化一样,按顺序执行。

public class StaticInitTest
{
    // 先执行类初始化块,将a赋值为6
    static {
        a = 6;
    }
    // 再将a类变量赋值为9
    static int a = 9;
    public static void main(String[] args)
    {
        // 下面的代码将输出9
        System.out.println(StaticInitTest.a);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/801408.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ACL实验

目录 一、实验拓扑​编辑 二. 实验要求(在图中) 三、实验思路 配IP 全网可达 创建模拟机pc1 创建telent r1 r2 由题目可得 截图 pcr1​编辑 pcr2​编辑 四、实验总结(写实验完成后的总结心得) 一、实验拓扑 二. 实验…

[Unity]碰撞器的接触捕获层详解

目录 前言※关闭效果器(Effector)的遮罩接触捕获层的官方描述官方描述的翻译和注解接触捕获层作用简介接触(Contact)和捕获(Capture)配置接触捕获层的作用※接触捕获层对碰撞响应的影响需要接触捕获的物理查询需要接触捕获的物理回调注意运行时(Runtime)修改接触的相互性总结 相…

再谈有关JVM中的四种引用

1.强引用 强引用就是我们平时使用最多的那种引用,就比如以下的代码 //创建一个对象 Object obj new Object();//强引用 这个例子就是创建了一个对象并建立了强引用,强引用一般就是默认支持的当内存不足的时候,JVM开始垃圾回收&#xff0c…

新手设计必读:学习五种流行弹窗基本样式

本文将给大家分享弹窗设计的 5 个关键方法是布局合理性、可视化元素、考虑目标受众、避免复杂内容、合理定时触发方式;5个弹窗设计基本样式,分别是电商应用弹窗、简约风格弹窗、红包主题弹窗、可视化按钮弹窗、多款通用 APP 弹窗。 即时设计-可实时协作…

EPLAN 去掉PDF中的红色跳转标识

EPLAN PDF图纸导出后体验跳转标识会有红色标识,如何去掉呢?下面介绍一下方法: 此为现象: EPLAN 2.9的帮助文档里提示: 在导出的 PDF 文档中,跳转后的跳转目标现在通过红色的闪烁框进行标识。可能的跳转目…

ROS2-Navigation2初体验:Gazebo“打不开”

输入ros2 launch nav2_bringup tb3_simulation_launch.py headless:False后只能打开RVIZ而无法打开Gazebo的问题,多次尝试解决后发现只是多等待一会儿即可,在此给同样学习Navigation2的朋友们提个醒 。 Getting Started — Nav2 1.0.0 documentation 1…

数据结构(4.4)——求next数组

next数组的作用:当模式串的第j个字符失配时,从模式串的第next[j]的继续往后匹配 求模式串的next数组(手算) next[1] 任何模式串都一样,第一个字符不匹配时,只能匹配下一个子串,因此,往后,next[1]都无脑写…

python的日期和时间

时间与日期 基础知识(python的时间表示方法) 时间戳 时间戳是一个用于表示特定时间点的方式,它表示自1970年1月1日00:00:00 UTC(协调世界时)以来经过的秒数。时间戳通常用于编程中,因为它提供了一种简单的方…

树结构添加分组,向上向下添加同级,添加子级

树结构添加分组&#xff0c;向上向下添加同级&#xff0c;添加子级 效果代码实现页面js 效果 代码实现 页面 <el-tree :data"treeData" :props"defaultProps" :expand-on-click-node"false":filter-node-method"filterNode" :ref&…

实战:功能强大齐全BBS论坛项目Echo简介

项目简介 Echo 是一套前后端不分离的开源社区系统&#xff0c;基于目前主流 Java Web 技术栈&#xff08;SpringBoot MyBatis MySQL Redis Kafka Elasticsearch Spring Security ...&#xff09;&#xff0c;并提供详细的开发文档和配套教程。包含帖子、评论、私信、系…

QT官方modbus_slave例子嵌入到界面

1.打开QT官方modbus_slave的例子 根据提示略微配置一下编译选项&#xff0c;就可以正常运行。 2.新将一个项目包含这个例子 这个例子非常简单&#xff0c;就是在默认的mainwindow上给个按钮&#xff0c;点击按钮调用这个例子的界面。 3.修改*.pro文件 serialport serialbus …

腾讯解禁 QQ 极速版,且看我收集的最全 QQ 各类版本

因为利益关系&#xff0c;腾讯早就限制QQ极速版的登录了&#xff0c;近日居然解除限制了&#xff0c;面对越来越臃肿的QQ&#xff0c;我给大伙准备了几十个版本的QQ&#xff0c;总有一个适合你。 QQ版本合集 给大伙们收集了QQ版本合集&#xff0c;分别有历史版本、精简版本、内…

第59期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

动手学深度学习——3.多层感知机

1.线性模型 线性模型可能出错 例如&#xff0c;线性意味着单调假设&#xff1a; 任何特征的增大都会导致模型输出的增大&#xff08;如果对应的权重为正&#xff09;&#xff0c; 或者导致模型输出的减小&#xff08;如果对应的权重为负&#xff09;。 有时这是有道理的。 例…

【Java--数据结构】队列与栈的相互成就

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 用队列实现栈 用栈实现队列 用队列实现栈 oj链接 一个队列是无法实现栈的 入栈push&#xff1a;把数据放到不为空的队列当中。 注意&#xff1a;第一次入栈时&…

手写new

手写new new是什么执行new会发生什么实现new new是什么 new 操作符是可以创建一个用户定义的对象的实例或具有构造函数的内置对象的实例 function Car (make, model, year) {this.make makethis.model modelthis.year year } Car.prototype.running function () {return …

R语言极值分析:GEV与GPD模型与MCMC的海洋观测数据极值模拟可视化研究

全文链接&#xff1a;https://tecdat.cn/?p37007 原文出处&#xff1a;拓端数据部落公众号 在海洋科学领域&#xff0c;极端天气和海洋事件如极端海浪、风暴潮和海啸等&#xff0c;对沿海社区、基础设施及生态环境构成了重大威胁。准确预测和评估这些极端事件的强度和频率&a…

Golang中读写锁的底层实现

目录 Sync.RWMutex 背景与机制 接口简单介绍 sync.RWMutex 数据结构 读锁流程 RLock RUnlock RWMutex.rUnlockSlow 写锁流程 Lock Unlock Sync.RWMutex 背景与机制 从逻辑上&#xff0c;可以把 RWMutex 理解为一把读锁加一把写锁&#xff1b; 写锁具有严格的排他性&…

Qt程序图标更改以及程序打包

Qt程序图标更改以及程序打包 1 windows1.1 cmake1.1.1 修改.exe程序图标1.1.2 修改显示页面左上角图标 1.2 qmake1.2.1 修改.exe程序图标1.2.2 修改显示页面左上角图标 2 程序打包2.1 MinGW2.2 Visual Studio 3 参考链接 1 windows 1.1 cmake 1.1.1 修改.exe程序图标 获得一个…

【Linux】进程控制的详细介绍

前言 在此之前&#xff0c;我们学过进程的概念&#xff0c;进程的状态&#xff0c;进程地址空间等一系列进程相关的问题。本章我们继续学习进程&#xff0c;我们要来学习一下进程的控制&#xff0c;关于进程等待&#xff0c;等问题。 目录 1.再次认识Fork函数1.1 fork()之后操…