【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>
相關文章
相關標籤/搜索