`
lc52520
  • 浏览: 369189 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

java ClassLoader【Z】

    博客分类:
  • java
阅读更多

JVM规范定义了两种类型的类装载器:启动内装载器 (bootstrap) 和用户自定义装载器 (user-defined class loader)
一.    ClassLoader 基本概念
1 ClassLoader 分类
类装载器是用来把类(class)装载进JVM的。
JVM规范定义了两种类型的类装载器:启动内装载器 (bootstrap) 和用户自定义装载器 (user-defined class loader)


JVM在运行时会产生三个ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader. Bootstrap是用C++编写的,我们在Java中看不到它,是null,是JVM自带的类装载器,用来装载核心类库,如java.lang.*等。
AppClassLoader Parent ExtClassLoader ,而 ExtClassLoader Parent Bootstrap ClassLoader
 
Java 提供了抽象类 ClassLoader ,所有用户自定义类装载器都实例化自 ClassLoader 的子类。 System Class Loader 是一个特殊的用户自定义类装载器,由 JVM 的实现者提供,在编程者不特别指定装载器的情况下默认装载用户类 。系统类装载器可以通过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

第一行表示,系统类装载器实例化自类sun.misc.Launcher$AppClassLoader
第二行表示,系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader
第三行表示,系统类装载器parent的parent为bootstrap
第四行表示,核心类java.lang.Object是由bootstrap装载的
第五行表示,用户类LoaderSample1是由系统类装载器装载的
 
 
二. parent delegation模型
从1.2版本开始,Java引入了双亲委托模型,从而更好的保证Java平台的安全。在此模型下,当一个装载器被请求装载某个类时,它首先委托自己的 parent 去装载,若 parent 能装载,则返回这个类所对应的 Class 对象,若 parent 不能装载,则由 parent 的请求者去装载

图 1 parent delegation模型
如 图1所示,loader2的parent为loader1,loader1的parent为system class loader。假设loader2被要求装载类MyClass,在parent delegation模型下,loader2首先请求loader1代为装载,loader1再请求系统类装载器去装载MyClass。若系统装载器能成 功装载,则将MyClass所对应的Class对象的reference返回给loader1,loader1再将reference返回给 loader2,从而成功将类MyClass装载进虚拟机。若系统类装载器不能装载MyClass,loader1会尝试装载MyClass,若 loader1也不能成功装载,loader2会尝试装载。若所有的parent及loader2本身都不能装载,则装载失败。
 
若有一 个能成功装载,实际装载的类装载器被称为定义类装载器,所有能成功返回Class对象的装载器(包括定义类装载器)被称为初始类装载器。如图1所示,假设 loader1实际装载了MyClass,则loader1为MyClass的定义类装载器,loader2和loader1为MyClass的初始类装 载器。
 
需要指出的是,Class Loader是对象,它的父子关系和类的父子关系没有任何关系。
 
那么parent delegation模型为什么更安全了?因为在此模型下用户自定义的类装载器不可能装载应该由父亲装载器装载的可靠类,从而防止不可靠甚至恶意的代码代替由父亲装载器装载的可靠代码。实际上,类装载器的编写者可以自由选择不用把请求委托给 parent ,但正如上所说,会带来安全的问题。
 
 
三.命名空间及其作用
每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。
 
例 2演示了一个命名空间的类如何使用另一命名空间的类。在例子中,LoaderSample2由系统类装载器装载,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中可以创建处于另一命名空间的类LoaderSample3中的对象并可以访问其公共成员age。
运行时包(runtime package)
由 同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看的定义类装载器是否相 同。只有属于同一运行时包的类才能互相访问包可见的类和成员。这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自 己定义了一个类java.lang.Yes,并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*由不同的装 载器装载,它们属于不同的运行时包,所以java.lang.Yes不能访问核心类库java.lang中类的包可见的成员。
 
总结
命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了 Java 的安全,运行时包增加了对包可见成员的保护。
 
二.    扩展ClassLoader 方法
我们目的是从本地文件系统使用我们实现的类装载器装载一个类。为了创建自己的类装载器我们应该扩展 ClassLoader 类,这是一个抽象类。我们创建一个 FileClassLoader extends ClassLoader 。我们需要覆盖 ClassLoader 中的 findClass(String name) 方法,这个方法通过类的名字而得到一个 Class 对象。

     public  Class findClass(String name)
    {
        
byte [] data  =  loadClassData(name);
        
return  defineClass(name, data,  0 , data.length);
    }


   我们还应该提供一个方法loadClassData(String name),通过类的名称返回class文件的字
节数组。然后使用ClassLoader提供的defineClass()方法我们就可以返回Class对象了。

     public   byte [] loadClassData(String name)
    {
        FileInputStream fis 
=   null ;
        
byte [] data  =   null ;
        
try
        {
            fis 
=   new  FileInputStream( new  File(drive  +  name  +  fileType));
            ByteArrayOutputStream baos 
=   new  ByteArrayOutputStream();
            
int  ch  =   0 ;
            
while  ((ch  =  fis.read())  !=   - 1 )
            {
                baos.write(ch);
               
            }
            data 
=  baos.toByteArray();
        } 
catch  (IOException e)
        {
            e.printStackTrace();
        }
        
        
return  data;
    }
分享到:
评论

相关推荐

    ClassLoaderDemo.7z

    在Java编程语言中,ClassLoader是核心的组成部分,它负责加载类到JVM(Java虚拟机)中。`ClassLoaderDemo.7z`这个压缩包提供的示例,旨在帮助我们理解ClassLoader的工作原理,特别是双亲委托模型以及如何打破这个...

    my_classloader_demo-master.7z Native层实现热修复

    本示例项目"my_classloader_demo-master.7z"聚焦于通过Native层实现热修复,这涉及到Android系统的核心组件以及对Java虚拟机(JVM)的深入理解。 1. **类加载器(ClassLoader)**: 在Java编程中,类加载器是负责将类...

    JAVA字节码操作库 BCEL.7z

    最后,使用`ClassLoader`加载生成的字节码,使其在JVM中生效。 总的来说,BCEL是一个强大的工具,它为Java开发者提供了一种直接操作字节码的途径,极大地扩展了Java编程的可能性。无论是进行代码分析、动态生成还是...

    Java岗面试题库.7z

    - 类加载机制:Bootstrap ClassLoader、Extension ClassLoader、AppClassLoader。 - 获取类信息:Class类,Class.forName(),newInstance()。 - 动态调用方法和访问字段:Method、Constructor、Field。 8. **...

    Java程序员必会的程序

    了解类加载器(如Bootstrap、Extension和Application ClassLoader)的工作原理,可以更好地管理类路径和库依赖。 #### 6. 多线程编程 掌握线程生命周期、同步机制(如synchronized关键字和Lock接口)、线程通信(如...

    Java敏感词过滤Java敏感词过滤

    SimpleDateFormat formatter = new SimpleDateFormat("EEE,d MMM yyyy HH:mm:ss:SSS Z"); System.out.println("start:" + formatter.format(d1)); System.out.println("" + str.length() + "字符过滤后" + ...

    Tomcat中tcnative-1文件.7z

    at java.lang.ClassLoader$NativeLibrary.load(Native Method) /******************************/ 解决方法 /*****************************/ 将tomcat目录下的bin文件中的tcnative-1.dll文件替换为64位

    浅谈Java中类的实例化步骤

    在Java编程语言中,类的实例化是一个关键概念,它涉及到如何创建对象并分配内存空间。今天我们将深入探讨Java中类的实例化步骤,特别是与`static`关键字相关的部分。 首先,`static`关键字在Java中有着特殊的意义,...

    Desktop.7z

    **BaseDexClassLoader**是Android中的一个核心类,它继承自Java的`ClassLoader`,负责加载应用的 Dalvik 或 ART 字节码(即.dex文件)。在Android 28(对应的是Android 9.0 Pie)版本中,这个类用于处理应用程序的类...

    jdk1.8 全部源码,包括sun

    7. **类加载器(ClassLoader)**:了解"sun"包中的类加载器实现,可以深入理解Java的类加载过程,包括双亲委派模型和自定义类加载器的实现。 8. **并发(Concurrency)**:"sun"包中的并发工具类源码展示了Java如何...

    JDK11源码 jdk-11.0.4 src源码

    10. **类加载机制**:JDK11的类加载机制仍然遵循“双亲委派模型”,源码中的`java.lang.ClassLoader`类及其子类展示了如何加载和查找类。 通过深入研究JDK11源码,开发者不仅可以了解到Java语言的最新发展,还能...

    pinytin的jar包资源

    3. **用户界面**:在需要按首字母筛选的界面(如联系人列表)中,可以通过这个库将汉字姓名转换为拼音,以便进行A到Z的导航。 4. **国际化**:对于支持多种语言的应用,尤其是需要与英文界面集成时,拼音转换可以...

    JVM性能优化相关问题-面试-进阶

    类加载主要由ClassLoader及其子类负责,它们动态地将.class文件加载到内存。加载方式有隐式加载(如new关键字创建对象时)和显式加载(如通过class.forName())。JVM按需加载,仅加载必要的类,提高了速度并减少了...

    android动态加载

    - **ClassLoader**:是Java虚拟机(JVM)中负责加载类文件的机制。在Android中,通过自定义ClassLoader可以实现动态加载DEX文件,即Android应用程序的主要执行文件。这种方式虽然可以实现动态加载,但是在未来的版本...

    狂神说JVM探究md完整版

    - 类加载器负责加载类到JVM,包括Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader。 - 自定义类加载器可以实现特定的加载逻辑,比如热部署。 7. **方法区** - 存储类的信息,如常量池、字段和...

Global site tag (gtag.js) - Google Analytics