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

深入淺析Java反射機(jī)制

 更新時(shí)間:2015年11月06日 11:31:06   投稿:mrr  
Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為Java語(yǔ)言的反射機(jī)制

Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為Java語(yǔ)言的反射機(jī)制。反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。這一概念的提出很快引發(fā)了計(jì)算機(jī)科學(xué)領(lǐng)域關(guān)于應(yīng)用反射性的研究。它首先被程序語(yǔ)言的設(shè)計(jì)領(lǐng)域所采用,并在Lisp和面向?qū)ο蠓矫嫒〉昧顺煽?jī)。當(dāng)然反射本身并不是一個(gè)新概念,它可能會(huì)使我們聯(lián)想到光學(xué)中的反射概念,盡管計(jì)算機(jī)科學(xué)賦予了反射概念新的含義,但是,從現(xiàn)象上來(lái)說(shuō),它們確實(shí)有某些相通之處,這些有助于我們的理解。

      Java反射機(jī)制主要提供下面幾種用途:

在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類

在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象

在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法

在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法

首先看一個(gè)簡(jiǎn)單的例子,通過(guò)這個(gè)例子來(lái)理解Java的反射機(jī)制是如何工作的。

package com.wanggc.reflection;
import java.lang.reflect.Method;
/**
 * Java 反射練習(xí)。
 * 
 * @author Wanggc
 */
public class ForNameTest {
  /**
   * 入口函數(shù)。
   * 
   * @param args
   *      參數(shù)
   * @throws Exception
   *       錯(cuò)誤信息
   */
  public static void main(String[] args) throws Exception {
    // 獲得Class
    Class<?> cls = Class.forName(args[0]);
    // 通過(guò)Class獲得所對(duì)應(yīng)對(duì)象的方法
    Method[] methods = cls.getMethods();
    // 輸出每個(gè)方法名
    for (Method method : methods) {
      System.out.println(method);
    }
  }
}

      當(dāng)傳入的參數(shù)是java.lang.String時(shí),會(huì)輸出如下結(jié)果

public boolean java.lang.String.equals(java.lang.Object)
public java.lang.String java.lang.String.toString()
public int java.lang.String.hashCode()
public int java.lang.String.compareTo(java.lang.String)
public int java.lang.String.compareTo(java.lang.Object)
public int java.lang.String.indexOf(int)
public int java.lang.String.indexOf(int,int)
public int java.lang.String.indexOf(java.lang.String)
public int java.lang.String.indexOf(java.lang.String,int)
public static java.lang.String java.lang.String.valueOf(int)
public static java.lang.String java.lang.String.valueOf(char)
public static java.lang.String java.lang.String.valueOf(boolean)
public static java.lang.String java.lang.String.valueOf(float)
public static java.lang.String java.lang.String.valueOf(char[],int,int)
public static java.lang.String java.lang.String.valueOf(double)
public static java.lang.String java.lang.String.valueOf(char[])
public static java.lang.String java.lang.String.valueOf(java.lang.Object)
public static java.lang.String java.lang.String.valueOf(long)
public char java.lang.String.charAt(int)
public int java.lang.String.codePointAt(int)
public int java.lang.String.codePointBefore(int)
public int java.lang.String.codePointCount(int,int)
public int java.lang.String.compareToIgnoreCase(java.lang.String)
public java.lang.String java.lang.String.concat(java.lang.String)
public boolean java.lang.String.contains(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.StringBuffer)
public static java.lang.String java.lang.String.copyValueOf(char[])
public static java.lang.String java.lang.String.copyValueOf(char[],int,int)
public boolean java.lang.String.endsWith(java.lang.String)
public boolean java.lang.String.equalsIgnoreCase(java.lang.String)
public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])
public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[])
public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException
public void java.lang.String.getBytes(int,int,byte[],int)
public byte[] java.lang.String.getBytes()
public byte[] java.lang.String.getBytes(java.nio.charset.Charset)
public void java.lang.String.getChars(int,int,char[],int)
public native java.lang.String java.lang.String.intern()
public boolean java.lang.String.isEmpty()
public int java.lang.String.lastIndexOf(java.lang.String)
public int java.lang.String.lastIndexOf(int,int)
public int java.lang.String.lastIndexOf(int)
public int java.lang.String.lastIndexOf(java.lang.String,int)
public int java.lang.String.length()
public boolean java.lang.String.matches(java.lang.String)
public int java.lang.String.offsetByCodePoints(int,int)
public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int)
public boolean java.lang.String.regionMatches(int,java.lang.String,int,int)
public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence)
public java.lang.String java.lang.String.replace(char,char)
public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String)
public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String,int)
public boolean java.lang.String.startsWith(java.lang.String)
public boolean java.lang.String.startsWith(java.lang.String,int)
public java.lang.CharSequence java.lang.String.subSequence(int,int)
public java.lang.String java.lang.String.substring(int)
public java.lang.String java.lang.String.substring(int,int)
public char[] java.lang.String.toCharArray()
public java.lang.String java.lang.String.toLowerCase()
public java.lang.String java.lang.String.toLowerCase(java.util.Locale)
public java.lang.String java.lang.String.toUpperCase()
public java.lang.String java.lang.String.toUpperCase(java.util.Locale)
public java.lang.String java.lang.String.trim()
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
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 java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

      這樣就列出了java.lang.String類的所有方法名、及其限制符、返回類型及拋出的異常。這個(gè)程序使用Class類forName方法載入指定的類,然后調(diào)用getMethods方法返回指定類的方法列表。java.lang.reflect.Method用來(lái)表述某個(gè)類中的單一方法。

      使用java的反射機(jī)制,一般需要遵循三步:

獲得你想操作類的Class對(duì)象
通過(guò)第一步獲得的Class對(duì)象去取得操作類的方法或是屬性名
操作第二步取得的方法或是屬性

     Java運(yùn)行的時(shí)候,某個(gè)類無(wú)論生成多少個(gè)對(duì)象,他們都會(huì)對(duì)應(yīng)同一個(gè)Class對(duì)象,它表示正在運(yùn)行程序中的類和接口。如何取得操作類的Class對(duì)象,常用的有三種方式:

調(diào)用Class的靜態(tài)方法forName,如上例;

使用類的.class語(yǔ)法,如:Class<?> cls = String.class;
調(diào)用對(duì)象的getClass方法,如:String str = "abc";Class<?> cls = str .getClass();

      下面將通過(guò)實(shí)例講述如何通過(guò)前面所訴的三步來(lái)執(zhí)行某對(duì)象的某個(gè)方法:

 package com.wanggc.reflection;
 import java.lang.reflect.Method;
 /**
  * Java 反射練習(xí)。
  * 
  * @author Wanggc
  */
 public class ReflectionTest {
   public static void main(String[] args) throws Exception {
     DisPlay disPlay = new DisPlay();
     // 獲得Class
     Class<?> cls = disPlay.getClass();
     // 通過(guò)Class獲得DisPlay類的show方法
     Method method = cls.getMethod("show", String.class);
     // 調(diào)用show方法
     method.invoke(disPlay, "Wanggc");
   }
 }
 class DisPlay {
   public void show(String name) {
     System.out.println("Hello :" + name);
   }
 }

      前面說(shuō)過(guò),Java程序的每個(gè)類都會(huì)有個(gè)Class對(duì)象與之對(duì)應(yīng)。Java反射的第一步就是獲得這個(gè)Class對(duì)象,如代碼14行。當(dāng)然,每個(gè)類的方法也必有一個(gè)Method對(duì)象與之對(duì)應(yīng)。要通過(guò)反射的方式調(diào)用這個(gè)方法,就要首先獲得這個(gè)方法的Method對(duì)象,如代碼16行,然后用Method對(duì)象反過(guò)來(lái)調(diào)用這個(gè)方法,如代碼18行。注意16行g(shù)etMethod方法的第一個(gè)參數(shù)是方法名,第二個(gè)是此方法的參數(shù)類型,如果是多個(gè)參數(shù),接著添加參數(shù)就可以了,因?yàn)間etMethod是可變參數(shù)方法。執(zhí)行18行代碼的invoke方法,其實(shí)也就是執(zhí)行show方法,注意invoke的第一個(gè)參數(shù),是DisPlay類的一個(gè)對(duì)象,也就是調(diào)用DisPlay類哪個(gè)對(duì)象的show方法,第二個(gè)參數(shù)是給show方法傳遞的參數(shù)。類型和個(gè)數(shù)一定要與16行的getMethod方法一直。

      上例講述了如何通過(guò)反射調(diào)用某個(gè)類的方法,下面將再通過(guò)一個(gè)實(shí)例講述如何通過(guò)反射給某個(gè)類的屬性賦值:

 package com.wanggc.reflection;
  import java.lang.reflect.Field;
  /**
  * Java 反射之屬性練習(xí)。
  * 
  * @author Wanggc
  */
 public class ReflectionTest {
   public static void main(String[] args) throws Exception {
     // 建立學(xué)生對(duì)象
     Student student = new Student();
     // 為學(xué)生對(duì)象賦值
     student.setStuName("Wanggc");
     student.setStuAge();
     // 建立拷貝目標(biāo)對(duì)象
     Student destStudent = new Student();
     // 拷貝學(xué)生對(duì)象
     copyBean(student, destStudent);
     // 輸出拷貝結(jié)果
     System.out.println(destStudent.getStuName() + ":"
         + destStudent.getStuAge());
   }
   /**
    * 拷貝學(xué)生對(duì)象信息。
    * 
    * @param from
    *      拷貝源對(duì)象
    * @param dest
    *      拷貝目標(biāo)對(duì)象
    * @throws Exception
    *       例外
 */
   private static void copyBean(Object from, Object dest) throws Exception {
     // 取得拷貝源對(duì)象的Class對(duì)象
     Class<?> fromClass = from.getClass();
     // 取得拷貝源對(duì)象的屬性列表
     Field[] fromFields = fromClass.getDeclaredFields();
     // 取得拷貝目標(biāo)對(duì)象的Class對(duì)象
     Class<?> destClass = dest.getClass();
     Field destField = null;
     for (Field fromField : fromFields) {
       // 取得拷貝源對(duì)象的屬性名字
       String name = fromField.getName();
       // 取得拷貝目標(biāo)對(duì)象的相同名稱的屬性
       destField = destClass.getDeclaredField(name);
       // 設(shè)置屬性的可訪問(wèn)性
       fromField.setAccessible(true);
       destField.setAccessible(true);
       // 將拷貝源對(duì)象的屬性的值賦給拷貝目標(biāo)對(duì)象相應(yīng)的屬性
       destField.set(dest, fromField.get(from));
     }
   }
 }
 /**
  * 學(xué)生類。
  */
 class Student {
   /** 姓名 */
   private String stuName;
   /** 年齡 */
   private int stuAge;
   /**
    * 獲取學(xué)生姓名。
    * 
    * @return 學(xué)生姓名
 */
   public String getStuName() {
     return stuName;
   }
   /**
    * 設(shè)置學(xué)生姓名
    * 
    * @param stuName
    *      學(xué)生姓名
 */
   public void setStuName(String stuName) {
     this.stuName = stuName;
   }
   /**
    * 獲取學(xué)生年齡
    * 
    * @return 學(xué)生年齡
 */
   public int getStuAge() {
     return stuAge;
   }
   /**
    * 設(shè)置學(xué)生年齡
    * 
    * @param stuAge
    *      學(xué)生年齡
 */
   public void setStuAge(int stuAge) {
     this.stuAge = stuAge;
   }
 }

       Java的發(fā)射機(jī)制中類有Class對(duì)應(yīng),類的方法有Method對(duì)應(yīng),當(dāng)然屬性也有Field與之對(duì)應(yīng)。代碼中注釋已經(jīng)做了詳細(xì)的注釋,在此不再贅述。但要注意,F(xiàn)ield提供了get和set方法獲取和設(shè)置屬性的值,但是由于屬性是私有類型,所以需要設(shè)置屬性的可訪問(wèn)性為true,如代碼50~51行。也可以在為整個(gè)fields設(shè)置可訪問(wèn)性,在40行下面使用AccessibleObject的靜態(tài)方法setAccessible,如:AccessibleObject.setAccessible(fromFields, true);

      前面講述了如何用Java反射機(jī)制操作一個(gè)類的方法和屬性,下面再通過(guò)一個(gè)實(shí)例講述如何在運(yùn)行時(shí)創(chuàng)建類的一個(gè)對(duì)象:

package com.wanggc.reflection;
 import java.lang.reflect.Field;
 /**
  * Java 反射之屬性練習(xí)。
  * 
  * @author Wanggc
  */
 public class ReflectionTest {
   public static void main(String[] args) throws Exception {
     // 建立學(xué)生對(duì)象
     Student student = new Student();
     // 為學(xué)生對(duì)象賦值
     student.setStuName("Wanggc");
     student.setStuAge();
     // 建立拷貝目標(biāo)對(duì)象
     Student destStudent = (Student) copyBean(student);
     // 輸出拷貝結(jié)果
     System.out.println(destStudent.getStuName() + ":"
         + destStudent.getStuAge());
   }
   /**
   * 拷貝學(xué)生對(duì)象信息。
   * 
   * @param from
   *      拷貝源對(duì)象
   * @param dest
   *      拷貝目標(biāo)對(duì)象
   * @throws Exception
   *       例外
 */
   private static Object copyBean(Object from) throws Exception {
     // 取得拷貝源對(duì)象的Class對(duì)象
     Class<?> fromClass = from.getClass();
     // 取得拷貝源對(duì)象的屬性列表
     Field[] fromFields = fromClass.getDeclaredFields();
     // 取得拷貝目標(biāo)對(duì)象的Class對(duì)象
     Object ints = fromClass.newInstance();
     for (Field fromField : fromFields) {
       // 設(shè)置屬性的可訪問(wèn)性
       fromField.setAccessible(true);
       // 將拷貝源對(duì)象的屬性的值賦給拷貝目標(biāo)對(duì)象相應(yīng)的屬性
       fromField.set(ints, fromField.get(from));
     }
     return ints;
   }
 }
 /**
 * 學(xué)生類。
 */
 class Student {
   /** 姓名 */
   private String stuName;
   /** 年齡 */
   private int stuAge;
   /**
   * 獲取學(xué)生姓名。
   * 
   * @return 學(xué)生姓名
 */
   public String getStuName() {
     return stuName;
   }
   /**
   * 設(shè)置學(xué)生姓名
   * 
   * @param stuName
   *      學(xué)生姓名
 */
   public void setStuName(String stuName) {
     this.stuName = stuName;
   }
   /**
   * 獲取學(xué)生年齡
   * 
   * @return 學(xué)生年齡
 */
   public int getStuAge() {
     return stuAge;
   }
   /**
   * 設(shè)置學(xué)生年齡
   * 
   * @param stuAge
   *      學(xué)生年齡
 */
   public void setStuAge(int stuAge) {
     this.stuAge = stuAge;
   }
}

      此例和上例運(yùn)行的結(jié)果是相同的。但是copyBean方法返回的對(duì)象不再是外面?zhèn)魅氲?,而是由方法?nèi)部產(chǎn)生的,如第40行代碼所示。注意:Class的newInstance方法,只能創(chuàng)建只包含無(wú)參數(shù)的構(gòu)造函數(shù)的類,如果某類只有帶參數(shù)的構(gòu)造函數(shù),那么就要使用另外一種方式:fromClass.getDeclaredConstructor(int.class,String.class).newInstance(24,"wanggc");

      至此,Java反射機(jī)制的常用機(jī)能(運(yùn)行時(shí)調(diào)用對(duì)象的方法、類屬性的使用、創(chuàng)類類的對(duì)象)已經(jīng)介紹完了。

      補(bǔ)充:在獲得類的方法、屬性、構(gòu)造函數(shù)時(shí),會(huì)有g(shù)etXXX和getgetDeclaredXXX兩種對(duì)應(yīng)的方法。之間的區(qū)別在于前者返回的是訪問(wèn)權(quán)限為public的方法和屬性,包括父類中的;但后者返回的是所有訪問(wèn)權(quán)限的方法和屬性,不包括父類的。

以上內(nèi)容就是給大家介紹的java發(fā)射機(jī)制,希望大家喜歡。

相關(guān)文章

  • 深入講解基于JDK的動(dòng)態(tài)代理機(jī)制

    深入講解基于JDK的動(dòng)態(tài)代理機(jī)制

    眾所周知相比于靜態(tài)代理,動(dòng)態(tài)代理避免了開(kāi)發(fā)人員編寫(xiě)各個(gè)繁鎖的靜態(tài)代理類,下面這篇文章主要給大家介紹了關(guān)于基于JDK的動(dòng)態(tài)代理機(jī)制的相關(guān)資料,文中通過(guò)圖文以及示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2018-07-07
  • maven依賴關(guān)系中的<scope>provided</scope>使用詳解

    maven依賴關(guān)系中的<scope>provided</scope>使用詳解

    這篇文章主要介紹了maven依賴關(guān)系中的<scope>provided</scope>使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • 關(guān)于Spring不同類型的注入方式 p-namespace,c-namespace

    關(guān)于Spring不同類型的注入方式 p-namespace,c-namespace

    這篇文章主要介紹了Spring不同類型的注入方式 p-namespace,c-namespace。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • mybatis查詢到了數(shù)據(jù),但是實(shí)體類個(gè)別字段為null問(wèn)題

    mybatis查詢到了數(shù)據(jù),但是實(shí)體類個(gè)別字段為null問(wèn)題

    這篇文章主要介紹了mybatis查詢到了數(shù)據(jù),但是實(shí)體類個(gè)別字段為null問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java私有構(gòu)造函數(shù)作用原理解析

    Java私有構(gòu)造函數(shù)作用原理解析

    這篇文章主要介紹了Java私有構(gòu)造函數(shù)作用原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Springboot2.x+ShardingSphere實(shí)現(xiàn)分庫(kù)分表的示例代碼

    Springboot2.x+ShardingSphere實(shí)現(xiàn)分庫(kù)分表的示例代碼

    這篇文章主要介紹了Springboot2.x+ShardingSphere實(shí)現(xiàn)分庫(kù)分表的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Spring Boot日志的打印與持久化詳細(xì)解析

    Spring Boot日志的打印與持久化詳細(xì)解析

    Spring Boot默認(rèn)使用SLF4J+Logback 記錄日志,并提供了默認(rèn)配置,即使我們不進(jìn)行任何額外配,也可以使用SLF4J+Logback進(jìn)行日志輸出
    2022-07-07
  • java synchronized的用法及原理詳解

    java synchronized的用法及原理詳解

    如果要保證并發(fā)情況下多線程共享數(shù)據(jù)的訪問(wèn)安全,操作的原子性,就可以使用synchronized關(guān)鍵字。這篇文章主要介紹了java synchronized的用法及原理,需要的朋友可以借鑒一下
    2021-08-08
  • Java的JDBC和橋接模式詳解

    Java的JDBC和橋接模式詳解

    下面小編就為大家?guī)?lái)一篇Java的JDBC和橋接模式(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2021-09-09
  • Rabbitmq中的channel接口常用方法詳解

    Rabbitmq中的channel接口常用方法詳解

    這篇文章主要介紹了Rabbitmq中的channel接口常用方法詳解,為了確保消息一定被消費(fèi)者處理,rabbitMQ提供了消息確認(rèn)功能,就是在消費(fèi)者處理完任務(wù)之后,就給服務(wù)器一個(gè)回饋,服務(wù)器就會(huì)將該消息刪除,需要的朋友可以參考下
    2023-09-09

最新評(píng)論