java

位置:IT落伍者 >> java >> 浏览文章

Java的类装载器和命名空间


发布日期:2024年09月01日
 
Java的类装载器和命名空间

摘要

Java的类装载器是Java动态性的核心本文将向大家简要介绍Java的类装载器及相关的parentdelegation模型命名空间运行时包等概念同时讨论一些在学习中容易混淆的问题

类装载器的功能及分类

顾名思义类装载器是用来把类(class)装载进JVM的JVM规范定义了两种类型的类装载器启动类装载器(bootstrap)和用户自定义装载器(userdefinedclassloader)

bootstrap是JVM自带的类装载器用来装载核心类库如javalang*等如javalangObject是由bootstrap装载的

Java提供了抽象类ClassLoader所有用户自定义类装载器都实例化自ClassLoader的子类SystemClassLoader是一个特殊的用户自定义类装载器由JVM的实现者提供在编程者不特别指定装载器的情况下默认装载用户类系统类装载器可以通过ClassLoadergetSystemClassLoader()方法得到

测试你所使用的JVM的ClassLoader

/*LoaderSamplejava*/

publicclassLoaderSample{

publicstaticvoidmain(String[]args){

Classc;

ClassLoadercl;

cl=ClassLoadergetSystemClassLoader();

Systemoutprintln(cl);

while(cl!=null){

cl=clgetParent();

Systemoutprintln(cl);

}

try{

c=ClassforName(javalangObject);

cl=cgetClassLoader();

Systemoutprintln(javalangObjectsloaderis+cl);

c=ClassforName(LoaderSample);

cl=cgetClassLoader();

Systemoutprintln(LoaderSamplesloaderis+cl);

}catch(Exceptione){

eprintStackTrace();

}

}

}

在我的机器上(SunJava)的运行结果

C:\java>java LoaderSample

sunmiscLauncher$AppClassLoader@ba

sunmiscLauncher$ExtClassLoader@e

null

javalangObjects loader is null

LoaderSamples loader is sunmiscLauncher$AppClassLoader@ba

第一行表示系统类装载器实例化自类sunmiscLauncher$AppClassLoader

第二行表示系统类装载器的parent实例化自类sunmiscLauncher$ExtClassLoader

第三行表示系统类装载器parent的parent为bootstrap

第四行表示核心类javalangObject是由bootstrap装载的

第五行表示用户类LoaderSample是由系统类装载器装载的

parentdelegation模型

版本开始Java引入了双亲委托模型从而更好的保证Java平台的安全在此模型下当一个装载器被请求装载某个类时它首先委托自己的parent去装载若parent能装载则返回这个类所对应的Class对象若parent不能装载则由parent的请求者去装载

如图所示loader的parent为loaderloader的parent为systemclassloader假设loader被要求装载类MyClass在parentdelegation模型下loader首先请求loader代为装载loader再请求系统类装载器去装载MyClass若系统装载器能成功装载则将MyClass所对应的Class对象的reference返回给loaderloader再将reference返回给loader从而成功将类MyClass装载进虚拟机若系统类装载器不能装载MyClassloader会尝试装载MyClass若loader也不能成功装载loader会尝试装载若所有的parent及loader本身都不能装载则装载失败

若有一个能成功装载实际装载的类装载器被称为定义类装载器所有能成功返回Class对象的装载器(包括定义类装载器)被称为初始类装载器如图所示假设loader实际装载了MyClass则loader为MyClass的定义类装载器loader和loader为MyClass的初始类装载器

parentdelegation模型

需要指出的是ClassLoader是对象它的父子关系和类的父子关系没有任何关系一对父子loader可能实例化自同一个Class也可能不是甚至父loader实例化自子类子loader实例化自父类假设MyClassLoader继承自ParentClassLoader我们可以有如下父子loader

ClassLoaderloader=newMyClassLoader();//参数loader为parentClassLoaderloader=newParentClassLoader(loader);                        

那么parentdelegation模型为什么更安全了?因为在此模型下用户自定义的类装载器不可能装载应该由父亲装载器装载的可靠类从而防止不可靠甚至恶意的代码代替由父亲装载器装载的可靠代码实际上类装载器的编写者可以自由选择不用把请求委托给parent但正如上所说会带来安全的问题

命名空间及其作用

每个类装载器有自己的命名空间命名空间由所有以此装载器为初始类装载器的类组成不同命名空间的两个类是不可见的但只要得到类所对应的Class对象的reference还是可以访问另一命名空间的类

演示了一个命名空间的类如何使用另一命名空间的类在例子中LoaderSample由系统类装载器装载LoaderSample由自定义的装载器loader负责装载两个类不在同一命名空间但LoaderSample得到了LoaderSample所对应的Class对象的reference所以它可以访问LoaderSampl中公共的成员(如age)

不同命名空间的类的访问

/*LoaderSamplejava*/

import*;

importjavalangreflect*;

publicclassLoaderSample{

publicstaticvoidmain(String[]args){

try{

Stringpath=SystemgetProperty(userdir);

URL[]us={newURL(file://+path+/sub/)};

ClassLoaderloader=newURLClassLoader(us);

Classc=loaderloadClass(LoaderSample);

Objecto=cnewInstance();

Fieldf=cgetField(age);

intage=fgetInt(o);

Systemoutprintln(ageis+age);

}catch(Exceptione){

eprintStackTrace();

}

}

}

/*sub/Loadersamplejava*/

publicclassLoaderSample{

static{

Systemoutprintln(LoaderSampleloaded);

}

publicintage=;

}

编译

javacLoaderSamplejava;

javacsub/LoaderSamplejava

运行javaLoaderSample

LoaderSampleloadedageis                        

从运行结果中可以看出在类LoaderSample中可以创建处于另一命名空间的类LoaderSample中的对象并可以访问其公共成员age

运行时包(runtimepackage)

由同一类装载器定义装载的属于相同包的类组成了运行时包决定两个类是不是属于同一个运行时包不仅要看它们的包名是否相同还要看类装载器是否相同只有属于同一运行时包的类才能互相访问包可见的类和成员这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况假设用户自己定义了一个类javalangYes并用用户自定义的类装载器装载由于javalangYes和核心类库javalang*由不同的装载器装载它们属于不同的运行时包所以javalangYes不能访问核心类库javalang中类的包可见的成员

总结

在简单讨论了类装载器parentdelegation模型命名空间运行时包后相信大家已经对它们的作用有了一定的了解命名空间并没有完全禁止属于不同空间的类的互相访问双亲委托模型加强了Java的安全运行时包增加了对包可见成员的保护

               

上一篇:修改struts2的.action后缀名

下一篇:Java网络编程从入门到精通(11):使用NetworkInterface类获得网络接口信息