`
senton
  • 浏览: 206674 次
  • 性别: Icon_minigender_1
  • 来自: 紫禁城
社区版块
存档分类
最新评论

java类装载器

    博客分类:
  • J2SE
阅读更多

一 . 面向接口编程. 不要面向类编程.

二 . 关于异常:
如果父类的一个方法抛出了异常,子类在重写此方法时可以不抛出异常而直接处理,也可以抛出父类异常的子异

常,但是不能抛出比父类方法抛出的异常级别更高的异常.

三 . Java的类装载器(Class Loader)和命名空间(NameSpace)

1.摘要:
Java的类装载器是Java动态性的核心,本文将向大家简要介绍Java的类装载器,及相关的双亲委派模型,命名

空间,运行时包等概念,同时讨论一些在学习中容易混淆的问题。

2.类装载器的功能及分类:
顾名思义,类装载器是用来把类(class)装载进JVM的。JVM规范定义了两种类型的类装载器:启动内装载器

(bootstrap)和用户自定义装载器(user-defined class loader)。

bootstrap是JVM自带的类装载器,用来装载核心类库,如java.lang.*等。由例1可以看出,java.lang.Object

是由bootstrap装载的。

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是由系统类装载器装载的


3.双亲委派模型:
从1.2版本开始,Java引入了双亲委托模型,从而更好的保证Java平台的安全。在此模型下,当一个装载器被请

求装载某个类时,它首先委托自己的parent去装载,若parent能装载,则返回这个类所对应的Class对象,若

parent不能装载,则由parent的请求者去装载。

如图1所示,loader2的parent为loader1,loader1的parent为system class loader。假设loader2被要求装载

类MyClass,在双亲委派模型下,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是对象,它的父子关系和类的父子关系没有任何关系。一对父子loader可能实例

化自同一个Class,也可能不是,甚至父loader实例化自子类,子loader实例化自父类。假设MyClassLoader继

承自ParentClassLoader,我们可以有如下父子loader:
ClassLoader loader1 = new MyClassLoader();
ClassLoader loader2 = new ParentClassLoader(loader1); //参数 loader1为parent

那么双亲委托模型为什么更安全了?因为在此模型下用户自定义的类装载器不可能装载应该由父亲装载器装载

的可靠类,从而防止不可靠甚至恶意的代码代替由父亲装载器装载的可靠代码。实际上,类装载器的编写者可

以自由选择不用把请求委托给parent,但正如上所说,会带来安全的问题。


4.命名空间及其作用:
每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。不同命名空间的两个

类是不可见的,但只要得到类所对应的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。

5.运行时包(runtime package):
由同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要

看它们的包名是否相同,还要看的定义类装载器是否相同。只有属于同一运行时包的类才能互相访问包可见的

类和成员。这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自

己定义了一个类java.lang.Yes,并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*

由不同的装载器装载,它们属于不同的运行时包,所以java.lang.Yes不能访问核心类库java.lang中类的包可

见的成员。


6.总结:
在简单讨论了类装载器,双亲委派模型,命名空间,运行时包后,相信大家已经对它们的作用有了一定的了解

。命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了Java的安全,运行时包增加了

对包可见成员的保护。


7.参考资料:
 <<Inside The Java Virtual Machine>> by Bill Venners
 <<The Java Virtual Machine Specification>> by Sun

四 . 再谈类装载器

 作为程序的一部分,每个类都有一个class对象.换言之,每当你编写并且编译了一个新类,就会产生一个

Class对象(更恰当的说,是被保存在一个同名的.class文件中).在运行期,一旦我们想生成这个类的一个对象,运

行这个程序的java虚拟机(JVM)首先检查这个类的Class对象是否已经加载,如果尚未加载,JVM就会根据类名查找

.class文件,并将期载入,所以Java程序并不是一开始执行就被完全加载的,这一点与许多传统语言不同,一旦某

个类的Class对象被载入内存,它就被用来创建这个类的所有对象,请看下面的例子:

class Candy
{
 static
 {
  System.out.println ("Loading Candy");
 }
}

class Gum
{
 static
 {
  System.out.println ("Loading Gum");
 }
}

class Cookie
{
 static
 {
  System.out.println ("Loading Cookie");
 }
}

public class ClassTest
{
    public static void main(String[] args)
    {
     System.out.println ("inside main");
     new Candy();
     System.out.println ("After creating Candy");
     try
     {
      Class.forName("Gum");
     }
     catch(ClassNotFoundException e)
     {
      System.out.println ("Couldn't find Gum");
     }
     
     System.out.println ("After Class.forName(\"Gum\")");
     new Cookie();
     System.out.println ("After creating Cookie");
    }
}

打印结果如下:
inside main
Loading Candy
After creating Candy
Couldn't find Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie

这里的每个类Candy,Gum,Cookie中,都有一个static语句,在类第一次被加载时执行,这时会有相应结果打印出来

告诉我们这个类什么时候被加载了.在main()中,创建对象的代码被置于打印语句之间,以帮助我们判断加载的时

间点.你可以从输出中看出,Class对象仅在需要的时候才被加载,static语句块是在类加载时被执行的.看这行

:Class.forName("Gum"),这是Class类(所有Class对象都属于这个类型)的一个static成员,Class对象和其他对

象一样,我们可以获取并操作它的引用(这就是类加载器的工作),forName()时取得Class对象的引用一个方法,它

时用一个包含目标类的文件名的String作为输入参数,返回一个Class对象的引用,上面的代码忽略了返回值,对

forName()的调用是为了它产生的"副作用":如果类Gum还没有被加载就加载它.在加载的过程中,Gum的static语

句被执行.在前面的例子中,如果Class.forName()找不到你要加载的类.它会抛出异常ClassNotFoundException
 

分享到:
评论

相关推荐

    [浅析J2EE应用服务器的JAVA类装载器]python回朔异常的模块.docx

    【浅析J2EE应用服务器的JAVA类装载器】 Java类装载器机制是Java语言灵活性的关键组成部分,尤其在J2EE应用服务器中扮演着重要角色。理解这一机制有助于开发者更好地部署和管理应用程序,解决可能出现的部署问题。 ...

    java类装载器学习一、类加载器的基本概念

    类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念 类装载器学习一、类加载器的基本概念

    java类加载器实例

    类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java ...

    java类装载

    java类装载介绍,介绍了java装载类的先后顺序

    Java的类装载器和命名空间

    在Java编程语言中,类装载器(ClassLoader)和命名空间是理解Java运行时环境的重要概念。它们共同确保了程序的正确性和安全性。类装载器负责将类文件加载到Java虚拟机(JVM)中,而命名空间则帮助组织和管理这些类,...

    Java深度历险(2)--深入类装载器

    ### Java深度历险(2)--深入类装载器 #### 前言 在现代软件开发领域,特别是使用Java这样的高级编程语言时,“动态性”是一个非常重要的概念。它指的是程序能够在运行时根据需要加载、卸载或替换部分代码的能力。这...

    WAS+V7+理解类装入器-红皮书.pdf

    3. **应用程序类装载器(Application Class Loader)**:它是默认的应用程序类装载器,负责加载用户类路径(`java.class.path`)中定义的类。用户可以通过环境变量`CLASSPATH`来控制哪些类路径被包含在内。应用程序类...

    Java虚拟机类装载的原理及实现

    所有JVM都内置了一个特殊的类装载器——根装载器(Bootstrap ClassLoader),它负责装载Java核心类库。当需要装载非设计时已知的类时,则需要使用用户自定义的类装载器。 #### 实例演示 以下是一个简单的示例,...

    Java虚拟机类装载:原理、实现与应用

    例如,我们可以创建一个类装载器,专门用于加载网络上的类,或者加载特定目录下的类文件,从而实现动态扩展应用程序的功能。 在实际应用中,类装载机制使得Java应用程序能够灵活地加载不同版本的库,或者在运行时...

    jvm类装载器原理

    Java的JVM(Java Virtual Machine)类装载器是Java运行时系统的重要组成部分,负责在程序运行期间查找并加载类的二进制数据。理解类装载器的工作原理对于优化Java应用性能和实现动态加载类至关重要。 装载过程包括...

    java之jvm学习笔记五(实践写自己的类装载器)

    Java的类装载器分为三个基本层次:启动类装载器(Bootstrap ClassLoader)、扩展类装载器(Extension ClassLoader)和应用程序类装载器(Application ClassLoader)。它们共同协作,根据类的全限定名(包括包名和...

    java中的四个核心概念_.docx

    Java类装载器分为两类:启动类装载器和用户定义的类装载器。启动类装载器是JVM的一部分,负责加载Java API和其他基础类。用户定义的类装载器可以自定义加载方式,如从网络加载class文件。用户定义的类装载器是用...

    Java虚拟机类装载机制

    Java虚拟机类装载机制是Java运行环境中的核心组成部分,它负责将类的字节码从磁盘、网络等不同来源加载到JVM中,并进行一系列处理以使类能够被正确地使用。类装载机制的目的是为了实现代码的动态加载和运行时的灵活...

    Java类装载过程_.docx

    在这个阶段,JVM会通过类装载器寻找并加载类的二进制数据。这通常是从类路径(Classpath)中获取的,例如`.class`文件。装载过程包括: - 二进制数据流生成:通过类路径查找指定类的`.class`文件,读取其二进制数据...

    Java虚拟机类装载.doc

    在Java中,类装载器 把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化。其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的。各个步骤的主要工作如下: * ...

    Java四大核心技术思想详解.doc

    Java类装载器体系结构设计灵活,支持不同类型的类装载器来适应不同的应用场景。主要分类包括: 1. **启动类装载器(Bootstrap Class Loader)**:它是JVM的一部分,负责加载Java核心库,如`rt.jar`。这些库通常位于...

    Java虚拟机类装载:原理、实现与应用.doc

    - 系统类装载器是JVM内置的,用于加载Java标准库的类。 理解类装载机制对于优化程序性能、实现动态加载、插件系统以及增强程序的灵活性具有重要意义。例如,通过自定义类装载器,开发者可以在运行时替换或添加新的...

Global site tag (gtag.js) - Google Analytics