Java 反射機(jī)制的應(yīng)用

上一篇文章介紹了 Java 反射機(jī)制的源頭 Class 類摊腋,今天我們來了解如何通過一個(gè)給定的字符串(包.類)的路徑來實(shí)例化一個(gè)類的對象嘁傀,以及通過反射得到一個(gè)類的具體結(jié)構(gòu)细办。

一笑撞、Class.forName() 方法實(shí)例化類的對象

1茴肥、通過無參構(gòu)造方法實(shí)例化對象

通過一個(gè)給定的字符串(包.類)的路徑瓤狐,我們可以利用 Class.forName() 方法獲取到給的的類,然后通過調(diào)用該類的 newInstance() 方法實(shí)例化此類的對象荧缘,這樣就取代了使用 new 關(guān)鍵字實(shí)例化對象的操作方式截粗。

通過調(diào)用類的 newInstance() 方法實(shí)例化類的對象绸罗,需要特別注意一點(diǎn)掰派,就是必須要保證被實(shí)例化的類中存在一個(gè)無參的構(gòu)造方法左痢,如果不存在無參構(gòu)造方法俊性,是無法使用 newInstance() 方法實(shí)例化類的對象的定页。

反射的大部分操作基本上都是調(diào)用無參構(gòu)造方法典徊,因此卒落,提倡大家在開發(fā)中儡毕,一定要在類中編寫無參的構(gòu)造方法腰湾。

@Test
  public void test1() throws Exception {
    String className = "com.jpm.reflection.User";
    Class<?> clazz = Class.forName(className);
    // 創(chuàng)建運(yùn)行時(shí)類的對象费坊,需要運(yùn)行時(shí)類有空的構(gòu)造函數(shù)
    Object obj = clazz.newInstance();
    System.out.println(obj);
  }

User 類的代碼上一篇文章里有,本次為了節(jié)省篇幅导犹,就不再重復(fù)提供源碼了:


運(yùn)行結(jié)果:

User [name=null, age=0]

2磕昼、通過有參構(gòu)造方法實(shí)例化對象

雖然一般我們使用無參的構(gòu)造方法來實(shí)例化類的對象票从,但是我們依然可以用有參構(gòu)造方法來實(shí)例化對象峰鄙,此時(shí)吟榴,需要用到 java.lang.reflect.Constructor 類囊扳,它表示構(gòu)造方法锥咸,首先通過 Class 類的 getConstructors() 方法狭瞎,獲得本類中所有構(gòu)造方法,通過調(diào)用構(gòu)造方法的 newInstance(Object ... initargs) 方法搏予,傳遞一個(gè)可變對象參數(shù)熊锭,完成對象的實(shí)例化操作。

@Test
  public void test2() throws Exception {
    String className = "com.jpm.reflection.User";
    Class clazz = Class.forName(className);
    // 通過反射獲取所有構(gòu)造方法
    Constructor[] con = clazz.getConstructors();
    for (Constructor c : con) {
      System.out.println("獲取到的構(gòu)造方法:" + c);
    }
    // 通過2個(gè)參數(shù)的構(gòu)造方法創(chuàng)建對象
    Object obj = con[0].newInstance("JPM", 20);
    System.out.println(obj);
  }

運(yùn)行結(jié)果:

獲取到的構(gòu)造方法:public com.jpm.reflection.User(java.lang.String,int)
獲取到的構(gòu)造方法:public com.jpm.reflection.User(java.lang.String)
獲取到的構(gòu)造方法:public com.jpm.reflection.User()
User [name=JPM, age=20]

二雪侥、通過反射取得類的結(jié)構(gòu)

通過反射可以得到一個(gè)類的完整結(jié)構(gòu)碗殷,需要使用到 java.lang.reflect 包中的以下類:
Constructor:表示類中的構(gòu)造方法
Field:表示類中的屬性
Method:表示類中的方法

下面為了演示反射的例子,我們提供一個(gè) Person 類:

public class Person implements Comparable<Object> {

  public String name;
  private int age;
  int sex;

  // 創(chuàng)建類時(shí)盡量寫一個(gè)空參的構(gòu)造器
  public Person() {
    super();
  }

  public Person(String name) {
    super();
    this.name = name;
  }

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

  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 "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
  }

  public void show() {
    System.out.println("show method run!");
  }

  private void display(String address) throws Exception {
    System.out.println("display method run速缨,address=" + address);
  }

  private String display1(String address, Integer i) throws Exception {
    System.out.println("display method run,address=" + address);
    return address + i;
  }

  public static void info() {
    System.out.println("info method run!");
  }

  @Override
  public int compareTo(Object o) {
    return 0;
  }

}

1鸟廓、獲取類實(shí)現(xiàn)的接口

獲取類所實(shí)現(xiàn)的全部接口从祝,可以使用 Class 類中 的 getInterfaces() 方法,接口是類的特殊形式引谜,而且一個(gè)類可以實(shí)現(xiàn)多個(gè)接口牍陌,所以 getInterfaces() 方法返回的是 Class 數(shù)組的形式。

public void test1() {
    Class clazz = Person.class;
    // 獲取實(shí)現(xiàn)的接口
    Class[] interfaces = clazz.getInterfaces();
    for (Class class1 : interfaces) {
      System.out.println(class1.getName());
    }
  }

運(yùn)行結(jié)果:

java.lang.Comparable

2员咽、獲取類繼承的父類

一個(gè)類可以實(shí)現(xiàn)多個(gè)接口毒涧,但是只能繼承一個(gè)父類,所以如果要獲取一個(gè)類的父類贝室,可以使用 Class 類中的 getSuperclass() 方法契讲,可以通過 getName() 方法取得名稱仿吞。

@Test
  public void test2() throws ClassNotFoundException {
    Class<?> clazz = Class.forName("com.jpm.reflection.Person");
    // 獲取運(yùn)行時(shí)類的父類
    Class<?> sc = clazz.getSuperclass();
    System.out.println(sc.getName());
  }

運(yùn)行結(jié)果:

java.lang.Object

3、獲取類中的構(gòu)造方法

獲取一個(gè)類中的構(gòu)造方法捡偏,可以使用 getConstructors() 方法獲取 public 修飾的構(gòu)造方法唤冈,使用 getDeclaredConstructors() 可以獲取所有的構(gòu)造方法。

@Test
  public void test3() throws Exception {
    String className = "com.jpm.reflection.Person";
    Class clazz = Class.forName(className);

    System.out.println("獲取類的public構(gòu)造方法");
    Constructor[] con = clazz.getConstructors();
    for (Constructor c : con) {
      System.out.println(c);
    }
    System.out.println("獲取類的所有構(gòu)造方法");
    // 使用Declared可以獲取私有的構(gòu)造方法
    con = clazz.getDeclaredConstructors();
    for (Constructor c : con) {
      System.out.println(c);
    }
  }

運(yùn)行結(jié)果:

獲取類的public構(gòu)造方法
public com.jpm.reflection.Person(java.lang.String)
public com.jpm.reflection.Person()
獲取類的所有構(gòu)造方法
com.jpm.reflection.Person(java.lang.String,int)
public com.jpm.reflection.Person(java.lang.String)
public com.jpm.reflection.Person()

4银伟、獲取類中的屬性

獲取一個(gè)類中的屬性你虹,使用 getFields() 只能獲取到運(yùn)行時(shí)類及其父類中聲明為public 的屬性,使用 getDeclaredFields() 獲取到運(yùn)行時(shí)類本身聲明的所有屬性彤避。

@Test
  public void Test4() {
    Class clazz = Person.class;
    // 1.getFields()只能獲取到運(yùn)行時(shí)類及其父類中聲明為public的屬性
    Field[] fields = clazz.getFields();
    for (int i = 0; i < fields.length; i++) {
      System.out.println(fields[i].getName());
    }
    System.out.println();
    // 2.getDeclaredFields()獲取到運(yùn)行時(shí)類本身聲明的所有屬性
    Field[] fields1 = clazz.getDeclaredFields();
    for (Field field : fields1) {
      System.out.println(field.getName());
    }
  }  

運(yùn)行結(jié)果:

name

name
age
sex

下面的例子演示如何為一個(gè)類的屬性賦值:

@Test
  public void Test5() throws Exception
 {
    Class clazz = Person.class;
    // 1傅物、獲取指定的public屬性,getField
    Field name = clazz.getField("name");
    // 2琉预、創(chuàng)建運(yùn)行時(shí)類的對象
    Person p = (Person) clazz.newInstance();
    System.out.println(p);
    // 3董饰、運(yùn)行時(shí)類的指定屬性賦值
    name.set(p, "jpm");
    System.out.println(p);
    // 4、獲取運(yùn)行時(shí)類中的所有屬性圆米,getDeclaredField
    Field age = clazz.getDeclaredField("age");
    // 使私有屬性可以被操作
    age.setAccessible(true);
    age.set(p, 18);
    System.out.println(p);
  }

運(yùn)行結(jié)果:

Person [name=null, age=0, sex=0]
Person [name=jpm, age=0, sex=0]
Person [name=jpm, age=18, sex=0]

5卒暂、獲取類中的方法

獲取一個(gè)類中的方法,使用 getMethods() 只能獲取運(yùn)行時(shí)類及其父類中所有的聲明為 public 的方法榨咐,使用 getDeclaredMethods() 獲取運(yùn)行時(shí)本身聲明的所有的方法介却。

public void test1() {
    Class clazz = Person.class;
    // 1谴供、getMethods()獲取運(yùn)行時(shí)類及其父類中所有的聲明為public的方法
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
      System.out.println(method);
    }
    System.out.println();
    // 2块茁、getDeclaredMethods()獲取運(yùn)行時(shí)本身聲明的所有的方法
    Method[] methods1 = clazz.getDeclaredMethods();
    for (Method method : methods1) {
      System.out.println(method);
    }
  }

運(yùn)行結(jié)果:

public java.lang.String com.jpm.reflection.Person.toString()
public int com.jpm.reflection.Person.compareTo(java.lang.Object)
public java.lang.String com.jpm.reflection.Person.getName()
public void com.jpm.reflection.Person.setName(java.lang.String)
public void com.jpm.reflection.Person.show()
public static void com.jpm.reflection.Person.info()
public int com.jpm.reflection.Person.getAge()
public void com.jpm.reflection.Person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

public java.lang.String com.jpm.reflection.Person.toString()
public int com.jpm.reflection.Person.compareTo(java.lang.Object)
public java.lang.String com.jpm.reflection.Person.getName()
public void com.jpm.reflection.Person.setName(java.lang.String)
public void com.jpm.reflection.Person.show()
private void com.jpm.reflection.Person.display(java.lang.String) throws java.lang.Exception
public static void com.jpm.reflection.Person.info()
public int com.jpm.reflection.Person.getAge()
public void com.jpm.reflection.Person.setAge(int)

6、獲取屬性的各個(gè)部分的內(nèi)容

獲取每個(gè)屬性的權(quán)限修飾符 getModifiers()
獲取屬性的變量類型 getType()
獲取屬性名 getName()

@Test
  public void Test2() {
    Class clazz = Person.class;
    Field[] fields1 = clazz.getDeclaredFields();
    for (Field field : fields1) {
      // 1桂肌、獲取每個(gè)屬性的權(quán)限修飾符
      int i = field.getModifiers();
      String str = Modifier.toString(i);
      System.out.print(str + " ");
      // 2数焊、獲取屬性的變量類型
      Class type = field.getType();
      System.out.print(type.getName() + " ");
      // 3、獲取屬性名
      System.out.println(field.getName());
    }
  }

運(yùn)行結(jié)果:

public java.lang.String name
private int age
 int sex

7崎场、獲取方法的各個(gè)部分的內(nèi)容

獲取每個(gè)方法的權(quán)限修飾符 getModifiers()
獲取方法的返回值類型 getReturnType()
獲取方法的名稱 getName()
獲取方法的參數(shù)類型 getParameterTypes()
獲取方法的異常 getExceptionTypes()

@Test
  public void test222() {
    Class clazz = Person.class;
    Method[] methods1 = clazz.getDeclaredMethods();
    for (Method method : methods1) {
      // 1佩耳、權(quán)限修飾符
      String str = Modifier.toString(method.getModifiers());
      System.out.print(str + " ");
      // 2、返回值類型
      Class returnType = method.getReturnType();
      System.out.print(returnType + " ");
      // 3谭跨、方法名
      System.out.print(method.getName() + " ");
      // 4干厚、形參列表
      System.out.print("(");
      Class[] params = method.getParameterTypes();
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < params.length; i++) {
        sb.append(params[i].getName() + " args-" + i + ", ");
      }
      if (sb.length() != 0) {
        System.out.print(sb.substring(0, sb.lastIndexOf(", ")));
      }
      System.out.print(")");
      // 5、異常
      Class[] exceptions = method.getExceptionTypes();
      if (exceptions.length != 0) {
        System.out.print("throws ");
      }
      for (Class e : exceptions) {
        System.out.print(e.getName());
      }

      System.out.println();
    }
  }

運(yùn)行結(jié)果:

public class java.lang.String toString ()
public int compareTo (java.lang.Object args-0)
public class java.lang.String getName ()
public void setName (java.lang.String args-0)
public void show ()
public static void info ()
private void display (java.lang.String args-0)throws java.lang.Exception
public int getAge ()
public void setAge (int args-0)

8螃宙、調(diào)用運(yùn)行時(shí)類中指定的方法

通過反射來調(diào)用指定的方法蛮瞄,首先需要通過 getMethod() 方法,傳入方法名稱來獲取到對應(yīng)的方法谆扎,然后用 Method 類中的 invoke() 方法來執(zhí)行這個(gè)方法挂捅。

@Test
  public void test3() throws Exception {
    Class clazz = Person.class;
    Person p = (Person) clazz.newInstance();
    Method show = clazz.getMethod("show");
    show.invoke(p);

    Method m2 = clazz.getMethod("toString");
    Object obj = m2.invoke(p);
    System.out.println(obj);

    // 獲取靜態(tài)方法
    Method m3 = clazz.getMethod("info");
    m3.invoke(clazz);

    // 獲取私有方法
    Method display = clazz.getDeclaredMethod("display", String.class);
    display.setAccessible(true);
    display.invoke(p, "bj");

    // 獲取多個(gè)參數(shù)的方法,并獲取方法的返回值
    Method display1 = clazz.getDeclaredMethod("display1", String.class, Integer.class);
    display1.setAccessible(true);
    Object returnVal = display1.invoke(p, "bj", 1);
    System.out.println(returnVal);
  }

運(yùn)行結(jié)果:

show method run!
Person [name=null, age=0, sex=0]
info method run!
display method run堂湖,address=bj
display method run闲先,address=bj
bj1

這篇文章主要介紹了如何通過一個(gè)給定的字符串(包.類)的路徑來實(shí)例化一個(gè)類的對象状土,以及通過反射得到一個(gè)類的具體結(jié)構(gòu)。

下篇文章將為大家介紹反射的高級應(yīng)用動態(tài)代理伺糠,敬請期待......

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒙谓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子训桶,更是在濱河造成了極大的恐慌彼乌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渊迁,死亡現(xiàn)場離奇詭異慰照,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)琉朽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門毒租,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人箱叁,你說我怎么就攤上這事墅垮。” “怎么了耕漱?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵算色,是天一觀的道長。 經(jīng)常有香客問我螟够,道長灾梦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任妓笙,我火速辦了婚禮若河,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寞宫。我一直安慰自己萧福,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布辈赋。 她就那樣靜靜地躺著鲫忍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钥屈。 梳的紋絲不亂的頭發(fā)上悟民,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音焕蹄,去河邊找鬼逾雄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸦泳。 我是一名探鬼主播银锻,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼做鹰!你這毒婦竟也來了击纬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤钾麸,失蹤者是張志新(化名)和其女友劉穎更振,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饭尝,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肯腕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钥平。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片实撒。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖涉瘾,靈堂內(nèi)的尸體忽然破棺而出知态,到底是詐尸還是另有隱情,我是刑警寧澤立叛,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布负敏,位于F島的核電站,受9級特大地震影響秘蛇,放射性物質(zhì)發(fā)生泄漏其做。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一彤叉、第九天 我趴在偏房一處隱蔽的房頂上張望庶柿。 院中可真熱鬧村怪,春花似錦秽浇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梭域,卻和暖如春斑举,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背病涨。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工富玷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓赎懦,卻偏偏與公主長得像雀鹃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子励两,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容