用户操作
[即时聊天] [发私信] [加为好友]
大龄青年ID:hahawen
115534次访问,排名751好友0人,关注者1
hahawen的文章
原创 46 篇
翻译 0 篇
转载 37 篇
评论 86 篇
大龄青年的公告
主人:大龄青年/hahawen
QQ:303015292
最近评论
皇冠世纪:皇冠世纪专业提供:

月子中心,酒店公寓住宿服务,香港胎儿性别测试,去香港生宝宝服务!
香港宝宝主网站:http://www.for-babys.cn
香港生宝宝论坛:http://bbs.for-babys.cn
皇冠世纪月子网站:http://www.for-mommy.cn
皇冠世纪香港生孩子网站: http://www.be……
kjb:[url=http://www.sirio.com.cn/]softgel[/url]
结肠炎治疗上我们也有非常强的历史
[url=http://www.google0808.cn/]GOOGLE左侧排名[/url]
专业的[url=http://www.zjcffy.com/]金华翻译公司[……
翻译:[url=http://www.goldenolive.net.cn]翻译公司[/url]
[url=http://www.goldenolive.net.cn]翻译[/url]
翻译公司
翻译
ff:水泵
磁力泵
多级泵
[url=http://www.hengxinbanjia.com]搬家公司[/url]
[url=http://www.hengxinbanjia.com/qqtl.htm]搬家公司[/url]
[url=http://www.hengxinbanjia.com]北京搬家公司[/url]
[url=http://www.hengxinbanjia.com/cc……
文章分类
收藏
相册
.net技术网站
devarticles
java技术网站
Hibernate中文网(RSS)
开源项目列表
php技术网站
pear官方网站
phpbuilder
phphub.com
php官方网站
StandardPHPLibrary
trip的blog,有好多的mail文章
zend官方网站
牛人的blog
其他的技术网站
xml资源下载
友情连接
王博的Blog(RSS)
娱乐网站
bt之家
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

转载 Java类别载入器收藏

新一篇: web开发的下一个学习方向:ajax | 旧一篇: 最近一段时间的java框架学习总结

1 Java的动态特性

  Java的动态特性有两种,一是隐式的;另一种是显示的。隱式的(implicit)方法就是當程式設計師用到new 這個Java 關鍵字時,會讓類別載入器依需求載入您所需要的類別,這種方式使用了隱式的(implicit)方法。顯式的方法,又分成兩種方式,一種是藉由java.lang.Class 裡的forName()方法,另一種則是藉由java.lang.ClassLoader 裡的loadClass()方法。您可以任意選用其中一種方法。

2 隐式的动态特性

  在执行java文件时,只有单独的变量声明是不会载入相应的类的,只有在用new生成实例时才载入

 如示例所示:

public class Main

public static void main(String args[])

{

A a1 = new A() ;

B b1 ;

}

A和B相同,如下:

public class A

{

    public void print(using A);

}

编译后,可用java verbose:class Main运行,察看输出结果。可以看到JVM只载入了A,而没有载入B.

另外,类的载入只在执行到new一个类时,才载入,如果没有执行到new语句,则不载入。

如://类Office

public class Office

{

   public static void main(String[] args)

   {

   Word myword=null;

  

   Excel myexcel=null;

  

   if (args[0].equals("Word"))

   {

             myword = new Word();

             myword.start();    

   }

         if (args[0].equals("Excel"))

         {

             myexcel = new Excel();

             myexcel.start();       

         } 

  

  

   }

}

//类Word和Excel基本相同,如下

public class Word

{

   public void start()

   {

   System.out.println("using word");

   }

}

dos命令提示符下,输入java verbose Office Excel可以看到JVM只载入Excel类,而不载入Word类。

 

 

 

3 显示的动态特性

3.1 java.lang.Class里的forName()方法

在上一个Office示例中,进行如下修改:

一 加入Assembly类

public interface Assembly

{

    public void start();

}

二 让Word和Excel类实现该接口

public class Word implements Assembly

{

   public void start()

   {

   System.out.println("using word");

   }

}

Office 类如下所示

public class Office

{

   public static void main(String[] args) throws Exception

   {

   java.lang.Class c = java.lang.Class.forName(args[0]);   

   Object o = c.newInstance();

   Assembly a = (Assembly)o;

   a.start();

   

   }

}

在命令提示符下输入java verbose Office Word 输出入下:

通过上图你可以看到,interface 如同class 一般,會由編譯器產生一個獨立的類別檔(.class),當類別載入器載入類別時,如果發現該類別繼承了其他類別,或是實作了其他介面,就會先載入代表該介面的類別檔,也會載入其父類別的類別檔,如果父類別也有其父類別,也會一併優先載入。換句話說,類別載入器會依繼承體系最上層的類別往下依序載入,直到所有的祖先類別都載入了,才輪到自己載入。

下面介绍一下 forName 函数, 如果您親自搜尋Java 2 SDK 說明檔內部對於Class 這個類別的說明,您可以發現其實有兩個forName()方法,一個是只有一個參數的(就是之前程式之中所使用的):

public static Class forName(String className)

另外一個是需要三個參數的:

public static Class forName(String name, boolean initialize,ClassLoader loader)

這兩個方法,最後都是連接到原生方法forName0(),其宣告如下:

private static native Class forName0(String name, boolean initialize, ClassLoader loader)

throws ClassNotFoundException;

只有一個參數的forName()方法,最後叫用的是:

forName0(className, true, ClassLoader.getCallerClassLoader());

而具有三個參數的forName()方法,最後叫用的是:

forName0(name, initialize, loader);

这里initialize参数指,在载入类之后是否进行初始化,对于该参数的作用可用如下示例察看:

类里的静态初始化块在类第一次被初始化时才被呼叫,且仅呼叫一次。在Word类里,加入静态初始化块

public class Word implements Assembly

{

   static

   {

   System.out.println("word static initialization "); 

   }

   

   public void start()

   {

   System.out.println("using word");

   }

}

将类Office作如下改变:

public class Office

{

   public static void main(String[] args) throws Exception

   {

   Office off= new Office();

   System.out.println("类别准备载入");

   java.lang.Class c = java.lang.Class.forName(args[0],true,off.getClass().getClassLoader());     

   System.out.println("类别准备实体化");

   Object o  = c.newInstance();

   Object o2 = c.newInstance();

   

   }

}

如果第二个参数为true 则输出入下

如果为false ,则输出入下:

可见,类里的静态初始化块仅在初始化时才执行,且不过初始化几次,它仅执行一次(这里有一个条件,那就是只有它是被同一个类别载入器多次载入时,才是这样,如果被不同的载入器,载入多次,则静态初始化块会执行多次)。

关于第三个参数请见下节介绍

3.2 直接使用类别载入器 java.lang.ClassLoader

Java 之中,每個類別最後的老祖宗都是Object,而Object 裡有一個名為getClass()的方法,就是用來取得某特定實體所屬類別的參考,這個參考,指向的是一個名為Class 類別(Class.class) 的實體,您無法自行產生一個Class 類別的實體,因為它的建構式被宣告成private,這個Class 類別的實體是在類別檔(.class)第一次載入記憶體時就建立的,往後您在程式中產生任何該類別的實體,這些實體的內部都會有一個欄位記錄著這個Class 類別的所在位置。

基本上,我們可以把每個Class 類別的實體,當作是某個類別在記憶體中的代理人。每次我們需要

查詢該類別的資料(如其中的fieldmethod )時,就可以請這個實體幫我們代勞。事實上,JavaReflection 機制,就大量地利用Class 類別。去深入Class 類別的原始碼,我們可以發現Class類別的定義中大多數的方法都是原生方法(native method)

Java 之中,每個類別都是由某個類別載入器(ClassLoader 的實體)來載入,因此,Class 類別的實體中,都會有欄位記錄著載入它的ClassLoader 的實體(注意:如果該欄位是null,並不代表它不是由類別載入器所載入,而是代表這個類別由靴帶式載入器(bootstrap loader,也有人稱rootloader)所載入,只不過因為這個載入器並不是用Java 所寫成,是用C++写的,所以邏輯上沒有實體)

    系統裡同時存在多個ClassLoader 的實體,而且一個類別載入器不限於只能載入一個類別,類別載入器可以載入多個類別。所以,只要取得Class 類別實體的參考,就可以利用其getClassLoader()方法籃取得載入該類別之類別載入器的參考。getClassLoader()方法最後會呼叫原生方法getClassLoader0(),其宣告如下:private native ClassLoader getClassLoader0();

最後,取得了ClassLoader 的實體,我們就可以叫用其loadClass()方法幫我們載入我們想要的類别,因此上面的Office类可做如下修改:

public class Office

{

   public static void main(String[] args) throws Exception

   {

   Office off= new Office();

   System.out.println("类别准备载入");

    ClassLoader loader = off.getClass().getClassLoader();

   java.lang.Class c = loader.loadClass(args[0]);

   System.out.println("类别准备实体化");

   Object o  = c.newInstance();

   Object o2 = c.newInstance();

   }

}

其输出结果同forName方法的第二个参数为false时相同。可见载入器载入类时只进行载入,不进行初始化。

获取ClassLoader还可以用如下的方法:

public class Office

{

   public static void main(String[] args) throws Exception

   {

    java.lang.Class cb = Office.class; 

   System.out.println("类别准备载入");

   ClassLoader loader = cb.getClassLoader();

   java.lang.Class c = loader.loadClass(args[0]);

   System.out.println("类别准备实体化");

   Object o  = c.newInstance();

   Object o2 = c.newInstance();

   }

}

在此之前,當我們談到使用類別載入器來載入類別時,都是使用既有的類別載入器來幫我們載

入我們所指定的類別。那麼,我們可以自己產生類別載入器來幫我們載入類別嗎? 答案是肯定的。

利用Java 本身提供的java.net.URLClassLoader 類別就可以做到。

   public class Office

{

   public static void main(String[] args) throws Exception

   {

      URL u = new URL("file:/d:/myapp/classload/");

        URLClassLoader ucl = new URLClassLoader(new URL[]{u});

        java.lang.Class c = ucl.loadClass(args[0]);

        Assembly asm = (Assembly)c.newInstance();

        asm.start();

   }   

}

在這個範例中,我們自己產生java.net.URLClassLoader 的實體來幫我們載入我們所需要的類別。但是載入前,我們必須告訴URLClassLoader 去哪個地方尋找我們所指定的類別才行,所以我們必須給它一個URL 類別所構成的陣列,代表我們希望它去搜尋的所有位置。URL 可以指向網際網路上的任何位置,也可以指向我們電腦裡的檔案系統(包含JAR )。在上述範例中,我們希望URLClassLoader d:\my\lib\ 這個目錄下去尋找我們需要的類別, 所以指定的URL為”file:/d:/my/lib/