码迷,mamicode.com
首页 > 编程语言 > 详细

JavaEE学习之类加载器

时间:2015-09-04 07:08:42      阅读:270      评论:0      收藏:0      [点我收藏+]

标签:

类装载子系统

  在JAVA虚拟机中,负责查找并装载类型的那部分被称为类装载子系统。

  JAVA虚拟机有两种类装载器:启动类装载器和用户自定义类装载器。前者是JAVA虚拟机实现的一部分,后者则是Java程序的一部分。由不同的类装载器装载的类将被放在虚拟机内部的不同命名空间中。

  类装载器子系统涉及Java虚拟机的其他几个组成部分,以及几个来自java.lang库的类。比如,用户自定义的类装载器是普通的Java对象,它的类必须派生自java.lang.ClassLoader类。ClassLoader中定义的方法为程序提供了访问类装载器机制的接口。此外,对于每一个被装载的类型,JAVA虚拟机都会为它创建一个java.lang.Class类的实例来代表该类型。和所有其他对象一样,用户自定义的类装载器以及Class类的实例都放在内存中的堆区,而装载的类型信息则都位于方法区。

  类装载器子系统除了要定位和导入二进制class文件外,还必须负责验证被导入类的正确性,为类变量分配并初始化内存,以及帮助解析符号引用。这些动作必须严格按以下顺序进行:

  (1)装载——查找并装载类型的二进制数据。

  (2)连接——指向验证、准备、以及解析(可选)。

    ● 验证  确保被导入类型的正确性。

    ● 准备  为类变量分配内存,并将其初始化为默认值。

    ● 解析  把类型中的符号引用转换为直接引用。

  (3)初始化——把类变量初始化为正确初始值。

  每个JAVA虚拟机实现都必须有一个启动类装载器,它知道怎么装载受信任的类,每个类装载器都有自己的命名空间,其中维护着由它装载的类型,所以一个Java程序可以多次装载具有同一个全限定名的多个类型,这样一个类型的全限定名就不足以确定在一个Java虚拟机中的唯一性。因此,当多个类装载器都装载了同名的类型时,为了惟一地标识该类型,还要在类型名称前加上装载该类型(指出它所位于的命名空间)的类装载器标识。位于不同命名空间的相同类无法相互转换,下面程序演示了这一点:

  1 import java.io.ByteArrayInputStream;
  2 import java.io.ByteArrayOutputStream;
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.FileNotFoundException;
  6 import java.io.IOException;
  7 import java.io.InputStream;
  8 
  9 public class MyClass extends ClassLoader{
 10     
 11     private String name;//类加载器的名称
 12     
 13     private String path;//加载类的路径
 14     
 15     private final String extendName = ".class";//文件扩展名
 16 
 17     public String getName() {
 18         return name;
 19     }
 20 
 21     public void setName(String name) {
 22         this.name = name;
 23     }
 24 
 25     public String getPath() {
 26         return path;
 27     }
 28 
 29     public void setPath(String path) {
 30         this.path = path;
 31     }
 32 
 33     public String getExtendName() {
 34         return extendName;
 35     }
 36     
 37     public MyClass(String name){
 38         super();
 39         this.name = this.name;
 40     }
 41     
 42     public MyClass(ClassLoader parent,String name){
 43         super(parent);
 44         this.name=name;
 45     }
 46 
 47     @Override
 48     public String toString() {
 49         return this.name;
 50     }
 51 
 52     @Override
 53     protected Class<?> findClass(String name) throws ClassNotFoundException {
 54         byte[] bytes = this.loadDate(name);
 55         return this.defineClass(name, bytes, 0, bytes.length);
 56     }
 57     
 58     public byte[] loadDate(String name){
 59         String filename = name.replace(".", "\\");
 60         String filepath = this.path+filename+this.extendName;
 61         File file = new File(filepath);
 62         InputStream in = null;
 63         ByteArrayOutputStream out = null;
 64         byte[] bytes = null;
 65         try {
 66              in = new FileInputStream(file);
 67             int len = 0;
 68             out = new ByteArrayOutputStream();
 69             while((len=in.read())!=-1){
 70                 out.write(len);
 71             }
 72             bytes=out.toByteArray();
 73             return bytes;
 74         } catch (FileNotFoundException e) {
 75             e.printStackTrace();
 76         } catch (IOException e) {
 77             e.printStackTrace();
 78         }finally{
 79             try {
 80                 in.close();
 81                 out.close();
 82             } catch (IOException e) {
 83                 e.printStackTrace();
 84             }
 85         }
 86         return null;
 87     }
 88     
 89     public static void main(String[] args) {
 90         MyClass loader1 = new MyClass("loader1");
 91         loader1.setPath("E:\\test\\loader1");
 92         MyClass loader2 = new MyClass(loader1,"loader2");
 93         loader2.setPath("E:\\test\\loader2");
 94         
 95         
 96         MyClass loader3 = new MyClass(null,"loader3");
 97         loader3.setPath("E:\\test\\loader3\\");
 98         test(loader1);
 99         test(loader2);
100         test(loader3);
101         
102         try{
103             Class classzz = loader3.loadClass("Sample");
104             Object object = classzz.newInstance();
105             Sample sample = (Sample)object;
106             System.out.println(sample.toString());
107         }catch(Exception e){
108             e.printStackTrace();
109         }
110     }
111     
112     public static void test(ClassLoader loader){
113         try{
114             Class classzz = loader.loadClass("Sample");
115             Object object = classzz.newInstance();
116         }catch(Exception e){
117             e.printStackTrace();
118         }
119     }
120 }
1 public class Sample {
2     public Sample(){
3         System.out.println("i am Sample......,加载我的类加载器的名称是:"+this.getClass().getClassLoader().toString());    
4         new Person();
5     }
6 }
1 public class Person {
2     public Person(){
3         System.out.println("i am person......,加载我的类加载器的名称是:"+this.getClass().getClassLoader().toString());    
4     }
5 }

上面程序通过继承ClassLoader,实现自定义类加载器,在主方法中,创建三个自定义类加载器,其中loader2的父类加载器为loader1,loader3的父类加载器为根类加载器,在E盘下创建三条路径,分别为E:\\test\\loader1,E:\\test\\loader2,E:\\test\\loader3,将三段程序的.class文件分别放置在三个文件夹内,通过DOS命令切换到该目录下,首先运行命令:java MyClass,结果如下:

1 E:\test\loader1>java MyClass
2 i am sample......,加载我的类加载器的名称是:sun.misc.Launcher$AppClassLoader@39443f
3 i am person......,加载我的类加载器的名称是:sun.misc.Launcher$AppClassLoader@39443f
4 i am sample......,加载我的类加载器的名称是:sun.misc.Launcher$AppClassLoader@39443f
5 i am person......,加载我的类加载器的名称是:sun.misc.Launcher$AppClassLoader@39443f
6 i am sample......,加载我的类加载器的名称是:loader3
7 i am person......,加载我的类加载器的名称是:loader3

    从结果可以看出,test1,test2均为系统类加载加载所需要类,对于test3,加载所需类的类加载器为自定义类加载器MyClass,可以肯出虚拟机在加载类的过程中使用父类委托机制,loader3的父类为根类加载器,在JDK中找不到自定义类Sample,所以只能靠自定义类加载器加载该类,对于该自定义类加载器加载的类则位于自己命名空间下,其他明明空间下无法调用,可以通过修改上述程序进行验证,

  1 //package com.swust.自定义类加载器;
  2 
  3 import java.io.ByteArrayInputStream;
  4 import java.io.ByteArrayOutputStream;
  5 import java.io.File;
  6 import java.io.FileInputStream;
  7 import java.io.FileNotFoundException;
  8 import java.io.IOException;
  9 import java.io.InputStream;
 10 
 11 public class MyClass extends ClassLoader{
 12     
 13     private String name;//类加载器的名称
 14     
 15     private String path;//加载类的路径
 16     
 17     private final String extendName = ".class";//文件扩展名
 18 
 19     public String getName() {
 20         return name;
 21     }
 22 
 23     public void setName(String name) {
 24         this.name = name;
 25     }
 26 
 27     public String getPath() {
 28         return path;
 29     }
 30 
 31     public void setPath(String path) {
 32         this.path = path;
 33     }
 34 
 35     public String getExtendName() {
 36         return extendName;
 37     }
 38     
 39     public MyClass(String name){
 40         super();
 41         this.name = this.name;
 42     }
 43     
 44     public MyClass(ClassLoader parent,String name){
 45         super(parent);
 46         this.name=name;
 47     }
 48 
 49     @Override
 50     public String toString() {
 51         return this.name;
 52     }
 53 
 54     @Override
 55     protected Class<?> findClass(String name) throws ClassNotFoundException {
 56         byte[] bytes = this.loadDate(name);
 57         return this.defineClass(name, bytes, 0, bytes.length);
 58     }
 59     
 60     public byte[] loadDate(String name){
 61         String filename = name.replace(".", "\\");
 62         String filepath = this.path+filename+this.extendName;
 63         File file = new File(filepath);
 64         InputStream in = null;
 65         ByteArrayOutputStream out = null;
 66         byte[] bytes = null;
 67         try {
 68              in = new FileInputStream(file);
 69             int len = 0;
 70             out = new ByteArrayOutputStream();
 71             while((len=in.read())!=-1){
 72                 out.write(len);
 73             }
 74             bytes=out.toByteArray();
 75             return bytes;
 76         } catch (FileNotFoundException e) {
 77             e.printStackTrace();
 78         } catch (IOException e) {
 79             e.printStackTrace();
 80         }finally{
 81             try {
 82                 in.close();
 83                 out.close();
 84             } catch (IOException e) {
 85                 e.printStackTrace();
 86             }
 87         }
 88         return null;
 89     }
 90     
 91     public static void main(String[] args) {
 92         MyClass loader1 = new MyClass("loader1");
 93         loader1.setPath("E:\\test\\loader1\\");
 94         MyClass loader2 = new MyClass(loader1,"loader2");
 95         loader2.setPath("E:\\test\\loader2\\");
 96         
 97         
 98         MyClass loader3 = new MyClass(null,"loader3");
 99         loader3.setPath("E:\\test\\loader3\\");
100 //        test(loader1);
101 //        test(loader2);
102 //        test(loader3);
103         
104         try{
105             Class classzz = loader3.loadClass("Sample");
106             Class classess = loader1.loadClass("Sample");
107             Object object = classzz.newInstance();
108             Object object1 = classess.newInstance();
109             System.out.println("由不同类加载器加载的类类型是否可以转换:"+(object==object1));
110 //            Sample sample = (Sample)object;
111 //            System.out.println(sample.toString());
112         }catch(Exception e){
113             e.printStackTrace();
114         }
115     }
116     
117     public static void test(ClassLoader loader){
118         try{
119             Class classzz = loader.loadClass("Sample");
120             Object object = classzz.newInstance();
121         }catch(Exception e){
122             e.printStackTrace();
123         }
124     }
125 }

执行结果如下:

1 E:\test\loader1>java -cp .;E:\test\loader3 MyClass
2 i am sample......,加载我的类加载器的名称是:loader3
3 i am person......,加载我的类加载器的名称是:loader3
4 i am sample......,加载我的类加载器的名称是:sun.misc.Launcher$AppClassLoader@39443f
5 i am person......,加载我的类加载器的名称是:sun.misc.Launcher$AppClassLoader@39443f
6 由不同类加载器加载的类类型是否可以转换:false

从结果可以看出,由不同类加载器加载的同一类无法相互引用,虽然都是相同的类Sample,但由于他们位于不同的命名空间中,但新建实例却不是同一对象,这样做也保证了类的唯一性

 

JavaEE学习之类加载器

标签:

原文地址:http://www.cnblogs.com/sunfie/p/4780947.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!