Jvm的類加載機制中,我們說過有一個階段是初始化(Initialization),這個階段的應用類加載器(Application or App ClasLoader)會收集所有的靜態代碼塊並執行,而且只執行一次。所以這裏有一個誤區,很多人認爲Java靜態代碼塊是在類被加載時自動執行,這是錯誤的,需要注意的是,靜態代碼塊只在類加載的初始化階段執行。
類被加載了,不一定會執行靜態代碼塊,詳情看代碼:
public class ClassLoaderTest {
public static void main(String[] args) {
System.out.println("main()函數===" + LoaderTest.class);
}
}
class LoaderTest {
static {
System.out.println(">>>靜態代碼塊執行了沒有<<<");
}
}
那麼,靜態代碼塊是如何執行的呢?
靜態代碼塊會在類加載的初始化階段執行,而且只執行一次。
如果繼承父類,則會先執行父類中的靜態代碼塊,然後再執行子類中的靜態代碼塊;
實例對象時,會先執行父類中的非靜態代碼塊,父類中的構造方法,然後再執行子類中的非靜態代碼塊,子類中的構造方法!
public class Father {
static {
System.out.println(">>>Father靜態代碼塊<<<");
}
{
System.out.println(">>>Father非靜態代碼塊<<<");
}
public Father() {
System.out.println(">>>Father無參構造<<<");
}
}
public class TestSon extends Father {
static {
System.out.println(">>>TestSon靜態代碼塊<<<");
}
{
System.out.println(">>>TestSon非靜態代碼塊<<<");
}
public TestSon() {
System.out.println(">>>TestSon無參構造<<<");
}
public static void main(String[] args) {
System.out.println("TestSon的main()函數");
TestSon son1 = new TestSon();
System.out.println("--------------------");
TestSon son2 = new TestSon();
}
}
靜態代碼塊一般用在什麼地方?
1)在項目啓動時,加載某個類,對數據進行數據化(如初始化基礎數據或數據庫連接池)。
// 輸出服務器編碼
static {
Charset defaultCharset = Charset.defaultCharset();
String name = defaultCharset.name();
System.out.println("\n"+"\t"+"當前服務器採用的字符集是:" + name);
}
2)工具類中使用static靜態代碼塊進行初始化,當第一次訪問工具類時,就會先進行初始化(只會執行一次),保存到靜態全局屬性中,當其他類再次訪問時,將直接使用初始化數據(如獲取一個單例sessionFactory)。
public class HibernateUtil {
private static final SessionFactory sessionFactory;
private static final ThreadLocal session = new ThreadLocal();
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
}