小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

java類裝載器

 軟件團隊頭目 2008-03-16

一 . 面向接口編程. 不要面向類編程.

二 . 關于異常:
如果父類的一個方法拋出了異常,子類在重寫此方法時可以不拋出異常而直接處理,也可以拋出父類異常的子異

常,但是不能拋出比父類方法拋出的異常級別更高的異常.

三 . Java的類裝載器(Class Loader)和命名空間(NameSpace)

1.摘要:
Java的類裝載器是Java動態(tài)性的核心,本文將向大家簡要介紹Java的類裝載器,及相關的雙親委派模型,命名

空間,運行時包等概念,同時討論一些在學習中容易混淆的問題。

2.類裝載器的功能及分類:
顧名思義,類裝載器是用來把類(class)裝載進JVM的。JVM規(guī)范定義了兩種類型的類裝載器:啟動lei裝載器

(bootstrap)和用戶自定義裝載器(user-defined class loader)。

bootstrap是JVM自帶的類裝載器,用來裝載核心類庫,如java.lang.*等。由例1可以看出,java.lang.Object

是由bootstrap裝載的。

Java提供了抽象類ClassLoader,所有用戶自定義類裝載器都實例化自ClassLoader的子類。
System Class Loader是一個特殊的用戶自定義類裝載器,由JVM的實現(xiàn)者提供,在編程者不特別指定裝載器的

情況下默認裝載用戶類。系統(tǒng)類裝載器可以通過ClassLoader.getSystemClassLoader() 方法得到。

例1,測試你所使用的JVM的ClassLoader
/*LoaderSample1.java*/
public class LoaderSample1
{
 public static void main(String[] args)
 {
  Class c;
  ClassLoader cl;
  
  cl = ClassLoader.getSystemClassLoader();
  System.out.println(cl);
  
  while (cl != null)
  {
   cl = cl.getParent();
   System.out.println(cl);  
  }

  try
  {
   c = Class.forName(“java.lang.Object”);
   cl = c.getClassLoader();
   System.out.println(“java.lang.Object’s loader is ” + cl);

   c = Class.forName(“LoaderSample1”);
   cl = c.getClassLoader();
   System.out.println(“LoaderSample1’s loader is ” + cl);
  }
  catch (Exception e)
  {
   e.printStackTrace();
  }
 }
}

在我的機器上(Sun Java 1.4.2)的運行結果
sun.misc.Launcher$AppClassLoader@1a0c10f
sun.misc.Launcher$ExtClassLoader@e2eec8
null
java.lang.Object‘s loader is null
LoaderSample1‘s loader is sun.misc.Launcher$AppClassLoader@1a0c10f

第一行表示,系統(tǒng)類裝載器實例化自類sun.misc.Launcher$AppClassLoader
第二行表示,系統(tǒng)類裝載器的parent實例化自類sun.misc.Launcher$ExtClassLoader
第三行表示,系統(tǒng)類裝載器parent的parent為bootstrap
第四行表示,核心類java.lang.Object是由bootstrap裝載的
第五行表示,用戶類LoaderSample1是由系統(tǒng)類裝載器裝載的


3.雙親委派模型:
從1.2版本開始,Java引入了雙親委托模型,從而更好的保證Java平臺的安全。在此模型下,當一個裝載器被請

求裝載某個類時,它首先委托自己的parent去裝載,若parent能裝載,則返回這個類所對應的Class對象,若

parent不能裝載,則由parent的請求者去裝載。

如圖1所示,loader2的parent為loader1,loader1的parent為system class loader。假設loader2被要求裝載

類MyClass,在雙親委派模型下,loader2首先請求loader1代為裝載,loader1再請求系統(tǒng)類裝載器去裝載

MyClass。若系統(tǒng)裝載器能成功裝載,則將MyClass所對應的Class對象的reference返回給loader1,loader1再

將reference返回給loader2,從而成功將類MyClass裝載進虛擬機。若系統(tǒng)類裝載器不能裝載MyClass,loader1

會嘗試裝載MyClass,若loader1也不能成功裝載,loader2會嘗試裝載。若所有的parent及l(fā)oader2本身都不能

裝載,則裝載失敗。

若有一個能成功裝載,實際裝載的類裝載器被稱為定義類裝載器,所有能成功返回Class對象的裝載器(包括定

義類裝載器)被稱為初始類裝載器。如圖1所示,假設loader1實際裝載了MyClass,則loader1為MyClass的定義

類裝載器,loader2和loader1為MyClass的初始類裝載器。


 

需要指出的是,Class Loader是對象,它的父子關系和類的父子關系沒有任何關系。一對父子loader可能實例

化自同一個Class,也可能不是,甚至父loader實例化自子類,子loader實例化自父類。假設MyClassLoader繼

承自ParentClassLoader,我們可以有如下父子loader:
ClassLoader loader1 = new MyClassLoader();
ClassLoader loader2 = new ParentClassLoader(loader1); //參數(shù) loader1為parent

那么雙親委托模型為什么更安全了?因為在此模型下用戶自定義的類裝載器不可能裝載應該由父親裝載器裝載

的可靠類,從而防止不可靠甚至惡意的代碼代替由父親裝載器裝載的可靠代碼。實際上,類裝載器的編寫者可

以自由選擇不用把請求委托給parent,但正如上所說,會帶來安全的問題?!驹恚合拗屏俗远x裝載器的權利】


4.命名空間及其作用:
每個類裝載器有自己的命名空間,命名空間由所有以此裝載器為創(chuàng)始類裝載器的類組成。不同命名空間的兩個

類是不可見的,但只要得到類所對應的Class對象的reference,還是可以訪問另一命名空間的類。
例2演示了一個命名空間的類如何使用另一命名空間的類。在例子中,LoaderSample2由系統(tǒng)類裝載器裝載,

LoaderSample3由自定義的裝載器loader負責裝載,兩個類不在同一命名空間,但LoaderSample2得到了

LoaderSample3所對應的Class對象的reference,所以它可以訪問LoaderSampl3中公共的成員(如age)。

例2不同命名空間的類的訪問
/*LoaderSample2.java*/
import java.net.*;
import java.lang.reflect.*;

public class LoaderSample2
{
 public static void main(String[] args)
 {
  try
  {
   String path = System.getProperty("user.dir");
   
   URL[] us = {new URL("file://" + path + "/sub/")};
   
   ClassLoader loader = new URLClassLoader(us);  
   
   Class c = loader.loadClass("LoaderSample3");
   Object o = c.newInstance();
   
   Field f = c.getField("age");
  
   int age = f.getInt(o);
   System.out.println("age is " + age);
      
  }
  catch (Exception e)
  {
   e.printStackTrace(); 
  }  
 }
 
}


/*sub/Loadersample3.java*/
public class LoaderSample3
{
 static
 {
  System.out.println("LoaderSample3 loaded"); 
 }
 
 public int age = 30; 
}

編譯:javac LoaderSample2.java; javac sub/LoaderSample3.java
運行:java LoaderSample2
LoaderSample3 loaded
age is 30

從運行結果中可以看出,在類LoaderSample2中可以創(chuàng)建處于另一命名空間的類LoaderSample3中的對象并可以

訪問其公共成員age。

5.運行時包(runtime package):
 
由同一類裝載器定義裝載的屬于相同包的類組成了運行時包,決定兩個類是不是屬于同一個運行時包,不僅要

看它們的包名是否相同,還要看的定義類裝載器是否相同。只有屬于同一運行時包的類才能互相訪問包可見的

類和成員。這樣的限制避免了用戶自己的代碼冒充核心類庫的類訪問核心類庫包可見成員的情況。假設用戶自

己定義了一個類java.lang.Yes,并用用戶自定義的類裝載器裝載,由于java.lang.Yes和核心類庫java.lang.*

由不同的裝載器裝載,它們屬于不同的運行時包,所以java.lang.Yes不能訪問核心類庫java.lang中類的包可

見的成員。


6.總結:
在簡單討論了類裝載器,雙親委派模型,命名空間,運行時包后,相信大家已經(jīng)對它們的作用有了一定的了解

。命名空間并沒有完全禁止屬于不同空間的類的互相訪問,雙親委托模型加強了Java的安全,運行時包增加了

對包可見成員的保護。


7.參考資料:
 <<Inside The Java Virtual Machine>> by Bill Venners
 <<The Java Virtual Machine Specification>> by Sun

四 . 再談類裝載器

 作為程序的一部分,每個類都有一個class對象.換言之,每當你編寫并且編譯了一個新類,就會產(chǎn)生一個

Class對象(更恰當?shù)恼f,是被保存在一個同名的.class文件中).在運行期,一旦我們想生成這個類的一個對象,運

行這個程序的java虛擬機(JVM)首先檢查這個類的Class對象是否已經(jīng)加載,如果尚未加載,JVM就會根據(jù)類名查找

.class文件,并將期載入,所以Java程序并不是一開始執(zhí)行就被完全加載的,這一點與許多傳統(tǒng)語言不同,一旦某

個類的Class對象被載入內(nèi)存,它就被用來創(chuàng)建這個類的所有對象,請看下面的例子[需要時才加載,不需要則不加載]:

class Candy
{
 static
 {
  System.out.println ("Loading Candy");
 }
}

class Gum
{
 static
 {
  System.out.println ("Loading Gum");
 }
}

class Cookie
{
 static
 {
  System.out.println ("Loading Cookie");
 }
}

public class ClassTest
{
    public static void main(String[] args)
    {
     System.out.println ("inside main");
     new Candy();
     System.out.println ("After creating Candy");
     try
     {
      Class.forName("Gum");
     }
     catch(ClassNotFoundException e)
     {
      System.out.println ("Couldn‘t find Gum");
     }
     
     System.out.println ("After Class.forName(\"Gum\")");
     new Cookie();
     System.out.println ("After creating Cookie");
    }
}

打印結果如下:
inside main
Loading Candy
After creating Candy
Couldn‘t find Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie

這里的每個類Candy,Gum,Cookie中,都有一個static語句,在類第一次被加載時執(zhí)行,這時會有相應結果打印出來

告訴我們這個類什么時候被加載了.在main()中,創(chuàng)建對象的代碼被置于打印語句之間,以幫助我們判斷加載的時

間點.你可以從輸出中看出,Class對象僅在需要的時候才被加載,static語句塊是在類加載時被執(zhí)行的.看這行

:Class.forName("Gum"),這是Class類(所有Class對象都屬于這個類型)的一個static成員,Class對象和其他對

象一樣,我們可以獲取并操作它的引用(這就是類加載器的工作),forName()時取得Class對象的引用一個方法,它

時用一個包含目標類的文件名的String作為輸入?yún)?shù),返回一個Class對象的引用,上面的代碼忽略了返回值,對

forName()的調用是為了它產(chǎn)生的"副作用":如果類Gum還沒有被加載就加載它.在加載的過程中,Gum的static語

句被執(zhí)行.在前面的例子中,如果Class.forName()找不到你要加載的類.它會拋出異常ClassNotFoundException
 

加載類的時機【也就是加載class對象的時機】靜態(tài)成員調用,class.forName方法調用,new方法(等同于一個靜態(tài)方法)調用

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1118975


[收藏到我的網(wǎng)摘]   [發(fā)送Trackback]  senton發(fā)表于 2006年08月25日 18:36:00

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多