實現(xiàn)java動態(tài)機制

作為一個前端,我很慶幸js是動態(tài)語言叹哭,這樣就減少了類型檢查卑惜,而java這種高級語言是如何做的呢?

1 什么是java反射機制袋倔?

當程序運行時荚恶,允許改變程序結構或變量類型晰赞,這種語言稱為動態(tài)語言谈秫。我們認為java并不是動態(tài)語言惕橙,但是它卻有一個非常突出的動態(tài)相關機制雇庙,俗稱:反射谓形。

話不多說看代碼:

package Reflect;
 
/**
 * 通過一個對象獲得完整的包名和類名
 * */
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Demo demo=new Demo();
        System.out.println(demo.getClass().getName());
    }
}

等等demo.getClass()是干嘛的。状共。套耕。

在面向對象的世界里,萬事萬物皆是對象峡继。而在java語言中冯袍,static修飾的東西不是對象,但是它屬于類。普通的數(shù)據(jù)類型不是對象康愤,例如:int a = 5;它不是面向對象儡循,但是它有其包裝類 Integer 或者分裝類來彌補了它。除了以上兩種不是面向對象征冷,其余的包括類也有它的面向對象择膝,類是java.lang.Class的實例化對象(注意Class是大寫)。也就是說:Class A{}當我創(chuàng)建了A類检激,那么類A本身就是一個對象肴捉,誰的對象?java.lang.Class的實例對象叔收。

這里的F的實例化對象就可以用f表達出來齿穗。同理F類也是一個實例化對象,Class類的實例化對象饺律。我們可以理解為任何一個類都是Class類的實例化對象窃页,這種實例化對象有三種表示方法:

public class Demo(){
F f=new F();
//第一種表達方式
Class c1=F.class;//這種表達方式同時也告訴了我們任何一個類都有一個隱含的靜態(tài)成員變量class
//第二種表達方式
Class c2=f.getClass();//這種表達方式在已知了該類的對象的情況下通過getClass方法獲取
try {
c3 = Class.forName("com.text.F");//類的全稱
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
class F{}

到這里想必大家也知道反射到底是干嘛的,就是運行時獲取該類本身的Class复濒。

看一下如何通過c1創(chuàng)建F類的實例

Public class Demo1{
try {
Foo foo = (Foo)c1.newInstance();//foo就表示F類的實例化對象
foo.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}}
class F{
void print(){
}
}

注意這里c1.newInstance()出來的是Object類型脖卖,需要強轉。

通過無參構造實例化對象

package Reflect;
 
class Person{
     
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per=null;
        try {
            per=(Person)demo.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        per.setName("Rollen");
        per.setAge(20);
        System.out.println(per);
    }
}

但是注意一下巧颈,當我們把Person中的默認的無參構造函數(shù)取消的時候畦木,比如自己定義只定義一個有參數(shù)的構造函數(shù)之后,會出現(xiàn)錯誤:

public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }

上述代碼會報錯砸泛。馋劈。。那么問題來了晾嘶,一個類總有有參構造函數(shù)把妓雾,碰到這種情況如何使用反射呢?

package Reflect;
 
import java.lang.reflect.Constructor;
 
class Person{
     
    public Person() {
         
    }
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //取得全部的構造函數(shù)
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[0].newInstance();
            per2=(Person)cons[1].newInstance("Rollen");
            per3=(Person)cons[2].newInstance(20);
            per4=(Person)cons[3].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}

其實問題的關鍵是動態(tài)獲取Person的構造函數(shù)垒迂,他是一個數(shù)組對象械姻。

下面來幾個例子給大家講解下反射的實際應用:
1.獲取類的全部屬性

import java.lang.reflect.Modifier   //這個類需要引入
class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("===============本類屬性========================");
        // 取得本類的全部屬性
        Field[] field = demo.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 權限修飾符
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            // 屬性類型
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";");
        }
}

同時再看java.lang.Class類中也有同樣的一個方法:
int getModifiers()
返回此類或接口以整數(shù)編碼的 Java語言修飾符。

2.獲取類的全部方法

public class ClassUtil {
public static void printClassMethodMessage(Object obj){
//要獲取類的信息》》首先我們要獲取類的類類型
Class c = obj.getClass();

System.out.println("類的名稱是:"+c.getName());

//如果我們要獲得所有的方法机断,可以用getMethods()方法楷拳,這個方法獲取的是所有的Public的函數(shù),包括父類繼承而來的吏奸。如果我們要獲取所有該類自己聲明的方法欢揖,就可以用getDeclaredMethods()方法,這個方法是不問訪問權限的奋蔚。
Method[] ms = c.getMethods();//c.getDeclaredMethods()
//接下來我們拿到這些方法之后干什么她混?我們就可以獲取這些方法的信息烈钞,比如方法的名字。
//首先我們要循環(huán)遍歷這些方法
for(int i = 0; i < ms.length;i++){
//然后可以得到方法的返回值類型的類類型
Class returnType = ms[i].getReturnType();
//得到方法的返回值類型的名字
System.out.print(returnType.getName()+" ");
//得到方法的名稱
System.out.print(ms[i].getName()+"(");
//獲取參數(shù)類型--->得到的是參數(shù)列表的類型的類類型
Class[] paramTypes = ms[i].getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+",");
}
System.out.println(")");
}
}
}

obj.getClass().getMethods() 與 getDeclaredMethods()的區(qū)別坤按,一個是獲取所有包括繼承的毯欣,一個是自身有的方法。

class Person{
   public void eat(string str,integert ){

   }

   public string sing(string str){

   }
}

printClassMethodMessage(new Person())

1 .java.lang.string   eat   java.lang.string   java.lang.interger
2 .java.lang.string   sing  java.lang.string

3.如何動態(tài)調用方法

public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {   
     Class ownerClass = owner.getClass();   

     Class[] argsClass = new Class[args.length];   

     for (int i = 0, j = args.length; i < j; i++) {   

         argsClass[i] = args[i].getClass();   

     }   

      Method method = ownerClass.getMethod(methodName,argsClass);   
      return method.invoke(owner, args);   

}  

我們上面定義了一個呼喚類實例方法的方法臭脓。

class Person{
   public void say(string name,integert age ){
             print 'i am' + name + 'age is' + age
   }
}

invokeMethod(new Person(),'say',['sumail',18])
// i am sumail age is 18

注意傳參列表為數(shù)組酗钞,獲取方法是通過ownerClass.getMethod(methodName,argsClass)來得到。

最后來看一下一個用反射的工廠模式例子:
原始版本

interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
// 構造工廠類
// 也就是說以后如果我們在添加其他的實例的時候只需要修改工廠類就行了
class Factory{
    public static fruit getInstance(String fruitName){
        fruit f=null;
        if("Apple".equals(fruitName)){
            f=new Apple();
        }
        if("Orange".equals(fruitName)){
            f=new Orange();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Orange");
        f.eat();
    }
 
}

反射版本

package Reflect;
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Reflect.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

好處就是我省略了一些判斷語句来累,更加簡潔砚作。
好了,今天的講解就到這里嘹锁。偎巢。。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末兼耀,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子求冷,更是在濱河造成了極大的恐慌瘤运,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匠题,死亡現(xiàn)場離奇詭異拯坟,居然都是意外死亡,警方通過查閱死者的電腦和手機韭山,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門郁季,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人钱磅,你說我怎么就攤上這事梦裂。” “怎么了盖淡?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵年柠,是天一觀的道長。 經常有香客問我褪迟,道長冗恨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任味赃,我火速辦了婚禮掀抹,結果婚禮上,老公的妹妹穿的比我還像新娘心俗。我一直安慰自己傲武,他們只是感情好,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谱轨,像睡著了一般戒幔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上土童,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天诗茎,我揣著相機與錄音,去河邊找鬼献汗。 笑死敢订,一個胖子當著我的面吹牛,可吹牛的內容都是我干的罢吃。 我是一名探鬼主播楚午,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尿招!你這毒婦竟也來了矾柜?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤就谜,失蹤者是張志新(化名)和其女友劉穎怪蔑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丧荐,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡缆瓣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了虹统。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弓坞。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖车荔,靈堂內的尸體忽然破棺而出渡冻,到底是詐尸還是另有隱情,我是刑警寧澤忧便,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布菩帝,位于F島的核電站,受9級特大地震影響茬腿,放射性物質發(fā)生泄漏呼奢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一切平、第九天 我趴在偏房一處隱蔽的房頂上張望握础。 院中可真熱鬧,春花似錦悴品、人聲如沸禀综。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽定枷。三九已至孤澎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間欠窒,已是汗流浹背覆旭。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留岖妄,地道東北人型将。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像荐虐,于是被迫代替她去往敵國和親七兜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法福扬,類相關的語法腕铸,內部類的語法,繼承相關的語法铛碑,異常的語法狠裹,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)亚茬,斷路器,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 一:java概述:1浓恳,JDK:Java Development Kit刹缝,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,650評論 0 11
  • 那一年颈将,我21歲 想過自己是風梢夯, 再也無所畏懼。 想過自己是云晴圾, 飄到...
    讀楊小莫有感閱讀 204評論 0 0
  • “山清水秀”“鳥語花香”颂砸,這是我記憶里小學時最喜歡的兩個成語,喜歡清晨的微風死姚,喜歡穿過樹葉縫隙的陽光人乓,大自然總有使...
    伊心心心心閱讀 467評論 0 0