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());
}
}
}