JAVA反射機(jī)制詳解

1.理解反射的基礎(chǔ):Class類

眾所周知Java有個(gè)Object 類,是所有Java 類的繼承根源,其內(nèi)聲明了數(shù)個(gè)應(yīng)該在所有Java 類中被改寫的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中g(shù)etClass()返回一個(gè)Class 對(duì)象。

Class 類十分特殊。它和一般類一樣繼承自O(shè)bject,其實(shí)體用以表達(dá)Java程序運(yùn)行時(shí)的classes和interfaces,也用來(lái)表達(dá)enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及關(guān)鍵詞void。當(dāng)一個(gè)class被加載,或當(dāng)加載器(class loader)的defineClass()被JVM調(diào)用,JVM 便自動(dòng)產(chǎn)生一個(gè)Class 對(duì)象。如果您想借由“修改Java標(biāo)準(zhǔn)庫(kù)源碼”來(lái)觀察Class 對(duì)象的實(shí)際生成時(shí)機(jī)(例如在Class的constructor內(nèi)添加一個(gè)println()),這樣是行不通的!因?yàn)镃lass并沒(méi)有public constructor。

Class是Reflection故事起源。針對(duì)任何您想探勘的類,唯有先為它產(chǎn)生一個(gè)Class 對(duì)象,接下來(lái)才能經(jīng)由后者喚起為數(shù)十多個(gè)的Reflection APIs。這些APIs將在稍后的探險(xiǎn)活動(dòng)中一一亮相。

Java類用于描述一類事物的共性,該類事物有什么屬性,至于這個(gè)類的屬性值是什么,則是由這個(gè)類的對(duì)象來(lái)確定,不同的實(shí)例對(duì)象有不同的屬性值。java程序中的各個(gè)類,他們也屬于同一類事物,也可以用一個(gè)類來(lái)描述這類事物,這個(gè)類就是Class,要注意和小寫的class關(guān)鍵字的區(qū)別。Class類描述那些方面的信息呢?類的名字,類的訪問(wèn)屬性,類所屬于的包名,字段名稱的列表,方法名稱的列表,等等,學(xué)習(xí)反射,首先要明白這個(gè)Class類。

對(duì)比提問(wèn)1:眾多的人用一個(gè)什么類表示?眾多的java類用什么表示?
人-》Person
Java類-》Class
此時(shí)很明顯的體現(xiàn)了java面向?qū)ο蟮乃枷耄ㄒ磺薪詾閷?duì)象)。

對(duì)比提問(wèn)2:Person類代表人,他的實(shí)例對(duì)象就是張三,李四這樣一個(gè)個(gè)具體的人,Class類代表java類,那么他的實(shí)例對(duì)象又分別對(duì)應(yīng)什么呢?
對(duì)應(yīng)的是各個(gè)類在內(nèi)存中的字節(jié)碼(一個(gè)類有且僅有一份),例如,Person類的字節(jié)碼,ArrayList類的字節(jié)碼等等。(字節(jié)碼就是類被加載到j(luò)vm中內(nèi)存中的Class類的實(shí)例,然后利用這個(gè)字節(jié)碼復(fù)制一個(gè)個(gè)指定類的對(duì)象)。

一個(gè)類被類加載器加載到內(nèi)存中,占用一片存儲(chǔ)空間,這個(gè)空間里邊的內(nèi)容就是類的字節(jié)碼,不同的類的字節(jié)碼是不同的,所以他在內(nèi)存中的內(nèi)容是不同的,這一個(gè)個(gè)的空間分別用一個(gè)個(gè)對(duì)象來(lái)表示,這些對(duì)象顯示具有相同的類型,這個(gè)類型是什么呢?就是 Class類。

三種獲取Class對(duì)象的方法:
不能用Class c = new Class(),沒(méi)有這個(gè)構(gòu)造方法的,應(yīng)該采取下邊的三種方法:
1).  Person.class 類名.class的方式;
2).  Person p = new Person; p.getClass(); person類的實(shí)例getClass的方式;
3).  Class.forName(“類名(全路徑)”); 這個(gè)如果在jvm內(nèi)存中沒(méi)有找到指定類的字節(jié)碼,就先將指定類加載到j(luò)vm內(nèi)存中,然后在返回指定的類的Class實(shí)例,如果jvm中存在就直接返回。

需要注意的是:一般實(shí)現(xiàn)反射的話都是使用第三種方式Class.forName(“”).因?yàn)檫@個(gè)參數(shù)可以寫成變量傳進(jìn)來(lái),此時(shí)就可以讀取配置文件的字符串來(lái)動(dòng)態(tài)的獲取相關(guān)類的字節(jié)碼實(shí)例。

      /**
       * 獲取一個(gè)類的字節(jié)碼對(duì)象的三種方法 同一個(gè)類,類實(shí)例(字節(jié)碼對(duì)象)在jvm中有且只有一份
       * 
       * @throws ClassNotFoundException
       */
      @Test
      public void test1() throws ClassNotFoundException {
          String str = "abc";
          // 表示返回此對(duì)象運(yùn)行時(shí)類的 Class對(duì)象
          Class<? extends String> cls1 = str.getClass();
  
          // 編譯器通過(guò)String就可以確定返回String類型的Class對(duì)象。
          Class<String> cls2 = String.class;
  
          // 給編譯器看的,編譯器并不知道通過(guò)forName會(huì)返回什么類型的Class對(duì)象
          Class<?> cls3 = Class.forName("java.lang.String");
  
          System.out.println(cls1 == cls2); // true
          System.out.println(cls1 == cls3); // true 
      }

由輸出結(jié)果可知,每個(gè)類不管使用三種方式中的哪種方式來(lái)獲取Class對(duì)象都是一份,從而證明了內(nèi)存中同一個(gè)類的Class對(duì)象有且只有一份。

9個(gè)預(yù)定義的class對(duì)象:八種基本數(shù)據(jù)類型和void關(guān)鍵字。

       /**
        * 預(yù)定義的Class對(duì)象
        */
       @Test
       public void test2() {
           Class<String> cls2 = String.class;
           // primitive是原始的意思,判定指定的 Class對(duì)象是否表示一個(gè)基本類型(原始類型)
           System.out.println(cls2.isPrimitive());
   
           // 判定指定的 Class 對(duì)象是否表示一個(gè)基本類型
           System.out.println(int.class.isPrimitive());
   
           // 基本類型和對(duì)應(yīng)包裝類Class對(duì)象不是同一個(gè)
           System.out.println(int.class == Integer.class); //false int和Integer包裝類不是同一份字節(jié)碼
   
           /*
            * Integer.TYPE代表的是integer包裝的基本類的字節(jié)碼
            * 根據(jù)文檔:表示基本類型 int 的 Class 實(shí)例
            */
           System.out.println(int.class == Integer.TYPE);  //true
   
           //數(shù)組有對(duì)應(yīng)的數(shù)組類(Array類)
           System.out.println(int[].class.isPrimitive()); //false
   
           // 是不是數(shù)組類class對(duì)象
           System.out.println(int[].class.isArray());
       }

2.反射的概念

JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為java語(yǔ)言的反射機(jī)制。

JAVA反射(放射)機(jī)制:“程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語(yǔ)言稱為動(dòng)態(tài)語(yǔ)言”。從這個(gè)觀點(diǎn)看,Perl,Python,Ruby是動(dòng)態(tài)語(yǔ)言,C++,Java,C#不是動(dòng)態(tài)語(yǔ)言。但是JAVA有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制:Reflection,用在Java身上指的是我們可以于運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的classes。換句話說(shuō),Java程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對(duì)象實(shí)體、或?qū)ζ鋐ields設(shè)值、或喚起其methods.

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ì)象的方法;生成動(dòng)態(tài)代理。

反射就是把java類中的各個(gè)成分映射成相應(yīng)的java類。

例如:一個(gè)java類中用一個(gè)Class類的對(duì)象來(lái)表示,一個(gè)類中的組成部分:成員變量,方法,構(gòu)造方法,包等信息也用一個(gè)個(gè)的java類來(lái)表示,就像汽車是一個(gè)類,汽車中的發(fā)動(dòng)機(jī),變速箱等等也是一個(gè)個(gè)的類。表示java類的Class類顯然要提供一些方法來(lái)獲取其中的變量,方法,構(gòu)造方法,修飾符,包等信息,這些信息就是用相應(yīng)類的實(shí)例對(duì)象來(lái)表示,他們是Filed,Method,Constructor,Package等等。(可以查看Class類的api就可以了解相關(guān)的方法)。

一個(gè)類的每個(gè)成員都可以用相應(yīng)的反射API類的一個(gè)實(shí)例對(duì)象來(lái)表示,通過(guò)調(diào)用Class類的方法可以得到這些實(shí)例對(duì)象后,得到這些實(shí)例對(duì)象后有什么用呢?怎么用呢?這才是要點(diǎn)。

反射在很多地方都能用到,比如Spring(一個(gè)開(kāi)放源代碼的設(shè)計(jì)層面框架),Struts(一個(gè)基于MVC設(shè)計(jì)模式的Web應(yīng)用框架),JUnit(一個(gè)Java語(yǔ)言的單元測(cè)試框架)等一些框架中,反射是框架設(shè)計(jì)的靈魂

3.構(gòu)造方法的反射

Constructor類代表某個(gè)類中的一個(gè)構(gòu)造方法。

       /**
        * 構(gòu)造方法的反射
        * @throws NoSuchMethodException
        * @throws SecurityException
        * @throws InstantiationException
        * @throws IllegalAccessException
        * @throws IllegalArgumentException
        * @throws InvocationTargetException
        */
       @Test
       public void test3() throws NoSuchMethodException, SecurityException,
               InstantiationException, IllegalAccessException,
               IllegalArgumentException, InvocationTargetException {
           Class<String> clazz = String.class;
           //獲取String類的所有構(gòu)造方法
           Constructor<?>[] constructors = clazz.getConstructors();
   
           /*
            * 通過(guò)構(gòu)造函數(shù)反射實(shí)例化對(duì)象
            */
           String str1 = new String(new StringBuffer("adc"));
           Constructor<String> constructor1 = String.class
                   .getConstructor(StringBuffer.class);
           String str2 = constructor1.newInstance(new StringBuffer("abc"));
   
           //使用默認(rèn)的構(gòu)造方法實(shí)例化對(duì)象,newInstance
           String str3 = String.class.newInstance();
       }

使用newInstance方法來(lái)實(shí)例化對(duì)象的情況,newInstance方法先得到相應(yīng)類的默認(rèn)的構(gòu)造方法,然后使用該默認(rèn)的構(gòu)造方法來(lái)實(shí)例化對(duì)象。
通過(guò)查看源碼知:java會(huì)用緩存機(jī)制來(lái)緩存默認(rèn)的構(gòu)造方法實(shí)例,由此可以看出用了緩存說(shuō)明獲取Constructor對(duì)象是一個(gè)很耗時(shí)的操作。

擴(kuò)展:因?yàn)榉瓷錂C(jī)制的存在,所以單例模式并不能完全保證單例對(duì)象的唯一性。如何保證單例防反射攻擊,請(qǐng)看這篇: 單例模式--反射--防止序列化破壞單例模式

4.成員變量的反射

Filed類代表某個(gè)類中的一個(gè)成員變量,即某個(gè)類的字節(jié)碼對(duì)象的字段對(duì)象,不和具體的類的實(shí)例對(duì)應(yīng)。

  public class ReflectPoint {
      private Date birthday = new Date();
  
      private int x;
      public int y;
      public String str1;
      public String str2;
      public String str3;
  
      public ReflectPoint(int x, int y) {
          super();
          this.x = x;
          this.y = y;
      }
      
      public ReflectPoint(String str1, String str2, String str3) {
          super();
          this.str1 = str1;
          this.str2 = str2;
          this.str3 = str3;
      }
  
  
  
      @Override
      public int hashCode() {
          final int prime = 31;
          int result = 1;
          result = prime * result + x;
          result = prime * result + y;
          return result;
      }
  
      @Override
      public boolean equals(Object obj) {
          if (this == obj)
              return true;
          if (obj == null)
              return false;
          if (getClass() != obj.getClass())
              return false;
          final ReflectPoint other = (ReflectPoint) obj;
          if (x != other.x)
              return false;
          if (y != other.y)
              return false;
          return true;
      }
  
      @Override
      public String toString() {
          return str1 + ":" + str2 + ":" + str3;
      }
  
      public int getX() {
          return x;
      }
  
      public void setX(int x) {
          this.x = x;
      }
  
      public int getY() {
          return y;
      }
  
      public void setY(int y) {
          this.y = y;
      }
  
      public Date getBirthday() {
          return birthday;
      }
  
      public void setBirthday(Date birthday) {
          this.birthday = birthday;
      }
  } 
      /**
       * 成員變量的反射
       * @throws SecurityException
       * @throws NoSuchFieldException
       * @throws IllegalAccessException
       * @throws IllegalArgumentException
       */
      @Test
      public void test4() throws NoSuchFieldException, SecurityException,
              IllegalArgumentException, IllegalAccessException {
          ReflectPoint pt1 = new ReflectPoint(3, 5);
          Class<? extends ReflectPoint> clazz = pt1.getClass();
          /*
           * 獲取指定的字段對(duì)象
           * fieldY的值是多少?是5,錯(cuò)!fieldY不是對(duì)象身上的變量,而是類上,要用它去取某個(gè)對(duì)象上對(duì)應(yīng)的值
           */
          Field fieldY = clazz.getField("y"); 
          
          //獲取pt1對(duì)象上的y字段的值
          System.out.println("變量Y的值:" + fieldY.getInt(pt1));
  
          /*
           * getField只能獲取public和defalut修飾的字段,此時(shí)x是私有變量。
           */
          /*
           * Field fieldX = clazz.getField("x");
           * System.out.println(fieldX.getInt(pt1));
           */
  
          /*
           * getDeclaredFields可以獲取類中所有的成員變量 包括私有的變量
           */
          Field[] fields = clazz.getDeclaredFields();
          System.out.println("成員變量個(gè)數(shù):" + fields.length);
  
          /*
           * 獲取私有變量x的值
           * 雖然獲取到x了,但是沒(méi)有權(quán)限訪問(wèn)其中的值,所以需要設(shè)置x字段對(duì)象為可以訪問(wèn)的。
           */
          Field fieldX = clazz.getDeclaredField("x");
          fieldX.setAccessible(true);
          System.out.println("變量X的值:" + fieldX.getInt(pt1));
      }
      /**
       * 成員變量反射的綜合案例 將任意一個(gè)對(duì)象中的所有String類型的成員變量所對(duì)應(yīng)的字段內(nèi)容中的“b”改成”a”
       * @throws SecurityException
       * @throws NoSuchFieldException
       * @throws IllegalAccessException
       * @throws IllegalArgumentException
       */
      @Test
      public void test5() throws NoSuchFieldException, SecurityException,
              IllegalArgumentException, IllegalAccessException {
          ReflectPoint pt1 = new ReflectPoint("ball", "basketball", "itcast");
          System.out.println("修改前:");
          System.out.println(pt1.str1);
          System.out.println(pt1.str2);
          System.out.println(pt1.str3);
  
          Class<? extends ReflectPoint> clazz = pt1.getClass();
          // /Field fieldX = clazz.getDeclaredField("x");
          Field[] fields = clazz.getDeclaredFields();  //獲取所有的字段 包括私有字段
          for (Field field : fields) {
              /*
               * 獲取字段的類型(返回的是類型的字節(jié)碼實(shí)例) 判斷是否和String類的字節(jié)碼相等就能判斷是否是String類型的字段了。  
               * 因?yàn)樽止?jié)碼只有一個(gè),所以使用 == 比使用equeals更能體現(xiàn)意義
               */
              Class<?> filedType = field.getType();
              if (filedType == String.class) {
                  field.setAccessible(true);
                  String oldValue = (String) field.get(pt1);
                  String newValue = oldValue.replace("b", "a");
                  field.set(pt1, newValue);  //重新將替換后的新值set到相關(guān)到對(duì)象中去。
              }
           }
  
           System.out.println("修改后:");
           System.out.println(pt1.str1);
           System.out.println(pt1.str2);
           System.out.println(pt1.str3);
      }

結(jié)論:
從上可以看出對(duì)于一些對(duì)象,可以使用反射將其中的值都改掉,Spring實(shí)例化里邊的值和初始化對(duì)象的值都是如此實(shí)現(xiàn)的。

5.成員方法的反射

Method類代表某個(gè)類中的一個(gè)成員方法。

      /**
       * 成員方法的反射
       * @throws SecurityException
       * @throws NoSuchMethodException
       * @throws InvocationTargetException
       * @throws IllegalArgumentException
       * @throws IllegalAccessException
       */
      @Test
      public void test6() throws NoSuchMethodException, SecurityException,
              IllegalAccessException, IllegalArgumentException,
              InvocationTargetException {
          String str = "abc";
          //獲取指定方法的Method類的實(shí)例
          Method method = String.class.getMethod("charAt", int.class);
          //調(diào)用指定實(shí)例的方法,并傳參
          //如果是Method代表的是靜態(tài)方法,那么第一參數(shù)為null
          System.out.println(method.invoke(str, 1));
      }

6.對(duì)接收數(shù)組參數(shù)的成員方法進(jìn)行反射

問(wèn)題:
用反射的方式執(zhí)行某個(gè)類中的main方法,寫一個(gè)程序,根據(jù)用戶提供的類名,去執(zhí)行該類的main方法。如果使用傳統(tǒng)的方式執(zhí)行main方法可以直接Test.main(new String[]{}); 但是不能動(dòng)態(tài)指定類名(用戶提供的),因?yàn)閭鹘y(tǒng)的方式都已經(jīng)編譯了不能再改了。

      /**
       * 對(duì)接收數(shù)組參數(shù)的成員方法進(jìn)行反射 用反射的方式執(zhí)行某個(gè)類中的main方法,寫一個(gè)程序,根據(jù)用戶提供的類名,去執(zhí)行該類的main方法。
       * 
       * @throws ClassNotFoundException
       * @throws SecurityException
       * @throws NoSuchMethodException
       * @throws InvocationTargetException
       * @throws IllegalArgumentException
       * @throws IllegalAccessException
       */
      @Test
      public void test7() throws ClassNotFoundException, NoSuchMethodException,
              SecurityException, IllegalAccessException,
              IllegalArgumentException, InvocationTargetException {
  
          String mainStr = "mytest.TestArguments";
          Method mainMethod = Class.forName(mainStr).getMethod("main",
                  String[].class);
          mainMethod.invoke(null, new String[] { "a", "b", "c" }); 
      }
  /**
   * 測(cè)試反射main方法的類
   */
  class TestArguments {
      public static void main(String[] args) {
          for (String arg : args) {
              System.out.println(arg);
          }
      }
  }

上述代碼報(bào)錯(cuò):java.lang.IllegalArgumentException: wrong number of arguments

明顯是參數(shù)個(gè)數(shù)錯(cuò)誤,main方法確實(shí)需要一個(gè)參數(shù),而我也傳了一個(gè)參數(shù),為什么會(huì)錯(cuò)呢?

因?yàn)樵跒閕nvoke傳遞數(shù)組類型的參數(shù)的時(shí)候,按照jdk1.5的做法,整個(gè)數(shù)組是一個(gè)參數(shù),而按照jdk1.4的語(yǔ)法,會(huì)將數(shù)組拆開(kāi),每個(gè)元素對(duì)應(yīng)一個(gè)參數(shù),所以當(dāng)把一個(gè)字符串?dāng)?shù)組作為一個(gè)參數(shù)傳遞給invoke方法時(shí),javac會(huì)按照哪種方法進(jìn)行處理呢?jdk1.5肯定要兼容jdk1.4的做法,會(huì)先按照1.4的語(yǔ)法處理,即把數(shù)組拆開(kāi)為每一個(gè)元素作為一個(gè)參數(shù)。所以如果按照上邊的方式會(huì)出現(xiàn)異常。可以采用下邊的方式:

      /**
       * 對(duì)接收數(shù)組參數(shù)的成員方法進(jìn)行反射 用反射的方式執(zhí)行某個(gè)類中的main方法,寫一個(gè)程序,根據(jù)用戶提供的類名,去執(zhí)行該類的main方法。
       * @throws ClassNotFoundException
       * @throws SecurityException
       * @throws NoSuchMethodException
       * @throws InvocationTargetException
       * @throws IllegalArgumentException
       * @throws IllegalAccessException
       */
      @Test
      public void test7() throws ClassNotFoundException, NoSuchMethodException,
              SecurityException, IllegalAccessException,
              IllegalArgumentException, InvocationTargetException {
  
          String mainStr2 = "mytest.TestArguments";
          Method mainMethod2 = Class.forName(mainStr2).getMethod("main",
                  String[].class);
  
          /*
           *  jdk1.4的做法
           *  重新包裝字符串?dāng)?shù)組為一個(gè)object數(shù)組,此時(shí)按照1.4的方式拆開(kāi)之后只有一個(gè)參數(shù)就是里邊的string數(shù)組
           */
          mainMethod2
                  .invoke(null, new Object[] { new String[] { "a", "b", "c" } });
  
          /*
           * jdk1.5的做法
           * 重新包裝字符串?dāng)?shù)組為一個(gè)object,此時(shí)給invoke方法傳遞的參數(shù)不是數(shù)組,編譯器不會(huì)去拆解了,
           * (數(shù)組也是Object)
           */
          mainMethod2.invoke(null, (Object) new String[] { "a", "b", "c" });
      }

7.數(shù)組與Object的關(guān)系及數(shù)組的反射類型

根據(jù)文檔中class的解釋,對(duì)于數(shù)組的Class對(duì)象實(shí)例,具有相同維數(shù)(一維數(shù)組二維數(shù)組等)和元素類型的屬于同一個(gè)類型,即具有相同的Class實(shí)例對(duì)象。中文文檔的說(shuō)明:所有具有相同元素類型和維數(shù)的數(shù)組都共享該 Class 對(duì)象。

     int[] a1 = new int[] { 1, 2, 3 };
     Integer[] a11 = new Integer[] { 1, 2, 3 };
     int[] a2 = new int[4];
     int[][] a3 = new int[2][3];
     String[] a4 = new String[] { "a", "b", "c" };
    
     System.out.println(a1.getClass() == a2.getClass()); // true

     // 都是一維數(shù)組,但是數(shù)組元素類型不一致,直接編譯不通過(guò)。
     // System.out.println(a1.getClass() == a4.getClass());
     // 數(shù)組元素類型以致,但是維數(shù)不同,直接編譯不通過(guò)。
     // System.out.println(a1.getClass() == a3.getClass());

數(shù)組的反射類型的name:

         /*
         * 基本類型的數(shù)組getName
         */
        //[I
        System.out.println("int[]:" + a1.getClass().getName());
        //int
        System.out.println("int:" + int.class.getName());

        /*
         * 引用類型的數(shù)組getName
         */
        // [Ljava.lang.String;
        System.out.println("String[]:" + a4.getClass().getName());
        // java.lang.String
        System.out.println("String:" + String.class.getName());

        /*
         * 與getName相對(duì)應(yīng)的是forName 
         * 根據(jù)數(shù)組類型的Name類獲取Class
         */
        // 基本類型
        Class<?> c1 = Class.forName("[I");
        System.out.println(c1.isArray()); // true

        // 引用類型
        Class<?> c2 = Class.forName("[Ljava.lang.String;");
        System.out.println(c2.isArray()); // true

對(duì)于"[I"中,[表示數(shù)組,I表示數(shù)組元素類型是int。
具體I代表什么參考getName方法的api注釋:

基礎(chǔ)類型:
Element Type  Encoding 
boolean        Z  
byte           B  
char           C   
double         D  
float          F  
int            I  
long           J  
short          S 

引用類型:
Element Type             Encoding
class or interface       Lclassname;  

例子: 
 String.class.getName()
 returns "java.lang.String"

 byte.class.getName()
 returns "byte"

 (new Object[3]).getClass().getName()
 returns "[Ljava.lang.Object;"

 (new int[3][4][5][6][7][8][9]).getClass().getName()
 returns "[[[[[[[I"

getSimpleName方法

  // String
  System.out.println(String.class.getSimpleName());

  // int[]
  System.out.println(a1.getClass().getSimpleName()); 

8.數(shù)組的反射應(yīng)用

數(shù)組不是類,但是實(shí)現(xiàn)了Object中的方法。

按照J(rèn)ava語(yǔ)言規(guī)范的說(shuō)法,Java數(shù)據(jù)類型分為兩大類:基本數(shù)據(jù)類型和復(fù)合數(shù)據(jù)類型,其中復(fù)合數(shù)據(jù)類型包括數(shù)組、類和接口。

Array類(Array工具類)完成對(duì)數(shù)組的反射,是代表了對(duì)于數(shù)組類的描述。文檔中說(shuō)明:Array 類提供了動(dòng)態(tài)創(chuàng)建和訪問(wèn) Java 數(shù)組的方法。

擴(kuò)展 : java.lang.reflect包

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評(píng)論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,740評(píng)論 3 420
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,856評(píng)論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,175評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,931評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,321評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評(píng)論 3 443
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,533評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,082評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,891評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,067評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,319評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,732評(píng)論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,987評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,794評(píng)論 3 394
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,076評(píng)論 2 375

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

  • 寫在前面的話:很多人會(huì)說(shuō)我直接new一個(gè)對(duì)象不就完了么,干嘛還用反射來(lái)獲取對(duì)象。因?yàn)閚ew屬于靜態(tài)編譯,而反射屬于...
    iDaniel閱讀 8,633評(píng)論 1 4
  • 前言 Java反射機(jī)制很早的時(shí)候就有耳聞,期間也會(huì)去看看相關(guān)資料,但是又很快會(huì)忘記,所以,寫一篇Blog來(lái)加深記憶...
    Android_Simon閱讀 525評(píng)論 0 1
  • 活著就像個(gè)鐘擺一會(huì)兒撞到無(wú)聊,一會(huì)兒又被無(wú)聊彈回去哐當(dāng)撞到痛苦一邊,來(lái)回在無(wú)聊與痛苦之間擺動(dòng),我時(shí)不常有輕生厭世的...
    單立人道長(zhǎng)閱讀 252評(píng)論 0 0
  • 自主招生又稱自主選拔,主要選拔具有學(xué)科特長(zhǎng)和創(chuàng)新潛質(zhì)的優(yōu)秀學(xué)生。是對(duì)現(xiàn)行統(tǒng)一高考招生按分?jǐn)?shù)錄取的一種補(bǔ)充,同時(shí)也是...
    咚咕隆咚閱讀 257評(píng)論 0 0
  • 昨天承認(rèn)了自己是個(gè)偽學(xué)習(xí)者以后,好像如釋重負(fù),面對(duì)真實(shí)地自己。似乎看清楚真實(shí)地自己才知道自己應(yīng)該需要怎么做這件事。...
    一個(gè)景天閱讀 425評(píng)論 0 1