认识java的类加载器(一)

1、认识类装载器:

类装入组件是 JAVA 虚拟机的基础,其是一个重要的、但又常常被我们忽略的 JAVA 运行时系统组件。它是负责在运行时查找和装入类文件的类,因此创建自己的 ClassLoader 可以非常方便的定制 JVM

JAVA编译的程序是一种特殊的、独立于平台的格式,并非依赖于它们所运行的平台。JAVA编译的类文件在运行时并非立即全部都装入内存,而是根据程序需要装入内存,有点类似我们操作系统的虚拟存储管理,根据。ClassLoader JVM 中将类装入内存的那部分。

JAVA的类加载器本身就是用 JAVA编写的,这意味着创建您自己的 ClassLoader 非常容易,不必了解 JVM的低层细节。

那么为什么要创建自己的类加载器呢,主要是由于JAVA默认的类加载器只能加载本地的类文件,这与JAVA的网络特性非常的不合,因此,有必要根据需要修改JAVA的类加载器方便的从网络加载类文件。

有许多其它方式可以获取类文件。除了简单地从本地或网络装入文件以外,可以使用定制的 ClassLoader 完成以下任务:

n        在执行非置信代码之前,自动验证数字签名

n        使用用户提供的密码透明地解密代码

n        动态地创建符合用户特定需要的定制化构建类

任何您认为可以生成 JAVA 字节码的内容都可以集成到应用程序中。

每个 Class 对象都包含一个对定义它的 ClassLoader 引用

数组类的 Class 对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建。数组类的类加载器由 Class.getClassLoader() 返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。

2、如何定制ClassLoader

我相信编写过Applet程序的朋友都知道,通过Http协议我们可以从远程服务器上下载JAVA字节代码进行加载运行,这都归功与JAVA的自定义类加载器,Applet查看器内置了一个类加载器,它不是在本地加载类文件,而是通过Http协议从网络中加载。同时这个加载器还可以做其它事情,通过JAVA的沙箱来限制Applet的安全范围,并且不干扰其他的Applet程序。

类加载器ClassLoader是负责加载类的对象。ClassLoader 类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。

ClassLoader 类使用委托模型来搜索类和资源。每个 ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 "bootstrap class loader")本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。

实例代码:

 

Java代码 复制代码
  1. import java.io.*;   
  2.   
  3. class NetworkClassLoader extends ClassLoader {   
  4.        
  5.     private String host;   
  6.     private int port;   
  7.        
  8.     public static void main(String[] args)throws Exception{   
  9.            
  10.          ClassLoader loader = new NetworkClassLoader("127.0.0.1"4444);   
  11.          Object pig = loader.loadClass("Pig.class").newInstance();   
  12.     }   
  13.        
  14.     public NetworkClassLoader(){   
  15.     }   
  16.        
  17.     public NetworkClassLoader(String host,int port){   
  18.         this.host = host;   
  19.         this.port = port;   
  20.     }   
  21.        
  22.     //类加载器   
  23.     public Class loadClass( String name, boolean resolve ) throws ClassNotFoundException{   
  24.         // 目标Class   
  25.         Class clas = null;   
  26.   
  27.         // 看是否已经加载该类   
  28.         clas = findLoadedClass( name );   
  29.            
  30.            
  31.         if(clas == null){   
  32.             clas = findClass(name);   
  33.         }   
  34.            
  35.         //如果class对象不存在则在系统中查找   
  36.         if (clas==null) {   
  37.           clas = findSystemClass( name );   
  38.         }   
  39.            
  40.         if(clas == null){   
  41.                
  42.             throw new ClassNotFoundException("该类不存在1");   
  43.         }   
  44.            
  45.         //是否需要分析该类   
  46.         if (resolve && clas != null)   
  47.             resolveClass( clas );   
  48.         return clas;   
  49.      }   
  50.        
  51.     //构造该类的Class对象   
  52.     public Class findClass(String name){   
  53.         try{   
  54.             byte[] b = loadClassData(name);   
  55.             if(b == null){   
  56.                 return null;   
  57.             }   
  58.             System.out.println("my findClass method");   
  59.                
  60.             return defineClass("Pig", b, 0, b.length);   
  61.                
  62.         }catch(IOException e){   
  63.             System.out.print(e.getMessage());   
  64.         }   
  65.         return null;   
  66.     }   
  67.        
  68.     //从网络加载加载类的二进制代码,此处我们使用本地文件   
  69.     private byte[] loadClassData(String name)throws IOException{   
  70.            
  71.         //读取类文件   
  72.         File file = new File(name);   
  73.         if(!file.exists()){   
  74.             return null;   
  75.         }   
  76.         FileInputStream input = new FileInputStream(file);   
  77.         long length = file.length();   
  78.         byte[] bt = new byte[(int)length];   
  79.            
  80.         int rl = input.read(bt);   
  81.            
  82.         if(rl != length){   
  83.             throw new IOException("不能读取所有内容");   
  84.         }   
  85.         input.close();   
  86.            
  87.         return bt;   
  88.     }   
  89. }  

Class loadClass( String name, boolean resolve )方法ClassLoader 的入口点。

使用指定的二进制名称来加载类。此方法的默认实现将按以下顺序搜索类:

l        调用 findLoadedClass(String) 来检查是否已经加载类。

l        在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。

l        调用 findClass(String) 方法查找类。

l        如果使用上述步骤找到类,并且 resolve 标志为真,则此方法将在得到的 Class 对象上调用 resolveClass(Class) 方法。

鼓励用 ClassLoader 的子类重写 findClass(String),而不是使用此方法。

finalClass<?>defineClass(String name,byte[] b,int off,int len)方法 ClassLoader 的主要功能部件。该方法接受由编译后的字节的数组并把它转换成 Class对象。原始数组包含如从文件系统或网络装入的数据。

defineClass 管理 JVM 的许多复杂、神秘和倚赖于实现的方面 -- 它把字节码分析成运行时数据结构、校验有效性等等,类似编译器的自动机。而且你没有办法重写这个方法,正如你看到的,他是final类型。

final Class<?> findSystemClass(String name)方法从本地classpath中装入文件。它在本地文件系统中寻找类文件,如果存在,就使用 defineClass 将原始字节转换成 Class 对象,以将该文件转换成类。当运行 Java 应用程序时,这是 JVM的缺省类文件装载机制。

final Class<?> findLoadedClass(String name)方法用来判断类加载器是否已经加载了该类,避免不必要的资源浪费,建议首先调用该方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值