Java 程序的工作機(jī)制: Java 對象都以單獨(dú)的 class 文件存在, java 虛擬機(jī)將其載入并執(zhí)行其虛擬機(jī)指令。
Java 虛擬機(jī)查找這些 java 對象:
java 虛擬機(jī)根據(jù) class path 來查找 java 對象,而虛擬機(jī)的 class path 又分為三層:
bootstrap : sun.boot.class.path
extension: java.ext.dirs
application: java.class.path
三個 class path 各有對應(yīng)的 classloader 。由上而下形成父子關(guān)系
當(dāng)程序中調(diào)用 new 指令,或者 ClassLoader.load 方法時。其順序如下:
1.?????? 首先查看 application 的 classloader 中是否已有對應(yīng)的 class 緩存,如果有則返回,并根據(jù) class 分配內(nèi)存。如果沒有,接下一步。
2.?????? 首先查看 extension 的 classloader 中是否已有對應(yīng)的 class 緩存,如果有則返回,并根據(jù) class 分配內(nèi)存。如果沒有,接下一步。
3.?????? 首先查看 bootstrap 的 classloader 中是否已有對應(yīng)的 class 緩存,如果有則返回,并根據(jù) class 分配內(nèi)存。如果沒有,接下一步。
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 虛擬機(jī)加載這些 java 對象:
每個 java 虛擬機(jī)都在其啟動時產(chǎn)生一個唯一的 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 ??? 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. ??????? } ??? } } |
復(fù)雜例子代碼:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.io.IOException;
public class ??? 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 虛擬機(jī)把每個 methods 當(dāng)作一個執(zhí)行單元。該執(zhí)行單元帶有兩種簽名:類簽名和屬性簽名( public , static 等)。 反射的第一步,驗證簽名的合法性。驗證通過后,順序執(zhí)行該 method 中的指令,當(dāng)需要訪問類實例的 fields 和傳入?yún)?shù)時,由虛擬機(jī)注入。
動態(tài)代理
Sun 對動態(tài)代理的說明:
一個簡單例子代碼:
動態(tài)代理的內(nèi)部實現(xiàn)——代碼生成:
研究 JDK 源代碼,發(fā)現(xiàn)在 Proxy 的 sun 實現(xiàn)中調(diào)用了 sun.misc.ProxyGenerator 類的 generateProxyClass( proxyName, interfaces) 方法,其返回值為 byte[] 和 class 文件的內(nèi)存類型一致。于是做如下試驗:
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. ??????? } ?????? } } |
運(yùn)行該類,到 class 文件夾下,利用反編譯技術(shù),發(fā)現(xiàn)原來其采用了代碼生產(chǎn)技術(shù):
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());
??????? }
??? }
} |
ok
我用的jd-gui.exe反編譯出現(xiàn)下面的情況
// ERROR //
public final java.lang.String toString()
throws
{
// Byte code:
// 0: aload_0
// 1: getfield 16 java/lang/reflect/Proxy:h Ljava/lang/reflect/InvocationHandler;
// 4: aload_0
// 5: getstatic 42 TempProxy:m2 Ljava/lang/reflect/Method;
// 8: aconst_null
// 9: invokeinterface 26 4 0
// 14: checkcast 44 java/lang/String
// 17: areturn
// 18: athrow
// 19: astore_1
// 20: new 34 java/lang/reflect/UndeclaredThrowableException
// 23: dup
// 24: aload_1
// 25: invokespecial 37 java/lang/reflect/UndeclaredThrowableException:<init> (Ljava/lang/Throwable;)V
// 28: athrow
//
// Exception table:
// from to target type
// 0 18 18 java/lang/RuntimeException
// 0 18 18 java/lang/Error
// 0 18 19 java/lang/Throwable
}
// ERROR //
public final int hashCode()
throws
{
// Byte code:
// 0: aload_0
// 1: getfield 16 java/lang/reflect/Proxy:h Ljava/lang/reflect/InvocationHandler;
// 4: aload_0
// 5: getstatic 49 TempProxy:m0 Ljava/lang/reflect/Method;
// 8: aconst_null
// 9: invokeinterface 26 4 0
// 14: checkcast 51 java/lang/Integer
// 17: invokevirtual 54 java/lang/Integer:intValue ()I
// 20: ireturn
// 21: athrow
// 22: astore_1
// 23: new 34 java/lang/reflect/UndeclaredThrowableException
// 26: dup
// 27: aload_1
// 28: invokespecial 37 java/lang/reflect/UndeclaredThrowableException:<init> (Ljava/lang/Throwable;)V
// 31: athrow
//
// Exception table:
// from to target type
// 0 21 21 java/lang/RuntimeException
// 0 21 21 java/lang/Error
// 0 21 22 java/lang/Throwable
}
// ERROR //