java反射教程

來源:互聯網
上載者:User

標籤:ble   資訊   -name   hang   開發人員   java反射   app   [1]   元素   

什麼是反射,為什麼它是有用的,以及如何使用它?

1.什麼是反射?

“反射通常是JVM中啟動並執行程式需要檢測和修改運行時程式的行為的一種能力。”這個概念通常與內省(Introspection)混淆。以下是這兩個術語在維基百科中的定義:

  1. 內省是指電腦程式在運行時檢查物件類型的一種能力,通常也可以稱作運行時類型檢查。
  2. 反射是指電腦程式在運行時可以訪問、檢測和修改它本身狀態或行為的一種能力。

從他們的定義可以看出,內省是反射的一個子集。有些語言支援內省,但不支援反射,如C++。

內省例子:instanceof運算子用於確定一個對象是否屬於一個特定的類。

if(obj instanceof Dog){
   Dog d = (Dog)obj;
   d.bark();
}

反射例子:Class.forName()方法通過類或介面的名稱(一個字串和完全限定名)來返回對應Class的對象。forName方法會對類初始化。

// with reflection
Class<?> c = Class.forName("classpath.and.classname");
Object dog = c.newInstance();
Method m = c.getDeclaredMethod("bark", new Class<?>[0]);
m.invoke(dog);

在Java中,更關注於反射而非內省,因為你不能改變一個對象的結構。

2.為什麼我們需要反射?

反射能夠讓我們:

  • 運行時檢測一個對象所屬的類;
  • 運行時構造一個類的對象;
  • 運行時檢測一個類的欄位和方法;
  • 運行時調用一個對象的任意方法;
  • 修改建構函式、方法、欄位的存取權限,AccessibleObject的setAccessible(boolean flag)方法;
  • 等等

反射是架構中常用的方法。

例如,JUnit通過反射來尋找標記為 @Test 註解的方法,並在運行單元測試時調用這些方法。

對於Web架構,產品開發人員在設定檔中定義介面和類的實現。通過使用反射,架構可以快速動態地初始化所需要的類。

例如,Spring架構使用bean的配置,如:

<bean id="someID" class="com.programcreek.Foo">
   <property name="someField" value="someValue" />
</bean>

當Spring上下文處理<bean>元素時,將使用Class.forName(String)與參數"com.programcreek.Foo"來執行個體化類。然後,它會再次使用反射來得到<property>元素對應的setter方法並設定指定的值。 

相同的機制也用於Servlet web applications:

<servlet>
   <servlet-name>someServlet</servlet-name>
   <servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
<servlet>3.如何使用反射?

通過以下幾個典型的小例子來學習如何使用反射。

例1:擷取對象的類名稱。

package myreflection;
import java.lang.reflect.Method;

public class ReflectionHelloWorld {
   public static void main(String[] args){
        Foo f = new Foo();
        System.out.println(f.getClass().getName());           
   }
}

class Foo {
   public void print() {
        System.out.println("abc");
   }
}

輸出:

myreflection.Foo

例2:調用未知對象的方法。

對於下面的程式碼範例,假象一下對象的類型是未知的。通過使用反射,代碼可以使用該對象,並找出對象有一個名為“print”的方法,然後調用它。

package myreflection;
import java.lang.reflect.Method;

public class ReflectionHelloWorld {
   public static void main(String[] args){
        Foo f = new Foo();

        Method method;
       try {
            method = f.getClass().getMethod("print", new Class<?>[0]);
            method.invoke(f);
       } catch (Exception e) {
            e.printStackTrace();
       }
   }
}

class Foo {
   public void print() {
        System.out.println("abc");
   }
}abc

例3:從Class執行個體建立對象

 package myreflection;

public class ReflectionHelloWorld {
   public static void main(String[] args){
       //create instance of "Class"
       Class<?> c = null;
       try{
            c=Class.forName("myreflection.Foo");
       }catch(Exception e){
            e.printStackTrace();
       }

       //create instance of "Foo"
       Foo f = null;

       try {
            f = (Foo) c.newInstance();
       } catch (Exception e) {
            e.printStackTrace();
       }

        f.print();
   }
}

class Foo {
   public void print() {
        System.out.println("abc");
   }
}

樣本4:擷取建構函式和建立執行個體。

package myreflection;

import java.lang.reflect.Constructor;

public class ReflectionHelloWorld {
   public static void main(String[] args){
       //create instance of "Class"
       Class<?> c = null;
       try{
            c=Class.forName("myreflection.Foo");
       }catch(Exception e){
            e.printStackTrace();
       }

       //create instance of "Foo"
       Foo f1 = null;
        Foo f2 = null;

       //get all constructors
       Constructor<?> cons[] = c.getConstructors();

       try {
            f1 = (Foo) cons[0].newInstance();
            f2 = (Foo) cons[1].newInstance("abc");
       } catch (Exception e) {
            e.printStackTrace();
       }

        f1.print();
        f2.print();
   }
}

class Foo {
    String s;

   public Foo(){}

   public Foo(String s){
       this.s=s;
   }

   public void print() {
        System.out.println(s);
   }
}null
abc

此外,你可以使用Class執行個體來擷取該類實現的介面,父類,聲明的欄位等。

例5:通過反射來修改數組的大小。

package myreflection;

import java.lang.reflect.Array;

public class ReflectionHelloWorld {
   public static void main(String[] args) {
       int[] intArray = { 1, 2, 3, 4, 5 };
       int[] newIntArray = (int[]) changeArraySize(intArray, 10);
        print(newIntArray);

        String[] atr = { "a", "b", "c", "d", "e" };
        String[] str1 = (String[]) changeArraySize(atr, 10);
        print(str1);
   }

   // change array size
   public static Object changeArraySize(Object obj, int len) {
        Class<?> arr = obj.getClass().getComponentType();
        Object newArray = Array.newInstance(arr, len);

       //do array copy
       int co = Array.getLength(obj);
        System.arraycopy(obj, 0, newArray, 0, co);
       return newArray;
   }

   // print
   public static void print(Object obj) {
        Class<?> c = obj.getClass();
       if (!c.isArray()) {
           return;
       }

        System.out.println("\nArray length: " + Array.getLength(obj));

       for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i) + " ");
       }
   }
}

輸出:

Array length: 10
1 2 3 4 5 0 0 0 0 0
Array length: 10
a b c d e null null null null null總結

上面的程式碼範例僅僅展現了Java反射提供的非常小的一部分功能。閱讀這些例子只能讓你初識Java反射,你需要在Oracle的官網閱讀相關文檔來瞭解更多資訊。

java反射教程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.