1. 程式人生 > >Java的靜態程式碼塊是否會在類被載入時自動執行?

Java的靜態程式碼塊是否會在類被載入時自動執行?

JAVA靜態程式碼塊會在類被載入時自動執行?

一、先看Java靜態方法,靜態變數

靜態程式碼塊

在類中,可以將某一塊程式碼宣告為靜態的,這樣的程式塊叫靜態初始化段。靜態程式碼塊的一般形式如下:

static {
    語句序列
}
public class staticBlock{

        //定義一個普通的main()方法

        public static void main(String args[]){

        System.out.println("This is main method."); 

       }

      //定義一個靜態程式碼塊
static{ System.out.println("This is static block."); int stVar = 0; //這是一個區域性變數,只在本塊內有效 } }

編譯通過後,用java命令載入本程式,會得到如下輸出:

This is static block.

This is main method.

從以上輸出結果中可以看出,靜態程式碼塊甚至在main方法之前就被執行。在main()方法中可以完成的任務在靜態程式碼塊中都可以完成。但是二者在執行上仍然有一些區別,main方法是整個程式啟動的入口,而靜態程式碼塊是存在於某個類中的一個過程。

那是不是隻要類被載入了就一定會執行靜態程式碼塊?

二、再看JVM類載入的過程

  1. 裝載
  2. 連線
  3. 初始化

    其中裝載階段又三個基本動作組成:

  1.     通過型別的完全限定名,產生一個代表該型別的二進位制資料流
  2.     解析這個二進位制資料流為方法區內的內部資料結
  3.     構建立一個表示該型別的java.lang.Class類的例項

    另外如果一個類裝載器在預先裝載的時遇到缺失或錯誤的class檔案,它需要等到程式首次主動使用該類時才報告錯誤。

    連線階段又分為三部分:

  1. 驗證,確認型別符合Java語言的語義,檢查各個類之間的二進位制相容性(比如final的類不用擁有子類等),另外還需要進行符號引用的驗證。
  2. 準備,Java虛擬機器為類變數分配記憶體,設定預設初始值。
  3. 解析(可選的) ,在型別的常量池中尋找類,介面,欄位和方法的符號引用,把這些符號引用替換成直接引用的過程。

 當一個類被主動使用時,Java虛擬就會對其初始化,如下五種情況為主動使用:

  1. 遇到new, getstatic, putstatic 或者 invokestatic 4條位元組碼指令時,如果類沒有進行過初始化,則需要先進行初始化。這些場景包括:使用new關鍵字例項化物件,讀取或者設定一個類的靜態欄位以及呼叫一個類的靜態方法的時候。

  2. 使用java.lang.reflect包的方法進行反射呼叫的時候,如果類沒有初始化,需要進行初始化。

  3. 當初始化一個類的時候發現其父類還沒有初始化,需要對父類進行初始化。

  4. JVM啟動時,使用者指定的包含main方法的那個類,需要首先進行初始化。

  5. JDK1.7中動態語言的支援,解析java.lang.invoke.MethodHandle的結果為REF_getStatic, REF_putStatic, REF_invokeStatic方法的控制代碼時,對應的類沒有初始化的時候。

實際上,static塊的執行發生在“初始化”的階段。初始化階段,jvm主要完成對靜態變數的初始化,靜態塊執行等工作。



下面我們看看執行static塊的幾種情況:

1、第一次new A()的過程會列印"";因為這個過程包括了初始化

2、第一次Class.forName("A")的過程會列印"";因為這個過程相當於Class.forName("A",true,this.getClass().getClassLoader());

3、第一次Class.forName("A",false,this.getClass().getClassLoader())的過程則不會列印""。因為false指明瞭裝載類的過程中,不進行初始化。不初始化則不會執行static塊。

再看這個例子

class MyClass1 {
    static {//靜態塊
        System.out.println("static block ");
    }
}
public class Main {

    Class[] classArray = {
            MyClass1.class//這樣引用該類,必然需要將該類載入到虛擬機器中,(反射機制)
    };
    public static void main(String[] args){
        System.out.println("hello word");
    }

}

結果:

hello world

所以結論是不初始化則不會執行static塊。

參考:《深入理解java虛擬機器》

相關推薦

Java靜態程式碼是否載入自動執行

JAVA靜態程式碼塊會在類被載入時自動執行? 一、先看Java靜態方法,靜態變數 靜態程式碼塊 在類中,可以將某一塊程式碼宣告為靜態的,這樣的程式塊叫靜態初始化段。靜態程式碼塊的一般形式如下: static { 語句序列 } public class staticBlock{

static{}(即static),載入的時候執行且僅執行一次,一般用來初始化靜態變數和呼叫靜態方法

這裡是一個工具類,因為連線配置資訊只需要執行一次就行所以採用static塊 static塊會最先執行 package com.my.jedis; import java.io.IOException; import java.io.InputStream; import

Java靜態程式碼靜態方法的區別/載入順序

 (一)java 靜態程式碼塊 靜態方法區別  一般情況下,如果有些程式碼必須在專案啟動的時候就執行的時候,需要使用靜態程式碼塊,這種程式碼是主動執行的;需要在專案啟動的時候就初始化,在不建立物件的情況下,其他程式來呼叫的時候,需要使用靜態方法,這種程式碼是被動執行的.

java靜態程式碼構造程式碼建構函式

01.靜態程式碼塊     靜態程式碼塊使用static關鍵字進行修飾,執行在類初始化階段,靜態程式碼塊只執行一次,主要用於類變數的初始化和賦值。靜態程式碼塊的金典用法是讀取配置檔案,程式碼如下:     

java 靜態程式碼和spring @value等註解注入順序

今天在引用yml配置檔案的時候,因為用到了繼承的靜態程式碼塊。類與類有繼承關係的靜態程式碼塊是先執行父類靜態程式碼塊再執行子類靜態程式碼塊,這個問題不用說。 今天探索的是與spring相關的執行順序 我在專案啟動的時候需要去載入部分配置檔案,這些配置檔案的資訊在子類的靜態程式碼塊需要使用

JAVA靜態程式碼

一 般情況下,如果有些程式碼必須在專案啟動的時候就執行的時候,需要使用靜態程式碼塊,這種程式碼是主動執行的;需要在專案啟動的時候就初始化,在不建立物件的情 況下,其他程式來呼叫的時候,需要使用靜態方法,這種程式碼是被動執行的. 靜態方法在類載入的時候 就已經載入 可以用類名直

Java靜態程式碼靜態方法

1 靜態程式碼塊:有些程式碼必須在專案啟動的時候就執行,這種程式碼是主動執行的(當類被載入時,靜態程式碼塊被執行,且只被執行一次,靜態塊常用來執行類屬性的初始化) 2 靜態方法:需要在專案啟動的時候就初始化,在不建立物件的情況下,這種程式碼是被動執行的(靜態方法在類載入的時候就已經載入 可以用類

A繼承父B, A a = new A(); 則父B建構函式、父B靜態程式碼、父B非靜態程式碼、子A建構函式、子A靜態程式碼、子A非靜態程式碼 執行的先後順序是?

(1)子類A繼承父類B, A a = new A(); 則: 父類B靜態程式碼塊->子類A靜態程式碼塊->父類B非靜態程式碼塊->父類B建構函式->子類A非靜態程式碼塊->子類A建構函式 (2)若子類建構函式中顯式的呼叫了父類

JAVA靜態程式碼的作用

一 般情況下,如果有些程式碼必須在專案啟動的時候就執行的時候,需要使用靜態程式碼塊,這種程式碼是主動執行的;需要在專案啟動的時候就初始化,在不建立物件的情 況下,其他程式來呼叫的時候,需要使用靜態方法,這種程式碼是被動執行的. 靜態方法在類載入的時候 就已經載入 可以用類名

Java靜態程式碼靜態方法的區別

(一)java 靜態程式碼塊 靜態方法區別 一般情況下,如果有些程式碼必須在專案啟動的時候就執行的時候,需要使用靜態程式碼塊,這種程式碼是主動執行的;需要在專案啟動的時候就初始化,在不建立物件的情況下,其他程式來呼叫的時候,需要使用靜態方法,這種程式碼是被動執行的. 靜態

Java靜態程式碼程式碼及建構函式執行順序

根據以下程式進行分析 定義一個父類 package sas.LearnJava; public class ExcuteOrderTest { { System.out.println("我是在父類開始的普通程式碼塊!"); } public ExcuteOrder

大括號{}的意義與靜態程式碼與建構函式的載入關係

import java.util.HashMap;import java.util.HashSet;import java.util.Hashtable;import java.util.Iterator;import java.util.Map;import java.u

當一個載入成員的初始化順序

        當一個類因為例項化被載入時,其成員的初始化順序是什麼呢?          先看下面這段程式碼: class Fsx{ public Fsx(){ System.out.println("Fsx無參構造器初始化了"); } public Fsx(

java機制:載入詳解(靜態,靜態變數,靜態方法,靜態程式碼,構造程式碼,成員變數,成員方法,父...)

       “程式碼編譯的結果從本地機器碼轉變為位元組碼,是儲存格式發展的一小步,卻是變成語言發展的一大步”,這句話出自《深入理解JAVA虛擬機器》 一.原始碼編譯      &n

Java與父靜態程式碼、非靜態程式碼、建構函式的執行順序一覽表

子類Child繼承父類Parent Child child=new Child(); 執行順序如下: ①父類靜態程式碼塊>>②子類靜態程式碼塊>>③父類非靜態程式碼塊>>④父類建構函式>>⑤子類非靜態程式碼塊>>⑥子類

Java基礎——靜態程式碼、構造程式碼、建構函式以及Java初始化順序

閱讀目錄 建構函式 構造程式碼塊 靜態程式碼塊 Java類初始化順序 靜態程式碼塊:用staitc宣告,jvm載入類時執行,僅執行一次 構造程式碼塊:類中直接用{}定義,每一次建立物件時執行。 執行順序優先順序:靜態塊,main(),構造塊,構造方法。

Java基礎---面向物件(面向物件,,物件,匿名物件,封裝,建構函式,構造程式碼,this,static,main,幫助文件,靜態程式碼,單例)

一. 面向物件概念: 面向物件其實是一種思考的思想,早期思想是面向過程。 面向過程注重的是過程,過程所涉及的行為,也就是功能。 【例項】:面向過程: 1. 把冰箱開啟 2. 把大象放入 3. 冰箱關起來      面向物件: 開啟冰箱,儲存,關閉都是對冰箱的操作,是冰箱的行為

Java載入過程&&靜態程式碼的初始化過程

問題的引入        還是老規矩,先說說自己遇到的問題。 最近看到了一個比較有意思的Java程式,初次看到這段程式執行的結果還是挺讓我意外的,話不多說先上程式,大家也可以揣摩一下(大神自行略過......) class Singleton{

Java靜態成員變數,靜態程式碼靜態內部類何時初始化?

關於這個問題,本文不扯理論,直接上程式碼,通過結果來驗證結論,廢話少說,測試程式碼如下: public class StaticTest { public static StaticMember staticMember = new Static

Java提高篇——靜態程式碼、構造程式碼、建構函式以及Java初始化順序

靜態程式碼塊:用staitc宣告,jvm載入類時執行,僅執行一次構造程式碼塊:類中直接用{}定義,每一次建立物件時執行。執行順序優先順序:靜態塊,main(),構造塊,構造方法。 建構函式 public HelloA(){//建構函式 } 關於建構函式,以下幾點