Java背後的秘密之Java的類裝載器 – JAVA編程語言程序開發技術文章

Java語言是一種先天具備動態性的語言,之所以具備動態性正是因為Java類裝載器的存在。這會給我們開發帶來革命性的變革,因為我們有可能開發出有彈性、易擴展的程序。從而大大增強我們程序的可維護性。按載入條件分為預先載入與按需載入。
1.通常基礎類庫需要預先載入。(常駐內存)
2.自定義類庫需要按需載入。(使用時載入,使用完畢時由垃圾收集器負責釋放)

類裝載器運行模式分為兩種,如下圖:

 

1.使用new關鍵字來隱式加載,首先來看一個例子:直接上代碼,很簡單的三個類。
        [java]
public class A { 
    public void print() { 
        System.out.println("Using class A"); 
    } 

public class A {
 public void print() {
  System.out.println("Using class A");
 }
}[java] view plaincopyprint?public class B { 
    public void print() { 
        System.out.println("Using class B"); 
    } 

public class B {
 public void print() {
  System.out.println("Using class B");
 }
}[java] view plaincopyprint?public class Main { 
    public static void main(String[] args) { 
        A a = new A(); 
        a.print(); 
        B b = new B(); 
        b.print(); 
    } 

public class Main {
 public static void main(String[] args) {
  A a = new A();
  a.print();
  B b = new B();
  b.print();
 }
}運行結果如下:


但是我們如果需要看類加載的詳細內容,我們就要用到這條命令:java -verbose:class Main


看看上圖是不是首先載入的Java的基礎類庫,看最後幾行,首先加載Main,接下來實例化A類的時候會加載A,調用a.print()的時候打印瞭Using class A,然後加載B類,執行B中的方法。

2.使用Class.forName()方法載入類,這個做過J2EE開發的應該知道,在數據庫連接加載驅動的時候都可以這麼加載。還是看一個簡單的例子:
[java]
public interface Office { 
    void start(); 

public interface Office {
 void start();
}[java] view plaincopyprint?public class Word implements Office { 
    public void start() { 
        System.out.println("Word start"); 
    } 

public class Word implements Office {
 public void start() {
  System.out.println("Word start");
 }
}[java] view plaincopyprint?public class Excel implements Office { 
    public void start() { 
        System.out.println("Excel start"); 
    } 

public class Excel implements Office {
 public void start() {
  System.out.println("Excel start");
 }
}[java] view plaincopyprint?public class Main { 
    public static void main(String[] args) throws Exception{ 
        Class c = Class.forName(args[0]); 
        Object o = c.newInstance(); 
        Office office = (Office) o; 
        office.start(); 
    } 

public class Main {
 public static void main(String[] args) throws Exception{
  Class c = Class.forName(args[0]);
  Object o = c.newInstance();
  Office office = (Office) o;
  office.start();
 }
}繼續看一下加載的詳細內容:


詳細觀察一下最後幾行載入的順序,看看是否跟我們程序執行的是一樣的呢?
此處有一個結論:Java類裝載器會按照繼承體系從上至下的依次載入類,直到所有的祖先類都載入(上例中是接口),才輪到自己;相反,在Java類對象實例被收集釋放時,順序與載入相反。由此,我們也能看出,Java類的繼承體系不宜過長,因為那樣會使類的載入與釋放的性能受到影響。

3.直接使用類裝載器ClassLoader,例子是上一個例子的改版,隻是修改瞭Main.java,其他三個類不變。
[java]
public class Main { 
    public static void main(String[] args) throws Exception { 
        System.out.println("begin load"); 
        // Main main = new Main();  
        // ClassLoader loader = main.getClass().getClassLoader();  
        ClassLoader loader = Main.class.getClassLoader(); 
        Class c = loader.loadClass(args[0]); 
        System.out.println("begin init"); 
        Object o = c.newInstance(); 
        Office office = (Office) o; 
        office.start(); 
    } 

public class Main {
 public static void main(String[] args) throws Exception {
  System.out.println("begin load");
  // Main main = new Main();
  // ClassLoader loader = main.getClass().getClassLoader();
  ClassLoader loader = Main.class.getClassLoader();
  Class c = loader.loadClass(args[0]);
  System.out.println("begin init");
  Object o = c.newInstance();
  Office office = (Office) o;
  office.start();
 }
}首先獲得ClassLoader的實例,有兩種方法,上面註釋的為一種,放開的為另一種。然後調用loadClass()方法。運行一下,看下效果:

 

怎麼樣,Java語言夠動態吧。

 

發佈留言