Java中靜態代碼塊、構造代碼塊、構造函數、普通代碼塊

  在Java中,靜態代碼塊、構造代碼塊、構造函數、普通代碼塊的執行順序是一個筆試的考點,經過這篇文章但願你們能完全瞭解它們之間的執行順序。java

一、靜態代碼塊

  ①、格式

  在java類中(方法中不能存在靜態代碼塊)使用static關鍵字和{}聲明的代碼塊:安全

public class CodeBlock {
	static{
		System.out.println("靜態代碼塊");
	}
}

  ②、執行時機

  靜態代碼塊在類被加載的時候就運行了,並且只運行一次,而且優先於各類代碼塊以及構造函數。若是一個類中有多個靜態代碼塊,會按照書寫順序依次執行。後面在比較的時候會經過具體實例來證實。函數

  ③、靜態代碼塊的做用

  通常狀況下,若是有些代碼須要在項目啓動的時候就執行,這時候就須要靜態代碼塊。好比一個項目啓動須要加載的不少配置文件等資源,咱們就能夠都放入靜態代碼塊中。測試

  ④、靜態代碼塊不能存在任何方法體中

  這個應該很好理解,首先咱們要明確靜態代碼塊是在類加載的時候就要運行了。咱們分狀況討論:對象

  對於普通方法,因爲普通方法是經過加載類,而後new出實例化對象,經過對象才能運行這個方法,而靜態代碼塊只須要加載類以後就能運行了。blog

  對於靜態方法,在類加載的時候,靜態方法也已經加載了,可是咱們必需要經過類名或者對象名才能訪問,也就是說相比於靜態代碼塊,靜態代碼塊是主動運行的,而靜態方法是被動運行的。資源

  不論是哪一種方法,咱們須要明確靜態代碼塊的存在在類加載的時候就自動運行了,而放在不論是普通方法仍是靜態方法中,都是不能自動運行的。編譯器

  ⑤、靜態代碼塊不能訪問普通變量

  這個理解思惟同上,普通變量只能經過對象來調用,是不能放在靜態代碼塊中的。編譯

二、構造代碼塊

  ①、格式

  在java類中使用{}聲明的代碼塊(和靜態代碼塊的區別是少了static關鍵字):class

public class CodeBlock {
	static{
		System.out.println("靜態代碼塊");
	}
	{
		System.out.println("構造代碼塊");
	}
}

  ②、執行時機

  構造代碼塊在建立對象時被調用,每次建立對象都會調用一次,可是優先於構造函數執行。須要注意的是,聽名字咱們就知道,構造代碼塊不是優先於構造函數執行,而是依託於構造函數,也就是說,若是你不實例化對象,構造代碼塊是不會執行的。怎麼理解呢?咱們看看下面這段代碼:

public class CodeBlock {
	{
		System.out.println("構造代碼塊");
	}
	
	public CodeBlock(){
		System.out.println("無參構造函數");
	}
	public CodeBlock(String str){
		System.out.println("有參構造函數");
	}
}

  咱們反編譯生成的class文件:

  

  若是存在多個構造代碼塊,則執行順序按照書寫順序依次執行。

  ③、構造代碼塊的做用

   和構造函數的做用相似,都能對對象進行初始化,而且只要建立一個對象,構造代碼塊都會執行一次。可是反過來,構造函數則不必定每一個對象創建時都執行(多個構造函數狀況下,創建對象時傳入的參數不一樣則初始化使用對應的構造函數)。

  利用每次建立對象的時候都會提早調用一次構造代碼塊特性,咱們能夠作諸如統計建立對象的次數等功能。

三、構造函數 

  1.構造函數的命名必須和類名徹底相同。在java中普通函數能夠和構造函數同名,可是必須帶有返回值;

  2.構造函數的功能主要用於在類的對象建立時定義初始化的狀態。它沒有返回值,也不能用void來修飾。這就保證了它不只什麼也不用自動返回,並且根本不能有任何選擇。而其餘方法都有返回值,即便是void返回值。儘管方法體自己不會自動返回什麼,但仍然可讓它返回一些東西,而這些東西多是不安全的;

  3.構造函數不能被直接調用,必須經過new運算符在建立對象時纔會自動調用;而通常的方法是在程序執行到它的時候被調用的;

  4.當定義一個類的時候,一般狀況下都會顯示該類的構造函數,並在函數中指定初始化的工做也可省略,不過Java編譯器會提供一個默認的構造函數.此默認構造函數是不帶參數的。而通常的方法不存在這一特色;

四、普通代碼塊

  普通代碼塊和構造代碼塊的區別是,構造代碼塊是在類中定義的,而普通代碼塊是在方法體中定義的。且普通代碼塊的執行順序和書寫順序一致。

public void sayHello(){
	{
		System.out.println("普通代碼塊");
	}
}

五、執行順序

  •  靜態代碼塊>構造代碼塊>構造函數>普通代碼塊 
public class CodeBlock {
	static{
		System.out.println("靜態代碼塊");
	}
	{
		System.out.println("構造代碼塊");
	}
	public CodeBlock(){
		System.out.println("無參構造函數");
	}
	
	public void sayHello(){
		{
			System.out.println("普通代碼塊");
		}
	}
	
	public static void main(String[] args) {
		System.out.println("執行了main方法");
		
		new CodeBlock().sayHello();;
		System.out.println("---------------");
		new CodeBlock().sayHello();;
	}
}

  反編譯生成的class文件:

  

 

  執行結果:

   

  咱們建立了兩個匿名對象,可是靜態代碼塊只是調用了一次。

六、父類和子類執行順序

  對象的初始化順序:

  首先執行父類靜態的內容,父類靜態的內容執行完畢後,接着去執行子類的靜態的內容,當子類的靜態內容執行完畢以後,再去看父類有沒有構造代碼塊,若是有就執行父類的構造代碼塊,父類的構造代碼塊執行完畢,接着執行父類的構造方法;父類的構造方法執行完畢以後,它接着去看子類有沒有構造代碼塊,若是有就執行子類的構造代碼塊。子類的構造代碼塊執行完畢再去執行子類的構造方法。

  總之一句話,靜態代碼塊內容先執行,接着執行父類構造代碼塊和構造方法,而後執行子類構造代碼塊和構造方法。

  父類:SuperClass.java

package com.ys.extend;

public class SuperClass {
	static{
		System.out.println("父類靜態代碼塊");
	}
	{
		System.out.println("父類構造代碼塊");
	}
	public SuperClass(){
		System.out.println("父類構造函數");
	}
}

  子類:SubClass.java

package com.ys.extend;

public class SubClass extends SuperClass{
	static{
		System.out.println("子類靜態代碼塊");
	}
	
	{
		System.out.println("子類構造代碼塊");
	}
	
	public SubClass(){
		System.out.println("子類構造函數");
	}
	
}

  測試:

public static void main(String[] args) {
	SubClass sb = new SubClass();
	System.out.println("------------");
	SubClass sb1 = new SubClass();
}

  打印結果:

  

相關文章
相關標籤/搜索