RTTI的一個(gè)例子:

Shape對(duì)象具體的draw邏輯是由引用所指向的具體對(duì)象Circle,Square或者Triangle決定的,這就是多態(tài)。
java在運(yùn)行時(shí)識(shí)別類和對(duì)象的信息主要有兩種方式:
- 傳統(tǒng)的“RTTI”,在編譯時(shí)已知道了所有的類型
- java 反射,在運(yùn)行時(shí)發(fā)現(xiàn)和使用類的信息
Class
Java使用Class對(duì)象來執(zhí)行器RTTI,Class對(duì)象是用來描述類信息的特殊對(duì)象,每個(gè)類都對(duì)應(yīng)一個(gè)Class對(duì)象(被保存在同名的.class文件中)。可通過Class.forName(類的全限定名)或者類名.class獲取Class對(duì)象的引用,通過引用創(chuàng)建類的示例。
所有的類都是在對(duì)其第一次使用時(shí),動(dòng)態(tài)加載到JVM中的。當(dāng)程序創(chuàng)建第一個(gè)對(duì)類的靜態(tài)成員的引用時(shí),就會(huì)加載這個(gè)類。這個(gè)證明構(gòu)造器也是類的靜態(tài)方法,即使在構(gòu)造器之前并沒有使用static關(guān)鍵字。因此,使用new操作符創(chuàng)建類的新對(duì)象也會(huì)被當(dāng)做對(duì)類的靜態(tài)成員的引用。因此,java程序在它開始運(yùn)行之前并非完全加載,其各個(gè)部分是在必需時(shí)才加載的。
為了使用類而做的準(zhǔn)備工作包含3個(gè)步驟:
- 加載 這是由JVM上的加載器執(zhí)行的,該步驟將查找字節(jié)碼并創(chuàng)建一個(gè)Class對(duì)象
- 鏈接 驗(yàn)證靜態(tài)類中的字節(jié)碼,為靜態(tài)域分配存儲(chǔ)空間。如果必須的話,解析這個(gè)類創(chuàng)建的對(duì)其它類的引用
- 初始化 如果該類具有超類,則對(duì)其進(jìn)行初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。
java反射
RTTI與反射之間的區(qū)別僅在于,RTTI在編譯時(shí)已知道類的所有信息,而對(duì)于反射機(jī)制來說,.class文件在編譯時(shí)是不可獲取的,而是在運(yùn)行階段發(fā)現(xiàn)或獲取類的信息。
Class類與java.lang.reflect類庫(kù)一起對(duì)反射的概念進(jìn)行了支持,該類庫(kù)包含了Fileld,Method以及Constructor類。這些類型的信息是有JVM在運(yùn)行時(shí)創(chuàng)建的,用以表示未知類里的成員。這樣就可以使用Constructor創(chuàng)建新的隊(duì)形,用get()方法和set()方法讀取和修改與Field對(duì)象關(guān)聯(lián)的字段,用invoke()方法調(diào)用與Method對(duì)象關(guān)聯(lián)的方法。這樣,匿名的對(duì)象就能在運(yùn)行時(shí)被完全確定下來,而在編譯時(shí)不需要知道任何事情。
動(dòng)態(tài)代理
動(dòng)態(tài)代理是一種在運(yùn)行時(shí)構(gòu)建動(dòng)態(tài)代理、動(dòng)態(tài)處理代理方法調(diào)用的機(jī)制,從而在運(yùn)行時(shí)實(shí)現(xiàn)調(diào)用者和實(shí)現(xiàn)者的解耦。下面是JDK 動(dòng)態(tài)代理的一個(gè)簡(jiǎn)單例子:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyDynamicProxy {
public static void main(String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello(){
System.out.println("Hello world");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoking sayHello");
Object result = method.invoke(target, args);
return result;
}
}
動(dòng)態(tài)代理機(jī)制可以動(dòng)態(tài)地創(chuàng)建代理并動(dòng)態(tài)地處理對(duì)所代理方法的調(diào)用。在動(dòng)態(tài)代理上所做的所有調(diào)用都會(huì)被重定向到單一的調(diào)用處理器上,如
上例的MyInvocationHandler。