电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

JVM技术,反射与动态代理


发布日期:2022/1/11
 

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

Java虚拟机查找这些java对象

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

bootstrapsunbootclasspath

extension: javaextdirs

application: javaclasspath

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

当程序中调用new指令或者ClassLoaderload方法时其顺序如下

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

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

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

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

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

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

Java虚拟机加载这些java对象

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

反射

JVM对反射的处理

简单例子代码

import javalangreflectInvocationHandler;

import javalangreflectMethod;

import javalangreflectInvocationTargetException;

import javaioIOException;

public class Main {

public static void main(String[] args){

TempImpl t = new TempImpl(temp);

try {

Method tTalk = tgetClass()getMethod(Talk new Class[]) ;

tTalkinvoke(t null);

} catch (NoSuchMethodException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

} catch (IllegalAccessException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

} catch (InvocationTargetException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

}

try {

Systeminread();

} catch (IOException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

}

}

}

复杂例子代码

import javalangreflectInvocationHandler;

import javalangreflectMethod;

import javalangreflectInvocationTargetException;

import javaioIOException;

public class Main {

public static void main(String[] args){

TempImpl t = new TempImpl(temp);

TempImpl t = new TempImpl(temp);

Temp temp = new Temp();

try {

Method tTalk = tgetClass()getMethod(Talk new Class[]) ;

Method tTalk = tgetClass()getMethod(Talk new Class[]) ;

tTalkinvoke(t null);

tTalkinvoke(t null);

if(tTalkequals(tTalk)){

Systemoutprintln(equals);

}

else{

Systemoutprintln(not equals);

}

if(tTalk==tTalk){

Systemoutprintln(ref equals);

}

else{

Systemoutprintln(ref not equals);

}

tTalkinvoke(temp null);

} catch (NoSuchMethodException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

} catch (IllegalAccessException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

} catch (InvocationTargetException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

}

try {

Systeminread();

} catch (IOException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

}

}

}

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

动态代理

Sun对动态代理的说明

一个简单例子代码

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

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


public class ProxyClassFile{

public static void main(String[] args){

String proxyName = TempProxy;

TempImpl t = new TempImpl(proxy);

Class[] interfaces =tgetClass()getInterfaces();

byte[] proxyClassFile = ProxyGeneratorgenerateProxyClass(

proxyName interfaces);

File f = new File(classes/TempProxyclass);

try {

FileOutputStream fos = new FileOutputStream(f);

foswrite(proxyClassFile);

fosflush();

fosclose();

} catch (FileNotFoundException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

} catch (IOException e) {

eprintStackTrace(); //To change body of catch statement use File | Settings | File Templates

}

}

}

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

public interface Temp{

public void Talk();

public void Run();

}

import javalangreflect*;

public final class TempProxy extends Proxy

implements Temp{

private static Method m;

private static Method m;

private static Method m;

private static Method m;

private static Method m;

public TempProxy(InvocationHandler invocationhandler) {

super(invocationhandler);

}

public final void Run() {

try {

hinvoke(this m null);

return;

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}

public final String toString(){

try{

return (String)hinvoke(this m null);

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

return ;

}

public final int hashCode() {

try {

return ((Integer)hinvoke(this m null))intValue();

}

catch(Error _ex) { }

catch(Throwable throwable){

throw new UndeclaredThrowableException(throwable);

}

return ;

}

public final void Talk(){

try{

hinvoke(this m null);

return;

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

}

public final boolean equals(Object obj) {

try {

return ((Boolean)hinvoke(this m new Object[] {

obj

}))booleanValue();

}

catch(Error _ex) { }

catch(Throwable throwable) {

throw new UndeclaredThrowableException(throwable);

}

return false;

}

static{

try{

m = ClassforName(Temp)getMethod(Run new Class[]);

m = ClassforName(javalangObject)getMethod(toString new Class[]);

m = ClassforName(javalangObject)getMethod(hashCode new Class[]);

m = ClassforName(Temp)getMethod(Talk new Class[]);

m = ClassforName(javalangObject)getMethod(equals new Class[] {

ClassforName(javalangObject)

});

}

catch(NoSuchMethodException nosuchmethodexception) {

throw new NoSuchMethodError(nosuchmethodexceptiongetMessage());

}

catch(ClassNotFoundException classnotfoundexception) {

throw new NoClassDefFoundError(classnotfoundexceptiongetMessage());

}

}

}

上一篇:关于JFreeChart的二三事

下一篇:编程方式部署jBPM工作流