`
liliang205
  • 浏览: 993 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

JavaVM,反射机制与动态代理

阅读更多
Java程序的工作机制:Java对象都以单独的class文件存在,java虚拟机将其载入并执行其虚拟机指令。



Java虚拟机查找这些java对象:

java虚拟机根据class path来查找java对象,而虚拟机的class path又分为三层:

bootstrap:sun.boot.class.path

extension: java.ext.dirs

application: java.class.path

三个class path各有对应的classloader。由上而下形成父子关系

当程序中调用new指令,或者ClassLoader.load方法时。其顺序如下:

1. 首先查看application的classloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。

2. 首先查看extension的classloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。

3. 首先查看bootstrap的classloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。

4. 由bootstrap的classloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,接下一步。

5. 由extension的classloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,接下一步。

6. 由application的classloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,则抛出ClassNotFound的exception。



Java虚拟机加载这些java对象:

每个java虚拟机都在其启动时产生一个唯一的class heap,并把所有的class instance都分配在其中。其中每个类实例的信息又分两部分,fields域和methods域。每个类实例各自拥有fields,但同一个类的不同实例共享methods



反射

JVM对反射的处理

简单例子代码:

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.InvocationTargetException;

import java.io.IOException;



public class Main {

public static void main(String[] args){

TempImpl t1 = new TempImpl("temp1");

try {

Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;

t1Talk.invoke(t1, null);

} catch (NoSuchMethodException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

} catch (IllegalAccessException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

} catch (InvocationTargetException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

}

try {

System.in.read();

} catch (IOException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

}

}

}


复杂例子代码:

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.InvocationTargetException;

import java.io.IOException;



public class Main {

public static void main(String[] args){

TempImpl t1 = new TempImpl("temp1");

TempImpl t2 = new TempImpl("temp2");

Temp2 temp2 = new Temp2();

try {

Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;

Method t2Talk = t2.getClass().getMethod("Talk", new Class[0]) ;

t1Talk.invoke(t2, null);

t2Talk.invoke(t1, null);

if(t1Talk.equals(t2Talk)){

System.out.println("equals");

}

else{

System.out.println("not equals");

}

if(t1Talk==t2Talk){

System.out.println("ref equals");

}

else{

System.out.println("ref not equals");

}

t2Talk.invoke(temp2, null);

} catch (NoSuchMethodException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

} catch (IllegalAccessException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

} catch (InvocationTargetException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

}

try {

System.in.read();

} catch (IOException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

}

}

}




分析:java虚拟机把每个methods当作一个执行单元。该执行单元带有两种签名:类签名和属性签名(public,static等)。 反射的第一步,验证签名的合法性。验证通过后,顺序执行该method中的指令,当需要访问类实例的fields和传入参数时,由虚拟机注入。



动态代理

Sun对动态代理的说明:

一个简单例子代码:

动态代理的内部实现——代码生成:

研究JDK源代码,发现在Proxy的sun实现中调用了sun.misc.ProxyGenerator类的generateProxyClass( proxyName, interfaces)方法,其返回值为byte[]和class文件的内存类型一致。于是做如下试验:

public class ProxyClassFile{

public static void main(String[] args){

String proxyName = "TempProxy";

TempImpl t = new TempImpl("proxy");

Class[] interfaces =t.getClass().getInterfaces();



byte[] proxyClassFile = ProxyGenerator.generateProxyClass(

proxyName, interfaces);

File f = new File("classes/TempProxy.class");

try {

FileOutputStream fos = new FileOutputStream(f);

fos.write(proxyClassFile);

fos.flush();

fos.close();

} catch (FileNotFoundException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

} catch (IOException e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

}

}

}


运行该类,到class文件夹下,利用反编译技术,发现原来其采用了代码生产技术:



public interface Temp{

public void Talk();

public void Run();

}

import java.lang.reflect.*;



public final class TempProxy extends Proxy

implements Temp{



private static Method m4;

private static Method m2;

private static Method m0;

private static Method m3;

private static Method m1;



public TempProxy(InvocationHandler invocationhandler) {

super(invocationhandler);

}



public final void Run() {

try {

h.invoke(this, m4, null);

return;

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}



public final String toString(){

try{

return (String)h.invoke(this, m2, null);

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

return "";

}



public final int hashCode() {

try {

return ((Integer)h.invoke(this, m0, null)).intValue();

}

catch(Error _ex) { }

catch(Throwable throwable){

throw new UndeclaredThrowableException(throwable);

}

return 123;

}



public final void Talk(){

try{

h.invoke(this, m3, null);

return;

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}



public final boolean equals(Object obj) {

try {

return ((Boolean)h.invoke(this, m1, new Object[] {

obj

})).booleanValue();

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

return false;

}



static{

try{

m4 = Class.forName("Temp").getMethod("Run", new Class[0]);

m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);

m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);

m3 = Class.forName("Temp").getMethod("Talk", new Class[0]);

m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {

Class.forName("java.lang.Object")

});

}

catch(NoSuchMethodException nosuchmethodexception) {

throw new NoSuchMethodError(nosuchmethodexception.getMessage());

}

catch(ClassNotFoundException classnotfoundexception) {

throw new NoClassDefFoundError(classnotfoundexception.getMessage());

}

}

}

技术交流群:30704235
欢迎大家共同交流
分享到:
评论
2 楼 liliang205 2007-12-20  
下次会好些的...第一次发贴,不要见怪!
1 楼 eivenchan 2007-12-18  
代码好乱,格式化一下的话会好看很多。

相关推荐

    Java2024突击面试手册(备战2024)

    然而,由于Java的动态特性,如动态代理、动态字节码生成等,JIT编译器仍然是必要的,因为它能更好地适应运行时的变化。 综上所述,对于准备2024年Java面试的工程师来说,全面理解Java基础、JVM的工作原理、JDK和JRE...

    计算机专业基础理论电子书合集06----编程语言:java (2)

    本电子书合集是针对计算机专业基础理论中的编程语言部分,特别是聚焦于Java语言的深入学习,涵盖了多个方面的知识,包括JVM原理、反射机制、多线程等内容。以下是这些书籍涉及的一些关键知识点: 1. **Java编程语言...

    JAVA性能优化.docJAVA性能优化.doc

    - **代码质量**:编写高效、简洁的代码是基础,避免过度使用反射、动态代理等高级特性,因为它们可能带来额外的性能开销。 - **数据结构和算法**:选择合适的数据结构和算法可以极大提升程序效率,例如,使用...

    jdk-11.0.10 src.zip

    通过这些源代码,开发者可以学习到Java内存管理、线程调度、网络编程、I/O操作、安全管理、类加载机制、反射机制等多个关键领域的实现细节。同时,了解JVM的内部工作原理,有助于优化代码性能,解决复杂问题,以及...

    Java发展史_&_Java9、10新特性

    ### Java发展史与Java 9、10新特性详解 #### Java发展史 Java自1995年由Sun Microsystems发布以来,历经多个版本的发展和完善,成为当今最受欢迎的编程语言之一。下面简要回顾Java的发展历程及其重要里程碑: - *...

    spring-cglib-repack-3.2.4.jar和spring-objenesis-repack-2.5.1.jar

    1. 高性能:相对于其他动态代理库(如Java的反射API或JDK动态代理),CGLIB的代理效率更高。 2. 易于使用:Spring框架已经封装了CGLIB的使用,开发者通常不需要直接与CGLIB库交互。 `spring-objenesis-repack-2.5.1...

    详解java类命周期.doc

    在这一阶段,可以通过反射机制获取类的`Class`对象,访问其成员变量和方法。 #### 六、卸载阶段(Unloading) 类的卸载通常发生在应用程序退出或系统资源紧张时。JVM通过垃圾回收机制自动释放不再使用的类资源。类...

    jdk11的源码src文件

    它包含了Java代理服务器和通信机制,使得开发者可以远程控制和监控应用的运行状态。 2. **java.prefs**: Java首选项API(Preferences API)位于这个模块中,提供了一种跨平台的方式来存储用户和系统偏好设置。它...

    jdk源码包jdk-11.0.1

    10. **jdk.dynalink**:动态链接库,提供了一种方式来在运行时动态绑定方法调用,通常用于实现动态语言的功能或者高效的反射机制。 通过研究这些源码,开发者可以提升对Java平台的理解,学习如何优化代码,解决性能...

    android Hook DEmo

    这两种 VM 都支持字节码级别的 Hook,例如,我们可以使用 Art 或 Dalvik 的代理类机制(Proxy Classes)或者利用 JVMTI(Java Virtual Machine Tool Interface)进行 Hook。在 Art 中,我们可以使用 MethodHandle 和...

    VMTranslator

    VMTranslator可能使用了一些关键的Java技术,例如反射(Reflection)、动态代理(Dynamic Proxy)、注解处理器(Annotation Processor)等。反射允许程序在运行时检查和修改自身的结构和行为,动态代理可以创建接口...

    JDK 1.6 帮助手册

    动态代理允许在运行时创建代理类和接口的实例,提供了一种灵活的方式来实现回调或者事件监听等功能。 ### 7. 反射(Reflection) 反射API在JDK 1.6中也得到了加强,可以更方便地在运行时检查类、接口、字段和方法...

    资深程序员的Java面试题总结汇总.pdf

    3. 动态代理用于在运行时创建一个实现一组给定接口的新类,常用于AOP(面向切面编程)或回调处理。 4. 动态代理可通过实现InvocationHandler接口和使用Proxy类来实现。 五、对象拷贝 1. 克隆用于复制对象,创建一个...

    jdk:jdk源码阅读

    6. **反射**:理解反射机制,可以动态地获取类的信息并操控对象,广泛应用于插件化、序列化、动态代理等场景。 7. **异常处理**:理解异常的分类、捕获和抛出机制,以及Checked异常和Unchecked异常的区别,有助于...

Global site tag (gtag.js) - Google Analytics