【Java】代码块

<font color="Teal"><b>前言</b></font>html

<hr> 在程序编写之中能够直接使用<font color=red>`{...}`</font>定义的一段语句就是代码块。根据代码块的位置以及关键字的不一样能够分为4种:普通代码块、构造块、静态块以及同步代码块(多线程相关)。下面将先介绍前3种以及Java类的初始化顺序:<br> <li><a href="#1" style="text-decoration:none">普通代码块</a></li> <li><a href="#2" style="text-decoration:none">构造块</a></li> <li><a href="#3" style="text-decoration:none">静态块</a></li> <li><a href="#4" style="text-decoration:none">Java类的初始化顺序</a> <ul> <li><a href="#41" style="text-decoration:none">对于一个类(没有继承)的初始化状况</a></li> <li><a href="#42" style="text-decoration:none">对于有继承的状况</a></li> </ul> </li>多线程

<a name="1"><font color="Teal"><b>普通代码块</b></font></a>函数

<hr>this

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

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

{...}表示的是一个做用域,内部定义的变量的能够起做用的范围仅在{...}这个范围内。<br> 上面代码中{int num=0;}的num在离开{...}后就被销毁了,因而能够在外部又能够定义int num=100。<br> 如果写成如下:线程

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

由于外部也存在num这个变量,且有效。因此,这样定义会出错。<br>code

普通代码块的做用就是<u>为了防止在方法中编写代码过多,产生变量重名,因而对一个方法中的代码进行局部的分割</u>。可是建议一个方法中的代码不要太长,尽可能不使用普通代码块<br>htm

<br> <a name="2"><font color="Teal"><b>构造块</b></font></a> <hr> 若是将一个代码块放在类里面,那么就是一个构造块。<br> <u>构造块的做用是为了给对象进行初始化</u>。咱们知道构造函数的做用也是为了给对象进行初始化,那么这二者有什么区别呢?<br> ```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 */blog

能够看出每次建立对象时,都会调用一次构造块,而且<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
*/

对于一个类而言:<br>

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

<font color="red">静态代码块>主函数>构造代码块>构造函数</font>

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

<font color="red">静态变量、静态代码块 > 主函数 > 指定初始值的属性 > 构造代码块 > 构造函数</font>

<br> <a name="42"><font color="#a5615f"><b>对于有继承的状况</b></font></a> <hr> ```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>
相关文章
相关标签/搜索