1. 程式人生 > >Java中類及方法的載入順序

Java中類及方法的載入順序

1. 虛擬機器在首次載入Java類時,會對靜態程式碼塊、靜態成員變數、靜態方法進行一次初始化(靜態間按順序執行)。

2. 只有在呼叫new方法時才會建立類的例項。

3. 類例項建立過程:父子繼承關係,先父類再子類。父類的靜態->子類的靜態->父類的初始化塊->父類的構造方法->子類的初始化塊->子類的構造方法

4. 類例項銷燬時候:首先銷燬子類部分,再銷燬父類部分。

例:

package exercise;

public class Main_exer {
	void myMethod(Object o){
		System.out.println("object");
	}
	void myMethod(String s){
		System.out.println("string");
	}
	public static void main(String[] args) {
		Main_exer ma = new Main_exer();
		ma.myMethod(null);
	}
}
輸出結果:

string

例:

package classLoader_demo;

public class Parent
{
	//靜態成員變數
    public static int t = parentStaticMethod2();
    //程式碼塊
    {
        System.out.println("父類非靜態初始化塊");
    }
    static
    {
        System.out.println("父類靜態初始化塊");
    }
    //構造方法
    public Parent()
    {
        System.out.println("父類的構造方法");
    }
    //父類靜態方法
    public static int parentStaticMethod()
    {
        System.out.println("父類的靜態方法");
        return 10;
    }
    public static int parentStaticMethod2()
    {
        System.out.println("父類的靜態方法2");
        return 9;
    }
  
    @Override
    protected void finalize() throws Throwable
    {
        // TODO Auto-generated method stub
        super.finalize();
        System.out.println("銷燬父類");
    }
 
}
package classLoader_demo;

public class Child extends Parent
{
	//程式碼塊
    {
        System.out.println("子類非靜態初始化塊");
    }
    static
    {
        System.out.println("子類靜態初始化塊");
    }
    //構造方法
    public Child()
    {
        System.out.println("子類的構造方法");
    }
    //靜態方法
    public static int childStaticMethod()
    {
        System.out.println("子類的靜態方法");
        return 1000;
    }
    
    @Override
    protected void finalize() throws Throwable
    {
        // TODO Auto-generated method stub
        super.finalize();
        System.out.println("銷燬子類");
    }
}
當main中語句為
Parent.parentStaticMethod();
輸出結果:

父類的靜態方法2
父類靜態初始化塊
父類的靜態方法


當main中語句為

Child child = new Child();
		try {
			child.finalize();
		} catch (Throwable e) {
			e.printStackTrace();
		}
輸出結果:

父類的靜態方法2
父類靜態初始化塊
子類靜態初始化塊
父類非靜態初始化塊
父類的構造方法
子類非靜態初始化塊
子類的構造方法
銷燬父類
銷燬子類
此處輸出結果中的先輸出“銷燬父類”,再輸出“銷燬子類”,與前面提到的先銷燬子類再銷燬父類並不矛盾。仍然為先呼叫子類的銷燬方法,再呼叫父類的銷燬方法,只是super關鍵字的原因。

備註:

1. Java中類方法和例項方法的區別

類體中的方法分為例項方法和類方法兩種,用static修飾的是類方法。

當類的位元組碼檔案被載入到記憶體時,類的例項方法不會被分配入口地址,當該類建立物件後,類中的例項方法才分配入口地址,從而例項方法可以被類建立的任何物件呼叫執行。需要注意的是,當我們建立第一個物件時,類中的例項方法就分配了入口地址,當再建立物件時,不再分配入口地址,也就是說,方法的入口地址被所有的物件共享,當所有的物件都不存在時,方法的入口地址才被取消。

對於類中的類方法,在該類被載入到記憶體時,就分配了相應的入口地址。從而類方法不僅可以被類建立的任何物件呼叫執行,也可以直接通過類名呼叫。類方法的入口地址直到程式退出才被取消。

類方法在類的位元組碼載入到記憶體時就分配了入口地址,因此,Java語言允許通過類名直接呼叫類方法,而例項方法不能通過類名呼叫。在講述類的時候我們強調過,在Java語言中,類中的類方法不可以操作例項變數,也不可以呼叫例項方法,這是因為在類建立物件之前,例項成員變數還沒有分配記憶體,而且例項方法也沒有入口地址。


2.  Java程式執行時需載入的幾個類

例:

package classLoader_demo;
import java.net.URL;
public class Main_cld {
	public static void main(String[] args) {
		URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();  
        for(int i=0; i < urls.length; i++){  
            System.out.println(urls[i].toExternalForm());  
        }         
        System.out.println("----- 分隔符------");        
        System.out.println(System.getProperty("sun.boot.class.path")); 
	}
}
輸出結果:

file:/C:/Program%20Files/Java/jre1.8.0_66/lib/resources.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/lib/rt.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/lib/jsse.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/lib/jce.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/lib/charsets.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/lib/jfr.jar
file:/C:/Program%20Files/Java/jre1.8.0_66/classes
----- 分隔符------
C:\Program Files\Java\jre1.8.0_66\lib\resources.jar;C:\Program Files\Java\jre1.8.0_66\lib\rt.jar;C:\Program Files\Java\jre1.8.0_66\lib\sunrsasign.jar;C:\Program Files\Java\jre1.8.0_66\lib\jsse.jar;C:\Program Files\Java\jre1.8.0_66\lib\jce.jar;C:\Program Files\Java\jre1.8.0_66\lib\charsets.jar;C:\Program Files\Java\jre1.8.0_66\lib\jfr.jar;C:\Program Files\Java\jre1.8.0_66\classes