有没有什么方法可以删除当前ClassLoader中已加载过的类对象

Z_Beginner 2009-06-11 11:21:21
rt
...全文
1490 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
msdn785 2011-07-20
  • 打赏
  • 举报
回复
有个问题想请教下楼主

当 Class A 和 B 都被 ClassLoad1 加载 其中 A test 方法 引用 B
后来 A发生改变 , 重新new 了一个 ClassLoad2 去重新加载Class A 并且 执行test 方法 这时候 报错 找不到 B 这种是否需要将 B也用 ClassLoad2 加载?

想知道tomcat 是否 当类有修改的时候 就将所有的ClassLoad 重新加载一遍!
Z_Beginner 2009-06-14
  • 打赏
  • 举报
回复
谢谢大家的回答。结贴了
Z_Beginner 2009-06-13
  • 打赏
  • 举报
回复
我有个应用是将接口和自定义的classloader放在一个EJB中、对于接口的不同实现类打成一个.jar包。他们都部署与JBoss相同位置。
加载实现类时出现找不到接口,我想应该是classpath问题,但不知该怎么办?
冰思雨 2009-06-12
  • 打赏
  • 举报
回复 1
没有。
在JVM中,如果一个已经被加载了的类,当它的所有对象都被GC后,这个类就有可能也被GC掉。
但Java没有显示提供卸载已被加载到JVM中的类的方法。

其次,JVM是通过 加载该类的加载器对象与该类的全限定名的组合 来唯一标识一个类的。
所以,如果程序中要求使用相同全限定名的类时,
可以通过重新创建一个加载器对象的方式来加载新的类,
这样,先后两个类,其getClassLoader方法返回的是不同的对象。

注意,上述说的类加载器,需要自己编写。因为java自带的ClassLoader抽象类中,默认的loadClass方法是交由父加载器类来完成的。
编写自己的加载器时,要注意,defineClass方式是将类文件的字节码读入到JVM中,
自定义的类加载器不调用(或不间接调用)该方法,是无法达到目的。
Z_Beginner 2009-06-11
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 Yedy2000 的回复:]
好像是没有这样的方法,可以自己再新建一个classloader来载入,用完就丢弃,要载入再新建,就能动态更新代码了吧?
[/Quote]

我试了一下,在加载部分子类时,有些父类或接口需要先加载,否则提示无法找到父类,
能否父类对象存放在一个固定的ClassLoader中,需要改动类加载到新建的ClassLoader中。
Yedy2000 2009-06-11
  • 打赏
  • 举报
回复
好像是没有这样的方法,可以自己再新建一个classloader来载入,用完就丢弃,要载入再新建,就能动态更新代码了吧?
zealVampire 2009-06-11
  • 打赏
  • 举报
回复
ClassLoader抽象类似乎没提供这样的方法.

http://www.javaresearch.org/html/article/46201.htm



====================================================
Java之ClassLoader(一)基础概念
shenkai 转贴 更新:2006-02-06 16:53:03 版本: 1.0

静态库、动态连接库

程序编制一般需经编辑、编译、连接、加载和运行几个步骤。在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;在连接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。

为了克服这个缺点可以采用动态连接库。这个时候连接器仅仅是在可执行文件中打上标志,说明需要使用哪些动态连接库;当运行程序时,加载器根据这些标志把所需的动态连接库加载到内存。

另外在当前的编程环境中,一般都提供方法让程序在运行的时候把某个特定的动态连接库加载并运行,也可以将其卸载(例如Win32的 LoadLibrary()&FreeLibrary()和Posix的dlopen()&dlclose())。这个功能被广泛地用于在程序运行时刻更新某些功能模块或者是程序外观。

What is ClassLoader?

与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。

JVM 本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,Bootstrap ClassLoader是用本地代码实现的,它负责加载核心Java Class(即所有java.*开头的类)。另外JVM还会提供两个ClassLoader,它们都是用 Java语言编写的,由Bootstrap ClassLoader加载;其中Extension ClassLoader负责加载扩展的 Java class(例如所有javax.*开头的类和存放在JRE的ext目录下的类),Application ClassLoader负责加载应用程序自身的类。

When to load the class?

什么时候JVM会使用ClassLoader加载一个类呢?当你使用java去执行一个类,JVM使用Application ClassLoader加载这个类;然后如果类A引用了类B,不管是直接引用还是用Class.forName()引用,JVM就会找到加载类A的ClassLoader,并用这个ClassLoader来加载类B。

Why use your own ClassLoader?

似乎JVM自身的ClassLoader已经足够了,为什么我们还需要创建自己的ClassLoader呢?

因为JVM自带的ClassLoader只是懂得从本地文件系统加载标准的java class文件,如果编写你自己的ClassLoader,你可以做到:
1)在执行非置信代码之前,自动验证数字签名
2)动态地创建符合用户特定需要的定制化构建类
3)从特定的场所取得java class,例如数据库中
4) 等等

事实上当使用Applet的时候,就用到了特定的ClassLoader,因为这时需要从网络上加载java class,并且要检查相关的安全信息。

目前的应用服务器大都使用了ClassLoader技术,即使你不需要创建自己的ClassLoader,了解其原理也有助于更好地部署自己的应用。

ClassLoader Tree & Delegation Model

当你决定创建你自己的ClassLoader时,需要继承java.lang.ClassLoader或者它的子类。在实例化每个ClassLoader对象时,需要指定一个父对象;如果没有指定的话,系统自动指定ClassLoader.getSystemClassLoader()为父对象。如下图:



在Java 1.2后,java class的加载采用所谓的委托模式(Delegation Modle),当调用一个ClassLoader.loadClass()加载一个类的时候,将遵循以下的步骤:
1)检查这个类是否已经被加载进来了?
2)如果还没有加载,调用父对象加载该类
3)如果父对象无法加载,调用本对象的findClass()取得这个类。

所以当创建自己的Class Loader时,只需要重载findClass()这个方法。

Unloading? Reloading?

当一个java class被加载到JVM之后,它有没有可能被卸载呢?我们知道Win32有FreeLibrary()函数,Posix有 dlclose()函数可以被调用来卸载指定的动态连接库,但是Java并没有提供一个UnloadClass()的方法来卸载指定的类。

在Java中,java class的卸载仅仅是一种对系统的优化,有助于减少应用对内存的占用。既然是一种优化方法,那么就完全是JVM自行决定如何实现,对Java开发人员来说是完全透明的。

在什么时候一个java class/interface会被卸载呢?Sun公司的原话是这么说的:"class or interface may be unloaded if and only if its class loader is unreachable. Classes loaded by the bootstrap loader may not be unloaded."

事实上我们关心的不是如何卸载类的,我们关心的是如何更新已经被加载了的类从而更新应用的功能。JSP则是一个非常典型的例子,如果一个JSP文件被更改了,应用服务器则需要把更改后的JSP重新编译,然后加载新生成的类来响应后继的请求。

其实一个已经加载的类是无法被更新的,如果你试图用同一个ClassLoader再次加载同一个类,就会得到异常(java.lang.LinkageError: duplicate class definition),我们只能够重新创建一个新的 ClassLoader实例来再次加载新类。至于原来已经加载的类,开发人员不必去管它,因为它可能还有实例正在被使用,只要相关的实例都被内存回收了,那么JVM就会在适当的时候把不会再使用的类卸载。
主要特性Java 语言是简单的:Java 语言的语法与 C 语言和 C++ 语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java 丢弃了 C++ 很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地,Java 语言不使用指针,而是引用。并提供了自动分配和回收内存空间,使得程序员不必为内存管理而担忧。Java 语言是面向对象的:Java 语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为 implements)。Java 语言全面支持动态绑定,而 C++语言只对虚函数使用动态绑定。总之,Java语言是一个纯的面向对象程序设计语言。Java语言是分布式的:Java 语言支持 Internet 应用的开发,在基本的 Java 应用编程接口有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括 URL、URLConnection、Socket、ServerSocket 等。Java 的 RMI(远程方法激活)机制也是开发分布式应用的重要手段。Java 语言是健壮的:Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证。对指针的丢弃是 Java 的明智选择。Java 的安全检查机制使得 Java 更具健壮性。Java语言是安全的:Java通常被用在网络环境,为此,Java 提供了一个安全机制以防恶意代码的攻击。除了Java 语言具有的许多安全特性以外,Java 对通过网络下载的类具有一个安全防范机制(类 ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制(类 SecurityManager)让 Java 应用设置安全哨兵。Java 语言是体系结构立的:Java 程序(后缀为 java 的文件)在 Java 平台上被编译为体系结构立的字节码格式(后缀为 class 的文件),然后可以在实现这个 Java 平台的任何系统运行。这种途径适合于异构的网络环境和软件的分发。Java 语言是可移植的:这种可移植性来源于体系结构立性,另外,Java 还严格规定了各个基本数据类型的长度。Java 系统本身也具有很强的可移植性,Java 编译器是用 Java 实现的,Java 的运行环境是用 ANSI C 实现的。Java 语言是解释型的:如前所述,Java 程序在 Java 平台上被编译为字节码格式,然后可以在实现这个 Java 平台的任何系统运行。在运行时,Java 平台的 Java 解释器对这些字节码进行解释执行,执行过程需要的类在联接阶段被载入到运行环境。Java 是高性能的:与那些解释型的高级脚本语言相比,Java 的确是高性能的。事实上,Java 的运行速度随着 JIT(Just-In-Time)编译器技术的发展越来越接近于 C++。Java 语言是多线程的:在 Java 语言,线程是一种特殊的对象,它必须由 Thread 类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为 Thread(Runnable) 的构造子类将一个实现了 Runnable 接口的对象包装成一个线程,其二,从 Thread 类派生出子类并重写 run 方法,使用该子类创建的对象即为线程。值得注意的是 Thread 类已经实现了 Runnable 接口,因此,任何一个线程均有它的 run 方法,而 run 方法包含了线程所要运行的代码。线程的活动由一组方法来控制。Java 语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为 synchronized)。Java 语言是动态的:Java 语言的设计目标之一是适应于动态变化的环境。Java 程序需要的类能够动态地被载入到运行环境,也可以通过网络来载入所需要的类。这也有利于软件的升级。另外,Java 的类有一个运行时刻的表示,能进行运行时刻的类型检查。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧