簡體   English   中英

使用反射將值設置為對象

[英]Setting a value into a object using reflection

我有一個具有很多屬性的對象,每個屬性都有它的getter和setter。 每個屬性都有一個非基本類型,我在運行時不知道。

例如,我所擁有的是:

public class a{

    private typeA attr1;
    private typeB attr2;

    public typeA getAttr1(){ return attr1; }
    public typeB getAttr2(){ return attr2; }

    public void setAttr1(typeA at){ attr1 = at; }
    public void setAttr2(typeB at){ attr2 = at; }
}

public class typeA{
    public typeA(){
        // doesn't matter
    }
}

public class typeB{
    public typeB(){
        // doesn't matter
    }
}

因此,使用反射,我獲得了屬性的setter方法。 以標准方式設置值是這樣的:

a test = new a();
a.setAttr1(new typeA());

但是我怎么能用反射呢? 我已經使用了反射的setAttr1()方法,但我不知道如何創建一個新的typeA對象插入到setter中。

使用Class#newInstance()

Class<TypeA> cls = TypeA.class;
TypeA typeA = cls.newInstance();

或者,在您必須確定方法參數類型的特定情況下:

Class<?> cls = setterMethod.getParameterTypes()[0];
Object value = cls.newInstance();
setterMethod.invoke(bean, value);

您可以在Sun教程中了解有關該主題的反射的更多信息。 也就是說,類名應該以大寫字母開頭。 我已經在上面的例子中糾正了它。

順便說一句,你可能會發現這里提到的工具之一也很有用,而不是重新發明Javabean反射輪。

使用Class對象中的getDeclaredFields()方法獲取所有字段,然后使用field.set(classInstance, value)設置實例中字段的值。 注意:如果字段為私有,則可能必須將字段上的可訪問標志設置為true。 無需依賴setter方法。

我遇到過一些我正在做的事情。 我的一般結論是,每當我覺得我需要一個有一堆字段的課時,我做錯了。 這是我的思考過程:

問題: - 我需要大量的字段來保存這些數據 - 所有這些字段都需要大量的樣板

解:

  • 使用反射減少樣板<“你在這里”
  • 使用元數據指定字段的使用方式

新問題:

  • 當有人看到代碼時,反思很難理解
  • 一旦你使用meta來消除更多的樣板,除了通過元數據之外,這些字段在代碼中通常沒有提及 - 為什么它們是字段?
  • 在代碼中指定元數據會變得非常快(順便說一下,最簡單的方法是字符串數組)

解決方案:開始在集合中存儲數據並在外部數據文件中指定元數據

新問題:錯誤變得難以找到

對錯誤檢查一絲不苟,並對您的錯誤消息非常明確。 確保可能使用您的代碼的任何其他程序員讀取錯誤消息。 嘗試指示元數據何時丟失或錯誤以及程序員應如何更新元數據 - 包括元數據文件的位置。

問題:沒有類型安全

是的,這有時令人討厭。 我最終在元數據中包含類型信息,這樣如果有人在字段中輸入了錯誤的值,就可以檢測到它 - 基本上這會將類型安全從構建時間移動到運行時間,這在我的情況下很好。

問題:在對象的整個生命周期中需要重復元數據

我不會在每次使用時按名稱查找它,而是在開頭解析元數據並將其放在一個對象中(稱之為IntHolder)。 這個持有者最終會在哈希表中,它將包含當前值以及對已解析元數據的引用。

以下是我的元數據最終會出現在樣式表的一個字段中:

FieldName:     Age
FieldType      Integer
ScreenBinding: AgeTextField
DBBinding:     User.age
Validation:    IntRange(0, 120); "Age is out of range"

字段名稱可能是它向用戶顯示的方式,也可能只是在程序中使用。 通常,您不需要按名稱直接操作此類數據 - 但有時您會這樣做。

當你需要使用時,使用getInt(“Age”)和setInt(“Age”,12)而不是getAge()和setAge(12) - 稍微冗長但不是真正的問題。

如果這是一個問題,你可以制作getAge / setAge輔助方法,你永遠不需要知道它不是一個字段,但它確實會再次開始在樣板上堆積。

FieldType:指定它的存儲方式,並允許您實現類型檢查。

ScreenBinding和DBBinding用於將值復制到其他系統和從其他系統復制。 我還使用這種機制將數據從服務器傳輸到客戶端並返回。

有趣的是驗證。 當從屏幕上提取數據時,它可以以非常循序的方式傳遞給驗證器。 在提交到DB之前可以使用相同的驗證器。

驗證器可以做很多事情,它們可以充當觸發器(如果值更改,執行此操作)或操作(當用戶提交屏幕時,執行此操作)。 這些是一個簡單的對象,能夠獲取一個值(通過一個接口) - 它們可以像你想的那樣靈活或強大,但除了通過元數據之外不直接綁定到任何對象。

這種方法的唯一問題是你必須是喜歡編寫fixture而不是容易出錯的樣板文件的程序員。 (是的,我發現時間量大致相等,但是當我必須實現樣板時,我往往會變得非常慢)

這樣做了幾次我真的很喜歡這個模式,但實現起來很困難。 下次我這樣做時,我會嘗試將它變成某種類型的庫。

如果你想設置一個“新鮮”的對象在你的類的每一個二傳手,你通常可以通過獲取這樣做Method ,每個方法你得到的Class的論點getParameterTypes()為每個類調用Class.newInstance() ...並交叉你的手指(應該打破原始類型 - 我懷疑Java在這里做了自動裝箱)。 您總是可以詢問參數是否是一個pimitive調用isPrimitive()

為什么要為類的原始字段設置“空”實例? 它們已經初始化。 你想“重置”它們嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM