java反射--Field用法實踐與IllegalArgumentException構造

 

一般而言,當用戶使用一個類的時候,應該先知道這個類,而後通過這個類產生實例化對象,“反射”指的是通過對象找到類。
 

簡單來說:

java反射機制簡單例子

 

 

使用反射設置屬性的例子:

代碼:

實體類

package JavaCharacter;

/**
 * Created by jiangyayi on 19/5/24.
 */
public class Car {
    private String brand;
    private String color;
    private int maxSpeed;

    public Car() {
        System.out.println("init car!!");
    }

    public Car(String brand, String color, int maxSpeed) {
        this.brand = brand;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }

    public void introduce() {
        System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:" + maxSpeed);
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}

測試類

package JavaCharacter;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * Created by jiangyayi on 19/5/24.
 */
public class ReflexTest {

    public static Car initByDefaultConst() throws Throwable{

        //①通過類裝載器獲取Car類對象
        ClassLoader loader =Thread.currentThread().getContextClassLoader();
        //loadclass可以通過getclass來獲取地址
        Class clazz=loader.loadClass("JavaCharacter.Car");


        //②獲取類的默認構造器對象並通過它實例化Car
        Constructor constructor=clazz.getDeclaredConstructor((Class[]) null);
        Car car = (Car) constructor.newInstance();
        //③通過反射方法設置屬性
        Method setBrand = clazz.getMethod("setBrand", String.class);
        setBrand.invoke(car, "紅旗CA72");
        Method setColor = clazz.getMethod("setColor", String.class);
        setColor.invoke(car, "黑色");
        Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
        setMaxSpeed.invoke(car, 200);
        return car;
    }


    public static void main(String args[]) throws Throwable {
        Car car = initByDefaultConst();
        System.out.println(car.getClass()); //打印類
        car.introduce();

        ReflexTest test =new ReflexTest();

        System.out.println(test.getClass()); //使用實例的getClass方法找到類

        System.out.println("-----------cls------------"); //打印類

        Class<?> cls=test.getClass(); //取得class對象

        System.out.println(cls.getClass()); //打印類
        System.out.println(cls.getName());  //使用反射機制打印名稱

    }
}

 

類Field定義:

http://tool.oschina.net/apidocs/apidoc?api=jdk-zh

Field是一個類,位於java.lang.reflect包下。在Java反射中Field類描述的是類的屬性信息,功能包括:

1.獲取當前對象的成員變量的類型
2.對成員變量重新設值

方法:

1、public Field[] getFields() throws SecurityException

返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共public字段。返回數組中的元素沒有排序,也沒有任何特定的順序。如果類或接口沒有可訪問的公共字段,或者表示一個數組類、一個基本類型或 void,則此方法返回長度爲 0 的數組。
getDeclaredFields(): 獲取類中所有的屬性(public、protected、default、private),但不包括繼承的屬性,返回 Field 對象的一個數組


2、public Field getField(String name throws NoSuchFieldException, SecurityException

返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。 name 參數是一個 String,用於指定所需字段的簡稱。

要反映的字段由下面的算法確定。設 C 爲此對象所表示的類:

  1. 如果 C 聲明一個帶有指定名的公共字段,則它就是要反映的字段。
  2. 如果在第 1 步中沒有找到任何字段,則該算法被遞歸地應用於 C 的每一個直接超接口。直接超接口按其聲明順序進行搜索。
  3. 如果在第 1、2 兩步沒有找到任何字段,且 C 有一個超類 S,則在 S 上遞歸調用該算法。如果 C 沒有超類,則拋出 NoSuchFieldException

 

3、public Field[] getDeclaredFields() throws SecurityException

 

返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。包括公共public、保護protected、默認(包)訪問和私有private字段,但不包括繼承的字段。 返回數組中的元素沒有排序,也沒有任何特定的順序。如果該類或接口不聲明任何字段,或者此Class 對象表示一個基本類型、一個數組類或 void,則此方法返回一個長度爲 0 的數組。

 

4、public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException

返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。 name 參數是一個 String,它指定所需字段的簡稱。注意,此方法不反映數組類的 length 字段。

 

方法摘要:


常見錯誤
1.set(Object obj, Object value) 時,新value和原value的類型不一致導致,如下:無法轉換類型導致 java.lang.IllegalArgumentException(注意:反射獲取或者修改一個變量的值時,編譯器不會進行自動裝/拆箱,所以int 和Integer需手動修改)


2.set(Object obj, Object value) 時,變量訪問檢查導致的 IllegalAccessException。由於 Field 繼承自 AccessibleObject , 我們可以使用 AccessibleObject.setAccessible() 方法告訴安全機制,這個變量可以訪問即可解決,如field.setAccessible(true)。

3、getField(String name) 或getFields() 獲取非 public 的變量,編譯器會報 java.lang.NoSuchFieldException 錯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章