- 浏览: 66884 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
DawnBells:
十年前的博..
简单理解Spring中的PROPAGATION_NESTED -
AALLLLEN:
请问为BC失败之后,是什么情况呢。并且BC又调用了声明了REQ ...
简单理解Spring中的PROPAGATION_NESTED -
sharajava:
草稿你也能看到?这段时间打算花些时间把技术梳理一下。
开发人员常用的Oracle技术 -
yjj1999:
老大 不错 学习了 好久没用过oracle了
开发人员常用的Oracle技术 -
sharajava:
之前在google上保存的一些学习笔记之一,google在中国 ...
事务的理解
问:调用 Class.forName() 与 ClassLoader.loadClass() 的区别在什么地方?
答:这两方法都是通过一个给定的类名去定位和加载这个类名对应的 java.long.Class 类对象 . 尽管如此 , 它们的在行为方式上还是有区别的 .
Ø 用哪个 java.lang.ClassLoader 进行加载
Ø 返回的 Class 对象是否被初始化
Class.forName(String) 方法(只有一个参数), 使用调用者的类加载器来加载, 也就是用加载了调用forName方法的代码的那个类加载器. 相应的, ClassLoader.loadClass()方法是一个实例方法(非静态方法), 调用时需要自己指定类加载器, 那么这个类加载器就可能是也可能不是加载调用代码的类加载器. 如果用特定的类加载器来加载类在你的设计中占有比较重要的地位, 你就应该调用ClassLoader.loadClass(String)方法或Class.forName(String, boolean, ClassLoader)方法.
另外, Class.forName()方法对加载的类对象进行初始化. 可见的效果就是类中静态初始化段及字节码中对所有静态成员的初始工作的执行(这个过程在类的所有父类中递归地调用). 这点就与ClassLoader.loadClass()不同. ClassLoader.loadClass()加载的类对象是在第一次被调用时才进行初始化的.
你可以利用上述的差异. 比如,要加载一个静态初始化开销很大的类, 你就可以选择提前加载该类(以确保它在classpath下), 但不进行初始化, 直到第一次使用该类的域或方法时才进行初始化.
最常用的是Class.forName(String, boolean, ClassLoader). 设置第二个参数为false即推迟初始化, 第三个参数指定要用来进行加载的类加载器. 我建议为了最大的灵活性使用这个方法.
类初始化错误是难处理的
成功地加载了类, 并不意味着就不会有其它问题. 静态初始化代码可以抛出异常, 异常被包装到java.long.ExceptionInInitializerError的实例中. 异常抛出后, 这个类将不可用. 这样, 如果你需要在代码中处理这些错误, 你就应该调用进行初始化的Class.forName()方法. <o:p></o:p>
但进一步说, 如果你要处理ExceptionInInitializerError并试图从错误中恢复, 很可能不如你想象的那样正常工作. 请看下面的示例代码:<o:p></o:p>
public class Main
{
public static void main (String [] args) throws Exception
{
for ( int repeat = 0; repeat < 3; ++ repeat)
{
try
{
// "Real" name for X is outer class name+$+nested class name:
Class.forName ("Main$X");
}
catch (Throwable t)
{
System.out.println ("load attempt #" + repeat + ":");
t.printStackTrace (System.out);
}
}
}
private static class X
{
static
{
if (++ s_count == 1)
throw new RuntimeException ("failing static initializer<v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 11.25pt; HEIGHT: 15pt" alt="" type="#_x0000_t75"><v:imagedata o:href="/Images/dot.gif" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"></v:imagedata></v:shape>");
}
} // End of nested class
private static int s_count;
} // End of class
<o:p></o:p>
上面的代码3次尝试加载一个内部类X, 即便是X的静态初始化只在每一次加载时失败, 这3次加载都抛出了异常. <o:p></o:p>
>java Main
load attempt #0:
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at Main.main(Main.java:17)
Caused by: java.lang.RuntimeException: failing static initializer...
at Main$X.<clinit>(Main.java:40)
... 3 more
load attempt #1:
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at Main.main(Main.java:17)
load attempt #2:
java.lang.NoClassDefFoundError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:140)
at Main.main(Main.java:17) <o:p></o:p>
有点令人吃惊的时, 在第2, 3次进行类加载时, 抛出的异常竟然是java.lang.NoClassDefFoundError. 这里发生的事情是, 第一次加载后(在进行初始化之前), JVM发现X已经被加载, 而这个X的类实例在加载它的类加载器被垃圾回收之前是不会被卸载的. 所以这之后的对Class.forName()的调用时, JVM不会再尝试进行初始化的工作, 但是, 更令人不解的是, 抛出一个NoClassDefFoundError. <o:p></o:p>
卸载这样的类的方法是丢弃原来加载该类的类加载器实例并重新创建一个. 当然, 这只能是在你使用了Class.forName(String, boolean, ClassLoader)这个3参数的方法的时候才能办到.<o:p></o:p>
隐藏的 Class.forName() 方法
你一定用过Java中X.class的语法去获取一个在编译器就知道名字的类对象实例. 在字节码的层次上, 这一点是如何实现的就不被人熟知了. 不同的编译器有不同的实例细节, 但共同点是, 所有编译器所相应产生的代码都是调用的Class.forName(String)这一个参数的方法. 比如J2SE <st1:chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False">1.4.1</st1:chsdate>的javac就把Class cls = X.class; 翻译成如下等价的形式:<o:p></o:p>
<v:shape id="_x0000_i1026" style="WIDTH: 11.25pt; HEIGHT: 15pt" alt="" type="#_x0000_t75"><v:imagedata o:href="/Images/dot.gif" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"></v:imagedata></v:shape>
// This is how "Class cls = X.class" is transformed:
if ( class $Main$X == null )
{
class $Main$X = class $ ("Main$X");
}
Class cls = class $Main$X;
<v:shape id="_x0000_i1027" style="WIDTH: 11.25pt; HEIGHT: 15pt" alt="" type="#_x0000_t75"><v:imagedata o:href="/Images/dot.gif" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"></v:imagedata></v:shape>
static Class class $ (String s)
{
try
{
return Class.forName (s);
}
catch (ClassNotFoundException e)
{
throw new NoClassDefFoundError (e.getMessage());
}
}
static Class class $Main$X; // A synthetic field created by the compiler <o:p></o:p>
跟 Sun 的 javac 开个玩笑
从上面的例子你可以看到, 编译器调用Class.forName()方法加载类对象, 并将其缓存到一个包内可见的静态变量中. 这种令人费解的实现方式的可能是因为在早期版本的Java中, 这种X.class的语法还未被支持, so the feature was added on top of the Java 1.0 byte-code instruction set.(???)<o:p></o:p>
利用这一点, 你可以在编译器的开销上做一些有趣的事情. 用J2SE <st1:chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False">1.3.1</st1:chsdate>编译下面的代码片段: <o:p></o:p>
public class <st1:place w:st="on">Main</st1:place>
{
public static void main (String [] args) throws Exception
{
System.out.println ("String class: " + String. class );
class $java$lang$String = int . class ;
System.out.println ("String class: " + String. class );
}
static Class class $java$lang$String;
} // End of class <o:p></o:p>
运行它, 你会得到下面这个很荒谬的输出结果: <o:p></o:p>
>java <st1:place w:st="on">Main</st1:place><o:p></o:p>
String class: class java.lang.String<o:p></o:p>
String class: int<o:p></o:p>
在J2SE <st1:chsdate w:st="on" year="1899" month="12" day="30" islunardate="False" isrocdate="False">1.4.1</st1:chsdate>中, 上面的代码将不能被编译通过, 但你仍然可以用反射的方式戏弄它: <o:p></o:p>
public static void main (String [] args) throws Exception
{
System.out.println ("String class: " + String. class );
Main. class .getDeclaredField ("class$java$lang$String").set ( null , int . class );
System.out.println ("String class: " + String. class );
} <o:p></o:p>
<o:p> </o:p>
综上所述, 下次你再调用Class.forName()方法时, 你应该知道它的局限性可选的替代方案了. <o:p></o:p>
<o:p> </o:p>
发表评论
-
求数组最大连续子段和
2011-12-16 16:26 0给定n个整数的数组a[](有正有负),求其最大连续子段和。例如 ... -
Memory Leaks in Java
2011-12-09 14:01 0http://olex.openlogic.com/wazi/ ... -
Hash相关的一些东西
2011-12-01 15:27 0http://en.wikipedia.org/wiki/Ha ... -
二分查找算法
2011-11-28 14:38 745摘自java.util.Arrays的代码: ... -
序列化到底是怎么回事
2011-12-04 22:16 1385有感:花了7年多时间才感悟到什么样才是一个真正的程序员。 “ ... -
单例到底是怎么回事
2011-12-06 14:08 892主要参考:http://www.javaw ... -
动态代理
2011-11-17 16:25 0http://www.ibm.com/developerwor ... -
【点滴】关于instanceof
2011-11-17 12:00 726Object a = null; if (a ... -
Java实现常用算法
2011-11-15 20:17 794// 冒泡排序 public static voi ... -
Java企业应用开发核心知识体系概述
2011-11-12 10:15 01、基础 普遍感觉《 ... -
Java企业应用开发核心知识体系概述
2011-11-12 10:14 01、基础 普遍感觉《Java核心技术》要比《Thinking ... -
理解Java调试体系
2011-11-11 10:13 0http://www.ibm.com/developerwor ... -
Java I/O到底怎么回事
2011-11-09 22:46 0http://www.ibm.com/developerwor ... -
Socket到底是什么玩意儿
2011-11-10 20:52 1573Socket这个东西是网络编程绕不过去的一块儿,不过如果你不是 ... -
关于Java编码方面的问题
2011-11-07 21:12 1008可算有人好好把编码这事说明白了: 深入分析 J ... -
技术补习之序列化ID(serialVersionUID)
2007-07-27 17:42 3321简单来说,Java的序列化机制是通过在运行时判断类的seria ... -
技术细节之SimpleDateFormat线程安全问题
2007-05-21 14:36 3574Date formats are not synchroniz ... -
走出ClassLoader迷局(译)
2007-05-07 23:23 2235问 : 我什么时候应该使 ... -
Java EE at a glance
2007-04-30 14:29 12431 Java EE 5 1.1 Java Platform, ...
相关推荐
在这个项目中,“微信小程序三级分类动态加载数据”指的是在小程序中实现一个具有三层结构的分类系统,并且能够根据用户的操作动态加载各级别的分类数据。 首先,我们来看看核心的文件结构: 1. `app.js`:这是小...
在Java编程中,类动态加载是一项重要的技术,它允许程序在运行时根据需要加载新的类,从而提高了灵活性和可扩展性。这篇博客“Java类动态加载(一)——java源文件动态编译为class文件”可能主要探讨了如何在运行时...
在Java编程中,类动态加载是一项重要的特性,它允许程序在运行时加载未知或自定义的类。这个特性在某些场景下非常有用,如插件系统、热部署以及安全相关的利用。本文主要探讨了Java代码执行漏洞中类动态加载的应用,...
### Java类动态加载机制在铁路互联网售票中的设计与实现 #### 概述 随着铁路互联网售票系统的广泛应用,其面临着越来越高的并发访问压力。为解决这一问题,系统采用分布式内存数据库集群来存储和处理如余票查询、...
在“反射,动态加载指定类调用类中的方法”这个主题中,我们将深入探讨如何使用反射来实现动态加载和执行类的方法。首先,我们需要理解几个关键的反射API: 1. `Class<?>`: 这是所有Java类的通用表示,通过`Class....
在Java中,动态加载jar包的核心在于使用`java.lang.ClassLoader`类或其子类。ClassLoader是Java虚拟机(JVM)的一部分,负责将类的字节码加载到JVM中并转换为Class对象。默认情况下,JVM会使用系统类加载器来查找和...
使用自定义类加载器后,我们可以在程序运行时动态加载jar文件中的类。例如,如果我们有一个名为`com.example.Plugin`的插件类存在于jar文件中,可以这样加载: ```java String jarPath = "path_to_your_jar.jar"; ...
例如,`MemoryClassLoader.java`可能就是一个自定义类加载器的实现,它可以在内存中动态加载或更新类。 **JarinJAR**是一种打包技术,它可以将多个JAR文件打包成一个大的JAR文件。在热加载场景下,JarinJAR使得在...
点击动态加载图片,将会弹出当前文件夹,用户可以选择pc某一目录下的图标,点击确认后按钮上的图标将会即时更新。代码当前支持是ico格式,但包含了bmp格式图片的支持(该部分代码用#if 0 #else宏包含)!
在Java编程语言中,动态加载类机制是一种强大的功能,它允许程序在运行时根据需要加载新的类或资源,而不是在编译时确定所有类。这种技术对于提高软件的灵活性、可扩展性和模块化至关重要,特别是在大型系统和插件式...
### JAVA类加载机制与动态代理 #### 一、类加载机制 ##### 1.1 类加载的时机 类加载机制负责将描述类的数据从`.class`文件加载到内存,并进行必要的校验、转换解析和初始化,使之成为可以被Java虚拟机直接使用的...
动态加载DLL允许在不重新编译主程序的情况下添加、更新或移除功能,而动态加载WebService则使得应用程序能灵活地与远程服务进行交互,即使这些服务的接口可能在运行时发生变化。这两项技术在软件开发中都有广泛的...
动态添加选项卡和`Frame`是提高用户界面灵活性的重要方法,允许应用程序根据需求在运行时创建新的视图。下面我们将详细探讨如何在WPF中实现这一功能。 首先,我们需要理解`TabControl`的基本结构。`TabControl`由一...
4. **插件化开发**:动态加载有助于实现插件化架构,使得新功能可以通过添加新的插件模块来实现,降低维护成本。 实现APK动态加载涉及的技术包括: 1. ** DexClassLoader**:Android系统提供的类加载器,可以加载...
android服务端动态加载类。 在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势...
### Java反射机制与动态加载实例类 在Java中,反射是一种强大的工具,允许程序在运行时检查和修改其结构和行为。通过反射,我们可以动态地加载类、创建对象、访问和修改字段、调用方法等。本文将深入探讨Java反射...
在动态加载类后,反射可用于创建类的实例,调用方法,访问和修改字段,甚至执行私有成员的操作。 5. **代理(Proxy)**: Java的动态代理机制可以在运行时创建实现一组指定接口的新类。这在实现回调、事件监听或者...
首先,动态加载布局指的是在运行时根据需要创建和添加布局。这通常通过Java代码或者Kotlin代码来完成,而不是在XML布局文件中预先定义。这样做的好处是可以减少应用资源的占用,同时增加布局的动态性和适应性。例如...
1. ClassLoader重写:Android系统的类加载是通过ClassLoader来完成的,因此,要实现动态加载,我们需要自定义ClassLoader。通过对默认的 DexClassLoader 或 PathClassLoader 进行扩展,我们可以控制何时以及如何加载...