首页 > 编程语言 >Java初学-8.3-代码块(实例初始化块/普通代码块和静态初始化块/静态代码块)

Java初学-8.3-代码块(实例初始化块/普通代码块和静态初始化块/静态代码块)

时间:2024-07-27 10:27:05浏览次数:15  
标签:初始化 静态 代码 System println public out

代码块又称初始化块,属于类中的成员,即类的一部分。类似于方法,将逻辑语句封装在方法体中,用{}包围起来。与方法不同的是,代码块没有方法名,没有返回值,没有参数,只有方法体,而且不能通过对象或类显式调用,而是在加载类时或创建对象时隐式调用。  

代码块可以用访问修饰符修饰,也可以写static关键字。

代码块可以分为两大类:实例初始化块/普通代码块和静态初始化块/静态代码块

实例初始化块/普通代码块

实例初始化块是在类体中定义的代码块,由一对大括号 {} 包围,不在任何方法内部。这种代码块会在每个对象创建时自动执行,并且在构造函数调用之前执行。它们通常用于对象状态的初始化。

示例1:

package CodeBlockTest;

public class CodeBlockTest01 {
    private int x;
    private int y;

    { // 实例初始化块
        x = 100;
        y = 200;
    }//;可加可不加

    public CodeBlockTest01() {
        System.out.println("x: " + x + " , y: " + y);
    }

    public static void main(String[] args) {
        CodeBlockTest01 CBT01 = new CodeBlockTest01(); // 构造函数前会执行实例初始化块
    }
}

示例2:

package CodeBlockTest;

public class CodeBlockTest03 {
    public static void main(String[] args) {
        CodeBlockTest03001 CBT03000101 = new CodeBlockTest03001("name");
        CodeBlockTest03001 CBT03000102 = new CodeBlockTest03001("name",12);
        CodeBlockTest03001 CBT03000103 = new CodeBlockTest03001("name",18,22.23);
    }
}
class CodeBlockTest03001{
    private int x;
    private int y;
    private int z;

    {
        x = 10;
        y = 20;
        z = 30;
        System.out.println("x = " + x);
        System.out.println("y = " + y);
        System.out.println("z = " + z);
    }

    public CodeBlockTest03001(String name) {
        System.out.println("CodeBlockTest03001(String name)");
    }

    public CodeBlockTest03001(String name,int a) {
        System.out.println("CodeBlockTest03001(String name,int a)");
    }

    public CodeBlockTest03001(String name,int a,double b) {
        System.out.println("CodeBlockTest03001(String name,int a,double b)");
    }
}

实例初始化块:每当创建一个新的 CodeBlockTest03001 对象时,这个实例初始化块都会被执行。它在所有构造器执行之前运行。

代码执行流程

当创建 CodeBlockTest03001 的对象时,执行流程如下:

分配内存:为新的 CodeBlockTest03001 对象分配内存。

实例初始化块执行:初始化块中的代码运行,设置 x, y, 和 z 的初始值,并打印它们。

构造器执行:调用与创建对象时提供的参数相匹配的构造器。构造器可以进一步初始化对象的状态,或者执行其他的初始化任务。

在给定的代码中,main 方法创建了三个 CodeBlockTest03001 的对象,每个对象都会先执行实例初始化块,然后调用相应的构造器。

则有:

每当一个类的构造器被调用来创建一个新的对象时,该类中的实例初始化块(非静态的初始化块)都会被执行。实例初始化块是在每个对象实例创建时都要运行的代码,它会在构造器执行之前运行。这是因为实例初始化块是为每个对象的初始化服务的,它的目的是确保在构造器开始执行之前,对象的某些状态已经被正确地设置。

静态初始化块/静态代码块

静态初始化块与实例初始化块类似,但它们使用 static 关键字定义。这意味着它们只在类加载时执行一次,而不是每次创建对象时都执行。它们通常用于初始化类的静态成员。

示例1:

package CodeBlockTest;

public class CodeBlockTest02 {
    static int x;

    static { // 静态初始化块
        x = 10000;
    }

    public static void main(String[] args) {
        System.out.println("x: " + CodeBlockTest02.x);
    }
}

示例2:

package CodeBlockTest;

public class CodeBlockTest04 {

    public static void main(String[] args) {

        CodeBlockTest04001 CBT04001 = new CodeBlockTest04001("嘻嘻~");

        CodeBlockTest04001 CBT04002 = new CodeBlockTest04001("哈哈",12);

        CodeBlockTest04001 CBT04003 = new CodeBlockTest04001("嘎嘎",18,22.3);

    }

}

class CodeBlockTest04001{

    private int a;

    private static int b;

    static {

        System.out.println("------------------");

        //a = 1;编译错误,因为a是非静态的        

b = 2;

        System.out.println("b = " + b);

        System.out.println("------------------");

    }

    public CodeBlockTest04001(String name) {

        System.out.println("CodeBlockTest04001(String name)");

    }

    public CodeBlockTest04001(String name,int x) {

        System.out.println("CodeBlockTest04001(String name,int a)");

    }

    public CodeBlockTest04001(String name,int x,double y) {

        System.out.println("CodeBlockTest04001(String name,int a,double y)");

    }

}

由输出结果可知,只在类加载时执行一次即输出一次,并且用于用于初始化类的静态成员。

那么类什么时候加载呢?

package CodeBlockTest;

public class CodeBlockTest05 {
    public static void main(String[] args) {
//1
        //这个静态初始化块会在类加载的时候执行,而不是在创建类的实例时执行。
        // 因此,当运行main方法并创建CodeBlockTest05001的实例时,下面的事件会发生:
        //类CodeBlockTest05001被加载,此时静态初始化块会被执行,输出:“CodeBlockTest05001中的静态代码块。”
        //然后,new CodeBlockTest05001()语句会调用CodeBlockTest05001类的默认无参构造器来创建一个新实例。
        /*System.out.println("----------------------------------------------");
        CodeBlockTest05001 CBT05001 = new CodeBlockTest05001();
        System.out.println("----------------------------------------------");
        */



//2
        //由于CodeBlockTest05002继承自CodeBlockTest05001,在创建CodeBlockTest05002的实例时,
        // JVM会先加载CodeBlockTest05001类(如果它还没有被加载的话),然后执行CodeBlockTest05001中的静态初始化块。
        // 接着,JVM会加载CodeBlockTest05002类,并执行其静态初始化块。
        // 最后,JVM会创建CodeBlockTest05002的实例,执行CodeBlockTest05002的构造器以及实例初始化块(如果有的话)。
        /*System.out.println("----------------------------------------------");
        CodeBlockTest05002 CBT05002 = new CodeBlockTest05002();
        System.out.println("----------------------------------------------");
        */




//3
        //调用类的静态成员时,也会执行其静态初始化块。
        //加载CodeBlockTest05003类:
        //当main方法尝试访问CodeBlockTest05003.name时,JVM检测到需要使用CodeBlockTest05003类的静态变量name。
        //如果CodeBlockTest05003类尚未被加载,JVM将加载这个类,包括执行其静态初始化块。
        //执行CodeBlockTest05003类的静态初始化块:
        //在加载CodeBlockTest05003类的过程中,静态初始化块会被执行,输出 "CodeBlockTest05003中的静态代码块。"。
        //访问CodeBlockTest05003.name:
        //由于CodeBlockTest05003类已经被加载并初始化,现在可以访问静态变量name。
        System.out.println(CodeBlockTest05003.name);

        //CodeBlockTest05003.CodeBlockTest0500301();
        //即只要程序首次主动使用了类的静态成员,无论是否创建了类的实例,相关的静态初始化过程都会发生。
    }
}
//类被加载的情况:
//1、创建类的实例:
//当你首次创建一个类的实例时,如果该类或其超类(父类)中包含静态代码块,这些静态代码块将会在实例创建之前执行。
// 这是因为类在实例化之前必须先被加载,而静态代码块正是在类加载时执行的。
//2、访问类的静态成员:
//当你首次访问一个类的静态成员(如静态变量或静态方法)时,如果该类还未被加载,JVM将加载该类并执行其静态代码块。
// 这是因为静态成员是类的一部分,而不是特定实例的一部分,所以它们的初始化和准备必须在类加载时完成。
//3、使用反射机制加载类(没学呢):
//当你使用反射API,如Class.forName(className),显式地加载一个类时,如果该类包含静态代码块,
// 静态代码块将在类加载时执行。这种情况下,类的加载完全由程序控制,通常是为了动态地获取类的信息或创建实例。
class CodeBlockTest05001{
    static {
        System.out.println("CodeBlockTest05001中的静态代码块。");
    }
}
class CodeBlockTest05002 extends CodeBlockTest05001{
    static {
        System.out.println("CodeBlockTest05002中的静态代码块。");
    }
}
class CodeBlockTest05003 {
    public static String name = "CodeBlockTest05003";
    public static void CodeBlockTest0500301(){
        System.out.println("静态方法: CodeBlockTest0500301()");
    }
    static {
        System.out.println("CodeBlockTest05003中的静态代码块。");
    }
}

不同类型的代码块(普通代码块和静态代码块)以及构造函数的使用方式(只有一个类):

示例:

package CodeBlockTest;

public class CodeBlockTest07 {
    public static void main(String[] args) {
        CodeBlockTest07001 CBT0701 = new CodeBlockTest07001("少林呱呱");
        CodeBlockTest07001 CBT0702 = new CodeBlockTest07001("富贵呱呱",12);
        CodeBlockTest07001 CBT0703 = new CodeBlockTest07001("逍遥呱呱",13,8);

    }
}
class CodeBlockTest07001{
    //每创建一次对象就会输出一次
    private String name = getName();

    {
        System.out.println("CodeBlockTest07001的第一个普通代码块。");
    }

    {
        System.out.println("CodeBlockTest07001的第二个普通代码块。");
    }

    public String getName(){
        System.out.println("getName()方法。");
        return "CodeBlockTest07001";
    }



//---------------------------------------------------------------------------------------------------
    //只输出一次!!!
    private static int x = getX();

    private static int y = getY();

    static{
        System.out.println("CodeBlockTest07001的第一个静态代码块。");
    }

    static{
        System.out.println("CodeBlockTest07001的第二个静态代码块。");
    }

    public static int getX(){
        System.out.println("getX()方法");
        return 123;
    }

    public static int getY(){
        System.out.println("getY()方法");
        return 456;
    }
//---------------------------------------------------------------------------------------------------
    //构造器
    public CodeBlockTest07001(String NAME){
        System.out.println("第一个构造器CodeBlockTest07001(String NAME)。");
    }
    public CodeBlockTest07001(String NAME, int A){
        System.out.println("第二个构造器CodeBlockTest07001(String NAME, int A)。");
    }
    public CodeBlockTest07001(String NAME, int A, int B){
        System.out.println("第三个构造器CodeBlockTest07001(String NAME, int A, int B)。");
    }
}
/*
执行顺序:
静态变量初始化:
x的初始化通过调用getX()方法来进行。
y的初始化通过调用getY()方法来进行。
这些初始化在类首次被加载时发生,并且发生在任何静态代码块之前(因为初始化顺序遵循它们在源代码中的声明顺序)。
静态代码块执行:
第一个静态代码块执行。
第二个静态代码块执行。
这些静态代码块在类首次被加载时执行,并且只执行一次。
创建对象:
对于每个对象创建:执行普通代码块。
调用对应的构造函数。
普通代码块执行:
每次创建对象时,普通代码块都会按照它们在源代码中的出现顺序执行。
name的初始化通过调用getName()方法来进行。
详细分析
静态变量和静态代码块:
x和y的初始化在类首次被加载时发生,并且在任何静态代码块之前(因为初始化顺序遵循它们在源代码中的声明顺序)。
两个静态代码块按照它们在源代码中的出现顺序执行。
普通代码块:
每次创建CodeBlockTest07001类的实例时,普通代码块都会执行。
普通代码块按照它们在源代码中的出现顺序执行。
构造函数:
构造函数在每个对象创建时被调用。
三个不同的构造函数被调用,分别对应不同的参数列表。
*/

package CodeBlockTest;

public class CodeBlockTest08 {
    public static void main(String[] args) {

        CodeBlockTest08002 CBT0801 = new CodeBlockTest08002();
    }
}

class CodeBlockTest08001{
    {
        System.out.println("父类CodeBlockTest08001中的普通代码块。");
    }
    public CodeBlockTest08001() {
        System.out.println("父类CodeBlockTest08001的无参构造函数。");
    }
}

class CodeBlockTest08002 extends CodeBlockTest08001{
    {
        System.out.println("子类CodeBlockTest08002中的普通代码块。");
    }
    public CodeBlockTest08002() {
        System.out.println("子类CodeBlockTest08002的无参构造函数。");
    }
}

构造函数调用顺序:

当创建一个子类对象时,构造函数的调用顺序是先调用父类的构造函数,再调用子类的构造函数。如果父类没有显式地调用其自身的构造函数,则会默认调用无参构造函数。

普通代码块执行顺序:

普通代码块在每个对象创建时执行,并且按照它们在源代码中的出现顺序执行。子类的普通代码块在父类构造函数调用之后执行。

由此引出继承关系中构造函数和普通代码块的执行顺序:

package CodeBlockTest;

public class CodeBlockTest09 {
    public static void main(String[] args) {
        /*new CodeBlockTest09001("少林呱呱");

        new CodeBlockTest09002("富贵呱呱");*/

        new CodeBlockTest09003("逍遥呱呱");
    }
}

class CodeBlockTest09001{
    private int a = getA();
    {
        System.out.println("CodeBlockTest09001的普通代码块。");
    }

    public int getA(){
        System.out.println("getA()方法。");
        return 1;
    }

//------------------------------------------------------------------------------------------------
    private static int b = getB();
    static {
        System.out.println("CodeBlockTest09001的静态代码块。");
    }

    public static int getB(){
        System.out.println("getB()方法。");
        return 2;
    }
    //------------------------------------------------------------------------------------------------
    public CodeBlockTest09001(String NAME){
        System.out.println("CodeBlockTest09001(String NAME)构造器。");
    }
}

class CodeBlockTest09002 extends CodeBlockTest09001{
    private int c = getC();
    {
        System.out.println("CodeBlockTest09002的普通代码块。");
    }
    public int getC(){
        System.out.println("getC()方法。");
        return 3;
    }

    //------------------------------------------------------------------------------------------------
    private static int d = getD();
    static {
        System.out.println("CodeBlockTest09002的静态代码块。");
    }

    public static int getD(){
        System.out.println("getD()方法。");
        return 4;
    }
    //------------------------------------------------------------------------------------------------
    public CodeBlockTest09002(String NAME){
        super(NAME);
        System.out.println("CodeBlockTest09002(String NAME)构造器。");
    }
}

class CodeBlockTest09003 extends CodeBlockTest09002{
    private int e = getE();
    {
        System.out.println("CodeBlockTest09003的普通代码块。");
    }
    public int getE(){
        System.out.println("getE()方法。");
        return 5;
    }

    //------------------------------------------------------------------------------------------------
    private static int f = getF();
    static {
        System.out.println("CodeBlockTest09003的静态代码块。");
    }

    public static int getF(){
        System.out.println("getF()方法。");
        return 6;
    }
    //------------------------------------------------------------------------------------------------
    public CodeBlockTest09003(String NAME){
        super(NAME);
        System.out.println("CodeBlockTest09003(String NAME)构造器。");
    }
}

输出结果为:

getB()方法。

CodeBlockTest09001的静态代码块。

getD()方法。

CodeBlockTest09002的静态代码块。

getF()方法。

CodeBlockTest09003的静态代码块。

//从结果上看先输出父类的静态属性和静态代码块(按实际在代码中的顺序输出),再输出子类的静态属性和静态代码块。

getA()方法。

CodeBlockTest09001的普通代码块。

CodeBlockTest09001(String NAME)构造器。

getC()方法。

CodeBlockTest09002的普通代码块。

CodeBlockTest09002(String NAME)构造器。

getE()方法。

CodeBlockTest09003的普通代码块。

CodeBlockTest09003(String NAME)构造器。

//紧接着是父类的普通属性和普通代码块(同样地按实际在代码中的顺序输出),再输出父类的构造器。然后是子类的普通属性和普通代码块(同样地按实际在代码中的顺序输出),再输出子类的构造器。

/*new CodeBlockTest09001("少林呱呱");

        new CodeBlockTest09002("富贵呱呱");*/

当这两行不注释时,输出也有相同的效果。并且其输出也说明了静态代码块只执行一次即只输出一次。

普通代码块和静态代码块调用的不同:

package CodeBlockTest;

public class CodeBlockTest10 {
    public static void main(String[] args) {

    }
}
class CodeBlockTest10001{
    public int x;
    public static int y;
    public int getX(){
        return this.x;
    }
    public static int getY(){
        return y;//this???
    }
    {
        x = 10;
        System.out.println(getX());
        y = 20;
        System.out.println(getY());
    }
    static {
        y = 100;
        System.out.println(getY());
        //x = 200;
        //System.out.println(getX());
        //静态代码块只能调用静态属性和静态方法。
    }
}

标签:初始化,静态,代码,System,println,public,out
From: https://blog.csdn.net/jhdyjbxsryokvdry/article/details/140694618

相关文章

  • 我写了一个代码来分隔偶数和奇数,但我遇到了这个错误?
    whileTrue:num=input("plstypethenumber:")#checkifit'sintorstringnumber=int(num)exceptValueError:print("errortryagain!!")continue#ifitwaswronggoback#ch......
  • 如何注释用文字初始化的“OrderedDict”的类型?
    假设我有以下内容:fromcollectionsimportOrderedDictfromdataclassesimportdataclass@dataclassclassHelloWorld:x:OrderedDict[str,int]a=OrderedDict([("a",0),("c",2),("b",1)])HelloWorld(a)<---#typeerro......
  • stata 代码实现熵值法计算 含常见问题解答
    适用:面板数据均可stata版本:无要求例如,使用了一个10年的省级面板数据,含15个指标,现在来计算各地区的熵值法得分。其中,x1x2x3x4x6x7x8x9x11x12x13x14x15是正向指标;而x5x10是负向指标。1.定义面板,定义指标的正负。tssetidyearglobalxlist1"x1x2x3x4x6x......
  • 七夕特献:用代码编织爱情的浪漫,程序员的专属爱情证书生成器
    文章目录1.背景介绍2.**为什么是爱情证书生成器?**3.**功能亮点**4.**技术实现**5.**如何获取?**6.总结1.背景介绍在这个数字化的时代,程序员们用代码编织世界,创造无限可能。七夕将至,一个充满古老传说和浪漫气息的东方情人节,我们何不用自己最擅长的方式,来表达内......
  • window系统使用经验:新买的window11初始化时最好要选择用Microsoft账户激活,而不要用loc
    Windows系统初始化时有两种类型的账户可以选择,一种时Microsoft账户,一种时local账户,Microsoft账户需要联网初始化,而local账户则和传统的初始化方式一致,即账号信息保存在本地而不和云端的Microsoft服务器上的信息同步。即使是使用local账户激活后也可以在进入系统后通过关联Micro......
  • 嵌入式Python、ROS、SLAM、WebSocket和Node.js:智能巡逻监控安防机器人设计流程(代码示
    项目概述随着智能技术的发展,智能巡逻机器人在安防、监控和巡逻等领域的应用越来越广泛。本文将介绍一个结合嵌入式系统、机器人技术和后端开发的智能巡逻机器人。该机器人能够自主导航,实时检测异常情况(如火灾或入侵者),并将数据发送到后端服务器,以实现高效的监控和应急响应。主......
  • 如何使用pytorch 远程服务器调试代码|同步编辑
    写在前面:写这篇博客的原因是本新手小白开始用服务器跑代码,有时候发现效果不理想,就要重新更改代码再上传到服务器重新跑,一来二去觉得很费工夫,就想:能不能在自己电脑上更新代码同时在服务器同步跟新,研究了一下发现pytorch可以远程服务器,实现了在我的电脑上改代码,在服务器上跑代......
  • vs2022 QT Opencv用到的一些代码
     MyFirstQT.cpp#include"MyFirstQT.h"#include"ui_MyFirstQT.h"#include<QFileDialog>#include<QMessageBox>#include<QPixmap>#include<opencv2/opencv.hpp>#include<QDebug>#include<opencv2/imgp......
  • jvm执行代码注释部分
    procedureTForm1.btn1Click(Sender:TObject);varjcls:JClass;strClass:AnsiString;strMetod:AnsiString;strSign:AnsiString;strArg1,strArg2:string;strResult:AnsiString;begin{查询Java类名,不用加.class扩展名}s......
  • C++优先队列 涵盖各种易错,技巧,应用和原理(附手写代码)
    当然也可以不看==> 阅读我的文章前请务必先阅读此文章! 都是废话这个文章里有视频,不知道为什么一点开文章就会播放,可以先翻到最后暂停一下再回来看目录阅读文章须知引言优先队列的概念优先队列的创建优先队列的操作*还有一些不常用的:优先队列的技巧如果类型是结构......