前言


在程序编写之中可以直接使用`{...}`定义的一段语句就是代码块。根据代码块的位置以及关键字的不同可以分为4种:普通代码块、构造块、静态块以及同步代码块(多线程相关)。下面将先介绍前3种以及Java类的初始化顺序:

  • 普通代码块
  • 构造块
  • 静态块
  • Java类的初始化顺序
  • 普通代码块


    写在方法里面的代码块就是普通代码块

    public static void main(String args[]){
    {
    int num = 0;
    }
    int num=100;
    }

    {...}表示的是一个作用域,内部定义的变量的可以起作用的范围仅在{...}这个范围内。

    上面代码中{int num=0;}的num在离开{...}后就被销毁了,于是可以在外部又可以定义int num=100

    若是写成以下:

    public static void main(String args[]){
    int num=100;
    {
    int num = 0; //报错:Duplicate local variable num
    }
    }

    因为外部也存在num这个变量,且有效。所以,这样定义会出错。

    普通代码块的作用就是为了防止在方法中编写代码过多,产生变量重名,于是对一个方法中的代码进行局部的分割。但是建议一个方法中的代码不要太长,尽量不使用普通代码块

    构造块


    如果将一个代码块放在类里面,那么就是一个构造块。

    构造块的作用是为了给对象进行初始化。我们知道构造函数的作用也是为了给对象进行初始化,那么这两者有什么区别呢?

    ```Java
    public class Student {
    private String name;
    private int age;

    //无参构造函数
    public Student() {
    System.out.println("constructor with no args ");
    System.out.println("name:"+this.name + " age:"+this.age);
    this.name = "no name";
    this.age = 18;
    } //有参构造函数
    public Student(String name, int age){
    System.out.println("constructor with args");
    System.out.println("name:"+this.name + " age:"+this.age);
    this.name = name;
    this.age = age;
    } //构造块
    {
    System.out.println("constructor block ");
    name = "cbname";
    age = 20;
    } public static void main(String[] args) {
    new Student();
    System.out.println("==========");
    new Student("sakura", 19);
    }

    }

    /*

    output:

    constructor block

    constructor with no args

    name:cbname age:20

    constructor block

    constructor with args

    name:cbname age:20

    */

    可以看出每次创建对象时,都会调用一次构造块,并且<b>构造块的优先于构造函数执行</b>。有对象的创建,才会调用构造快,类是不能调用构造块的。<br>
    
    构造块与构造函数的区别在于:每个对象被构造块初始化的那部分变量拥有的初始值是一样的,<b>构造块对所有对象的效果是一样的</b>。然而每个对象可能会使用不同构造函数,<b>不同的构造函数初始化对象的方式是不同的</b>。
    
    <br>
    <a name="3"><font color="Teal"><b>静态块</b></font></a>
    <hr>
    使用static修饰的代码块就叫做静态代码块或者直接叫静态块。<br> 前面在介绍<a style="text-decoration:none" target="_blank" href="https://www.cnblogs.com/myworld7/p/10052245.html#23" >
    <b>static关键字</b></a>(可以回顾查看)时,介绍了一部分static修饰代码块的知识。
    * 静态块在类加载时执行,且只会<b>执行一次</b>,<b>执行顺序优先主函数、构造函数和构造块</b>。 * 静态代码块主要用于<b>初始化类中的static属性(类属性)</b>,而构造块是初始化对象中的属性 * 一个类中可以有多个静态代码块, 执行顺序依照静态代码块的声明顺序。静态代码块<b>可以在类的任意位置定义,在方法中不可以声明静态块</b>。 <br>
    <a name="4"><font color="Teal"><b>Java类的初始化顺序</b></font></a>
    <hr>
    <br>
    <a name="41"><font color="#a5615f"><b>对于一个类(没有继承)的初始化情况</b></font></a>
    <hr>
    ```Java
    public class Student {
    private String name="no name";
    private int age=18;
    private static int id=1;
    //无参构造函数
    public Student() {
    System.out.println("======");
    System.out.println("无参构造函数");
    System.out.println("姓名:"+name+" 年龄:"+age);
    } //有参构造函数
    public Student(String name, int age){
    System.out.println("======");
    System.out.println("有参构造函数");
    System.out.println("姓名:"+this.name+" 年龄:"+this.age);
    this.name = name;
    this.age = age;
    System.out.println("姓名:"+this.name+" 年龄:"+this.age);
    } //构造块
    {
    System.out.println("======");
    System.out.println("构造块");
    System.out.println("姓名:"+this.name+" 年龄:"+this.age);
    this.name = "cbname";
    this.age = 18;
    } //静态代码块
    static {
    System.out.println("======");
    System.out.println("静态块");
    System.out.println("静态变量id="+id);
    } public static void main(String[] args) {
    System.out.println("======");
    System.out.println("主方法");
    new Student();
    new Student("小王",20);
    }
    } /*
    output:
    ======
    静态块
    静态变量id=1
    ======
    主方法
    ======
    构造块
    姓名:no name 年龄:18
    ======
    无参构造函数
    姓名:cbname 年龄:18
    ======
    构造块
    姓名:no name 年龄:18
    ======
    有参构造函数
    姓名:cbname 年龄:18
    姓名:小王 年龄:20
    */

    对于一个类而言:

    静态代码块、构造代码块、构造函数和主函数的执行顺序为:

    静态代码块>主函数>构造代码块>构造函数

    在加上静态属性、普通属性,他们的初始化执行顺序就为:

    静态变量、静态代码块 > 主函数 > 指定初始值的属性 > 构造代码块 > 构造函数

    对于有继承的情况


    ```Java
    class Person{
    private String name="Person没有名字";
    private int age=10;
    private static int id=1;
    //无参构造函数
    public Person() {
    System.out.println("======");
    System.out.println("Person无参构造函数");
    System.out.println("Person 姓名:"+this.name+" 年龄:"+this.age);
    }

    //构造块
    {
    System.out.println("======");
    System.out.println("Person 构造块");
    System.out.println("Person 姓名:"+this.name+" 年龄:"+this.age);
    this.name = "pcbname";
    this.age =11 ;
    } //静态代码块
    static {
    System.out.println("======");
    System.out.println("Person 静态块");
    System.out.println("Person 静态变量id="+id);
    }

    }

    public class Student extends Person{

    private String name="Student没有名字";

    private int age=18;

    private static int id=2;

    //无参构造函数

    public Student() {

    //自动调用父类的无参构造函数 super();

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

    System.out.println("Student无参构造函数");

    System.out.println("Student 姓名:"+this.name+" 年龄:"+this.age);

    }

    //有参构造函数
    public Student(String name, int age) {
    //自动调用父类的无参构造函数 super();
    System.out.println("======");
    System.out.println("Student有参构造函数");
    System.out.println("Student 姓名:"+this.name+" 年龄:"+this.age);
    this.name = name;
    this.age = age;
    } //构造块
    {
    System.out.println("======");
    System.out.println("Student 构造块");
    System.out.println("Student 姓名:"+this.name+" 年龄:"+this.age);
    this.name = "scbname";
    this.age = 19;
    } //静态代码块
    static {
    System.out.println("======");
    System.out.println("Student 静态块");
    System.out.println("Student 静态变量id="+id);
    } public static void main(String[] args) {
    System.out.println("======");
    System.out.println("主方法");
    System.out.println("\n--------第一次创建Studet对象--------");
    new Student();
    System.out.println("\n--------第二次创建Studet对象--------");
    new Student("小夏",20);
    }

    }

    /*

    Person 静态块

    Person 静态变量id=1

    Student 静态块

    Student 静态变量id=2

    主方法

    --------第一次创建Studet对象--------

    Person 构造块

    Person 姓名:Person没有名字 年龄:10

    Person无参构造函数

    Person 姓名:pcbname 年龄:11

    Student 构造块

    Student 姓名:Student没有名字 年龄:18

    Student无参构造函数

    Student 姓名:scbname 年龄:19

    --------第二次创建Studet对象--------

    Person 构造块

    Person 姓名:Person没有名字 年龄:10

    Person无参构造函数

    Person 姓名:pcbname 年龄:11

    Student 构造块

    Student 姓名:Student没有名字 年龄:18

    Student有参构造函数

    Student 姓名:scbname 年龄:19

    */

    观察代码结果,分析,对于有继承关系的类,初始化顺序按如下进行:
    > 1. 执行父类的静态代码块,并初始化父类静态成员变量
    2. 执行子类的静态代码块,并初始化子类静态成员变量
    3. 执行父类的构造代码块,执行父类的构造函数,若普通成员变量指定了初始值则先执行初始值的赋值,然后返回执行构造函数
    4.执行子类的构造代码块,执行子类的构造函数,若普通成员变量指定了初始值则先执行初始值的赋值,然后返回执行构造函数 <br>
    <font color="Teal"><b>小结</b></font>
    <hr>
    本文介绍的三种代码块,普通块和构造块都不建议使用,静态块可以使用用于初始化静态变量。<br>
    理清Java程序初始化的执行顺序可以很清楚地掌握程序的执行过程。<br>
    对一个类而言,`静态变量和静态代码块> 主函数 > 指定初始值的属性 > 构造代码块 > 构造函数`<br>
    对于有继承的来说,`父类静态块和静态变量 > 子类静态块和静态变量 > 父类指定初始值的属性 > 父类构造块 > 父类构造函数 > 子类指定初始值的属性 > 子类构造块 > 子类构造函数`<br> 参考博客:
    <https://www.cnblogs.com/Qian123/p/5713440.html>

    Java——代码块的更多相关文章

    1. Java代码块详解

      Java中代码块指的是用 {} 包围的代码集合,分为4种:普通代码块,静态代码块,同步代码块,构造代码块 普通代码块: 定义:在方法.循环.判断等语句中出现的代码块 修饰:只能用标签修饰 位置:普通代 ...

    2. java代码块的理解

      最近在复习java基础,在看到java代码块的时候,忽然发现自己貌似对于java代码块一无所知,于是赶紧对着一些资料实战演练了一把. 对于java代码块,不难根据名称看出其实就是一些java语句的集合 ...

    3. java代码块执行顺序

      父类 public class Father { public Father() { System.out.println("父类构造PUBLIC father"); } stat ...

    4. 夯实Java基础系列7:一文读懂Java 代码块和执行顺序

      目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...

    5. 夯实Java基础系列7:Java 代码块和执行顺序

      本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

    6. Java 代码块详解

      注:本文出自博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 注:本文原链接:https://www.cnblogs.com/chloneda/p/java-c ...

    7. java代码块 静态、非静态

      Java虚拟机的内存分区:Java栈.堆.方法区.本地方法栈.PC寄存器.还有一个常量池的概念,虚拟机会为每种类型分配一个常量池,而不是实例. 例如有一个类有很多子类,那么在父类定义的final变量, ...

    8. 08-02 Java 代码块,代码块执行的先后顺序问题

      代码块 /* 代码块:在Java中,使用{}括起来的代码被称为代码块. 根据其位置和声明的不同,可以分为 局部代码块:局部位置,用于限定变量的生命周期. 构造代码块:在类中的成员位置,用{}括起来的代 ...

    9. Java 代码块

      一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. 3.静态代码块: 用static{}包裹起来的代码片段,只会执 ...

    随机推荐

    1. HTTP lab01 做一个简单的测试用 web页面

        做一个简单的测试用 web页面     1.安装httpd服务   yum install httpd   安装完httpd服务后,系统就自动生成了/var/www/html目录     创建一个 ...

    2. 转 tomcat+nginx+redis实现均衡负载、session共享(二)

      http://www.cnblogs.com/zhrxidian/p/5491285.html http://www.cnblogs.com/zhrxidian/p/5432886.html

    3. c#项目减少源代码大小

      这次的代码缩减主要通过了这几个方面 1.bin和obj文件的删除(以前真的不知道,只是通过右键属性发现这些文件太大,然后上网搜索才知道,这些文件在源代码备份的时候是建议删掉的) 删掉的好处: 1.减少 ...

    4. Visual Studio 开发(一):安装配置Visual Studio Code

      一.为何使用Visual Studio Code 在学习音视频开发的时候,使用到了C和C++,在回顾复习C和C++的知识的时候,需要编写一些代码来加强理解. 虽然,有在线的语言编辑工具https:// ...

    5. 从 0 开始手写一个 Mybatis 框架,三步搞定!

      阅读本文大概需要 3 分钟. MyBatis框架的核心功能其实不难,无非就是动态代理和jdbc的操作,难的是写出来可扩展,高内聚,低耦合的规范的代码. 本文完成的Mybatis功能比较简单,代码还有许 ...

    6. 吴恩达机器学习笔记35-诊断偏差和方差(Diagnosing Bias vs. Variance)

      当你运行一个学习算法时,如果这个算法的表现不理想,那么多半是出现两种情况:要么是偏差比较大,要么是方差比较大.换句话说,出现的情况要么是欠拟合,要么是过拟合问题.那么这两种情况,哪个和偏差有关,哪个和 ...

    7. Git使用详细教程(4):git rm使用详解

      我们使用git rm 文件名来进行删除文件的操作. git rm index.php这个命令把工作区的index.php删除并暂存了. 如何撤回已暂存的删除命令? 上图中已经给出了提示,使用git r ...

    8. Redis 搭建文档,备份及认证

      wget http://download.redis.io/releases/redis-3.0.6.tar.gz为了方便管理,将Redis文件中的conf配置文件和常用命令移动到统一文件中[root ...

    9. hashMap,hashTable,concurrentHashMap区别

      HashTable 底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相 ...

    10. 基于 jq 实现拖拽上传 APK 文件,js解析 APK 信息

      技术栈 jquery 文件上传:jquery.fileupload,github 文档 apk 文件解析:app-info-parser,github 文档 参考:前端解析ipa.apk安装包信息 - ...