欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文搞懂Java中的反射機(jī)制

 更新時間:2020年08月19日 10:21:10   作者:弗蘭克的貓  
這篇文章主要介紹了Java中反射機(jī)制的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

  前一段時間一直忙,所以沒什么時間寫博客,拖了這么久,也該更新更新了。最近看到各種知識付費的推出,感覺是好事,也是壞事,好事是對知識沉淀的認(rèn)可與推動,壞事是感覺很多人忙于把自己的知識變現(xiàn),相對的在沉淀上做的實際還不夠,我對此暫時還沒有什么想法,總覺得,慢慢來,會更快一點,自己掌握好節(jié)奏就好。

  好了,言歸正傳。

  反射機(jī)制是Java中的一個很強(qiáng)大的特性,可以在運行時獲取類的信息,比如說類的父類,接口,全部方法名及參數(shù),全部常量和變量,可以說類在反射面前已經(jīng)衣不遮體了(咳咳,這是正規(guī)車)。先舉一個小栗子,大家隨意感受一下:

public void testA(){
    String name = "java.lang.String";
    try{
      Class cl = Class.forName(name);
      Class supercl = cl.getSuperclass();
      String modifiers = Modifier.toString(cl.getModifiers());
      if (modifiers.length() > 0){
        System.out.print(modifiers + " ");
      }
      System.out.print(name);
      if (supercl != null && supercl != Object.class){
        System.out.print(" extents " + supercl.getName());
      }
      System.out.print("{\n");
      printFields(cl);
      System.out.println();
      printConstructors(cl);
      System.out.println();
      printMethods(cl);
      System.out.println("}");
    }catch (ClassNotFoundException e){
      e.printStackTrace();
    }
    System.exit(0);
  }
  private static void printConstructors(Class cl){
    Constructor[] constructors = cl.getDeclaredConstructors();
    
    for (Constructor c : constructors){
      String name = c.getName();
      System.out.print(" ");
      String modifiers = Modifier.toString(c.getModifiers());
      if (modifiers.length() > 0){
        System.out.print(modifiers + " ");
      }
      System.out.print(name + "(");
      
      Class[] paraTypes = c.getParameterTypes();
      for (int j = 0; j < paraTypes.length; j++){
        if (j > 0){
          System.out.print(", ");
        }
        System.out.print(paraTypes[j].getSimpleName());
      }
      System.out.println(");");
    }
  }
  
  private static void printMethods(Class cl){
    Method[] methods = cl.getDeclaredMethods();
    for (Method m : methods){
      Class retType = m.getReturnType();
      String name = m.getName();
      
      System.out.print(" ");
      String modifiers = Modifier.toString(m.getModifiers());
      if (modifiers.length() > 0){
        System.out.print(modifiers + " ");
      }
      System.out.print(retType.getSimpleName() + " " + name +"(");
      Class[] paramTypes = m.getParameterTypes();
      for(int j = 0; j < paramTypes.length; j++){
        if (j > 0){
          System.out.print(", ");
        }
        System.out.print(paramTypes[j].getName());
      }
      System.out.println(");");
    }
  }
  
  private static void printFields(Class cl){
    Field[] fields = cl.getFields();
    for (Field f : fields){
      Class type = f.getType();
      String name = f.getName();
      System.out.print(" ");
      String modifiers = Modifier.toString(f.getModifiers());
      if (modifiers.length() > 0){
        System.out.print(modifiers + " ");
      }
      System.out.println(type.getSimpleName() + " " + name +";");
    }
  }

  調(diào)用testA方法輸出如下:

public final java.lang.String{
 public static final Comparator CASE_INSENSITIVE_ORDER;

 public java.lang.String(byte[], int, int);
 public java.lang.String(byte[], Charset);
 public java.lang.String(byte[], String);
 public java.lang.String(byte[], int, int, Charset);
 public java.lang.String(byte[], int, int, String);
 java.lang.String(char[], boolean);
 public java.lang.String(StringBuilder);
 public java.lang.String(StringBuffer);
 public java.lang.String(byte[]);
 public java.lang.String(int[], int, int);
 public java.lang.String();
 public java.lang.String(char[]);
 public java.lang.String(String);
 public java.lang.String(char[], int, int);
 public java.lang.String(byte[], int);
 public java.lang.String(byte[], int, int, int);

 public boolean equals(java.lang.Object);
 public String toString();
 public int hashCode();
 public int compareTo(java.lang.String);
 public volatile int compareTo(java.lang.Object);
 public int indexOf(java.lang.String, int);
 public int indexOf(java.lang.String);
 public int indexOf(int, int);
 public int indexOf(int);
 static int indexOf([C, int, int, [C, int, int, int);
 static int indexOf([C, int, int, java.lang.String, int);
 public static String valueOf(int);
 public static String valueOf(long);
 public static String valueOf(float);
 public static String valueOf(boolean);
 public static String valueOf([C);
 public static String valueOf([C, int, int);
 public static String valueOf(java.lang.Object);
 public static String valueOf(char);
 public static String valueOf(double);
 public char charAt(int);
 private static void checkBounds([B, int, int);
 public int codePointAt(int);
 public int codePointBefore(int);
 public int codePointCount(int, int);
 public int compareToIgnoreCase(java.lang.String);
 public String concat(java.lang.String);
 public boolean contains(java.lang.CharSequence);
 public boolean contentEquals(java.lang.CharSequence);
 public boolean contentEquals(java.lang.StringBuffer);
 public static String copyValueOf([C);
 public static String copyValueOf([C, int, int);
 public boolean endsWith(java.lang.String);
 public boolean equalsIgnoreCase(java.lang.String);
 public static transient String format(java.util.Locale, java.lang.String, [Ljava.lang.Object;);
 public static transient String format(java.lang.String, [Ljava.lang.Object;);
 public void getBytes(int, int, [B, int);
 public byte[] getBytes(java.nio.charset.Charset);
 public byte[] getBytes(java.lang.String);
 public byte[] getBytes();
 public void getChars(int, int, [C, int);
 void getChars([C, int);
 private int indexOfSupplementary(int, int);
 public native String intern();
 public boolean isEmpty();
 public static transient String join(java.lang.CharSequence, [Ljava.lang.CharSequence;);
 public static String join(java.lang.CharSequence, java.lang.Iterable);
 public int lastIndexOf(int);
 public int lastIndexOf(java.lang.String);
 static int lastIndexOf([C, int, int, java.lang.String, int);
 public int lastIndexOf(java.lang.String, int);
 public int lastIndexOf(int, int);
 static int lastIndexOf([C, int, int, [C, int, int, int);
 private int lastIndexOfSupplementary(int, int);
 public int length();
 public boolean matches(java.lang.String);
 private boolean nonSyncContentEquals(java.lang.AbstractStringBuilder);
 public int offsetByCodePoints(int, int);
 public boolean regionMatches(int, java.lang.String, int, int);
 public boolean regionMatches(boolean, int, java.lang.String, int, int);
 public String replace(char, char);
 public String replace(java.lang.CharSequence, java.lang.CharSequence);
 public String replaceAll(java.lang.String, java.lang.String);
 public String replaceFirst(java.lang.String, java.lang.String);
 public String[] split(java.lang.String);
 public String[] split(java.lang.String, int);
 public boolean startsWith(java.lang.String, int);
 public boolean startsWith(java.lang.String);
 public CharSequence subSequence(int, int);
 public String substring(int);
 public String substring(int, int);
 public char[] toCharArray();
 public String toLowerCase(java.util.Locale);
 public String toLowerCase();
 public String toUpperCase();
 public String toUpperCase(java.util.Locale);
 public String trim();
}

  這里把String類型的所有方法和變量都獲取到了,使用的僅僅是String類型的全名。當(dāng)然,反射的功能不僅僅是獲取類的信息,還可以在運行時動態(tài)創(chuàng)建對象,回想一下,我們正常的對象使用,都是需要在代碼中先聲明,然后才能使用它,但是使用反射后,就能在運行期間動態(tài)創(chuàng)建對象并調(diào)用其中的方法,甚至還能直接查看類的私有成員變量,還能獲取類的注解信息,在泛型中類型判斷時也經(jīng)常會用到。反射可以說完全打破了類的封裝性,把類的信息全部暴露了出來。

  上面的代碼看不太明白也沒關(guān)系,只要稍微感受一下反射的能力就好了。介紹完了反射能做的事情,本篇教程就不再寫一些玩具代碼了,這次以一個實用型的代碼為媒介來介紹反射。

  在開發(fā)中,經(jīng)常會遇到兩個不同類對象之間的復(fù)制,把一個類中的字段信息get取出來,然后set到另一個類中,大部分情況下,兩個類對應(yīng)的字段是一樣,每次這樣使用是很麻煩的,那么利用反射就可以實現(xiàn)一個封裝,只需要調(diào)用一個方法即可實現(xiàn)簡單的類字段復(fù)制。

  那么,先來想想,要復(fù)制一個類對象的所有字段信息到另一個類對象中,首先,怎么獲取一個類的某個字段的值呢?我們先來編寫一個方法:

  /**
   * 獲取對象的指定字段的值
   * @param obj 目標(biāo)對象
   * @param fieldName 目標(biāo)字段
   * @return 返回字段值
   * @throws Exception 可能拋出異常
   */
  private static Object getFieldValue(Object obj, String fieldName) throws Exception{
    //獲取類型信息
    Class clazz = obj.getClass();
    //取對應(yīng)的字段信息
    Field field = clazz.getDeclaredField(fieldName);
    //設(shè)置可訪問權(quán)限
    field.setAccessible(true);
    //取字段值
    Object value = field.get(obj);
    return value;
  }

  這里使用了兩個之前沒有說過的類,一個是Class,是不是很眼熟,想一想,我們每次定義一個類的時候是不是都要用到它,哈哈,那你就想錯了,那是class關(guān)鍵詞,java是大小寫的敏感的,這里的Class是一個類名,那這個類是干嘛用的呢?

  虛擬機(jī)在加載每一個類的時候,會自動生成一個對應(yīng)的Class類來保存該類的信息,可以理解為Class類是那個類的代理類,是連接實際類與類加載器的橋梁,可以通過它來獲取虛擬機(jī)的類加載器引用,從而實現(xiàn)更多的騷操作。Class類是一個泛型類,每個類都有對應(yīng)的一個Class類,比如String對應(yīng)的Class類就是Class<String>。

  Class有很多方法來獲取更多關(guān)于類的信息,這里使用getDeclaredField方法來獲取指定字段信息,返回的是Field類型對象,這個對象里存儲著關(guān)于字段的一些信息,如字段名稱,字段類型,字段修飾符,字段可訪問性等,setAccessible方法可以設(shè)置字段的可訪問性質(zhì),這樣就能直接訪問private修飾的字段了,然后使用get方法來獲取指定對象的對應(yīng)字段的值。

  我們來測試一下:

  public void testB(){
    try{
      Employee employee = new Employee();
      employee.setName("Frank");
      employee.setSalary(6666.66);
      System.out.println((String)getFieldValue(employee,"name"));
      System.out.println((double)getFieldValue(employee,"salary"));
    }catch (Exception e){
      e.printStackTrace();
    }
  }

  輸出如下:

Frank
6666.66

  接下來,我們需要獲取類中所有字段,然后在另一個類中查找是否有對應(yīng)字段,如果有的話就設(shè)置字段的值到相應(yīng)的字段中。

  /**
   * 復(fù)制一個類對象屬性到另一個類對象中
   * @param objA 需要復(fù)制的對象
   * @param objB 復(fù)制到的目標(biāo)對象類型
   * @return 返回復(fù)制后的目標(biāo)對象
   */
  private static void parseObj(Object objA,Object objB) throws Exception{
    if (objA == null){
      return;
    }
    //獲取objA的類信息
    Class classA = objA.getClass();
    Class classB = objB.getClass();
    try {
      //獲取objA的所有字段
      Field[] fieldsA = classA.getDeclaredFields();
      //獲取objB的所有字段
      Field[] fieldsB = classB.getDeclaredFields();
      if (fieldsA == null || fieldsA.length <= 0 || fieldsB == null || fieldsB.length <= 0){
        return;
      }
      
      //生成查詢map
      Map<String,Field> fieldMap = new HashMap<>();
      for (Field field:fieldsA){
        fieldMap.put(field.getName(),field);
      }
      
      //開始復(fù)制字段信息
      for (Field fieldB : fieldsB){
        //查找是否在objB的字段中存在該字段
        Field fielaA = fieldMap.get(fieldB.getName());
        if (fielaA != null){
          fieldB.setAccessible(true);
          fieldB.set(objB,getFieldValue(objA,fielaA.getName()));
        }
      }
    } catch (IllegalStateException e) {
      throw new IllegalStateException("instace fail: " ,e);
    }
  }

  這里獲取到classA和classB的所有字段之后,先生成了一個map用于查找,可以減少遍歷次數(shù),然后之后只需要遍歷一次就可以判斷相應(yīng)字段是否存在,如果存在則取出對應(yīng)值設(shè)置到相應(yīng)的字段里去。

  接下來測試一下:

  public void testB(){
    try{
      //生成Employee對象
      Employee employee = new Employee("Frank",6666.66);
      //生成一個Manager對象
      Manager manager = new Manager();
      //復(fù)制對象
      parseObj(employee,manager);
      System.out.println(manager.getName());
      System.out.println(manager.getSalary());
    }catch (Exception e){
      e.printStackTrace();
    }
  }
public class Employee {
  private String name;
  private Double salary;
  
  public Employee(String name, Double salary) {
    this.name = name;
    this.salary = salary;
  }
  
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
  
  public Double getSalary() {
    return salary;
  }
  
  public void setSalary(Double salary) {
    this.salary = salary;
  }
}
public class Manager {
  private String name;
  private Double salary;
  private Double bonus;
  
  public String getName() {
    return name;
  }
  
  public void setName(String name) {
    this.name = name;
  }
  
  public Double getSalary() {
    return salary;
  }
  
  public void setSalary(Double salary) {
    this.salary = salary;
  }
  
  public Double getBonus() {
    return bonus;
  }
  
  public void setBonus(Double bonus) {
    this.bonus = bonus;
  }
}

  輸出如下:

Frank
6666.66

  完美,這樣我們就利用了反射機(jī)制完美的把相同的字段在不同類的對象之間進(jìn)行了復(fù)制,這里僅僅是兩個字段,所以可能好處不明顯,但事實上,實際開發(fā)中,經(jīng)常會有將BO轉(zhuǎn)換為VO的操作,這時候,這個操作就很有必要了,簡單的一行命令就可以代替一大堆的get和set操作。

  當(dāng)然,使用反射機(jī)制固然高端大氣上檔次,但是也是一把雙刃劍,使用不當(dāng)很可能會帶來嚴(yán)重后果,而且使用反射的話,會占用更多資源,運行效率也會降低,上述工具類是用運行效率換開發(fā)效率。開發(fā)中不建議大量使用,還是那句話,技術(shù)只是手段,需要使用的時候再使用,不要為了使用而使用。

  至于反射中的其他方法和姿勢,大家盡可以慢慢去摸索,這里僅僅是拋磚引玉。

  至此,本篇講解完畢,歡迎大家繼續(xù)關(guān)注。

以上就是一文搞懂Java中的反射機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于Java反射機(jī)制的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論