[英]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<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方法。
我遇到過一些我正在做的事情。 我的一般結論是,每當我覺得我需要一個有一堆字段的課時,我做錯了。 這是我的思考過程:
問題: - 我需要大量的字段來保存這些數據 - 所有這些字段都需要大量的樣板
解:
新問題:
解決方案:開始在集合中存儲數據並在外部數據文件中指定元數據
新問題:錯誤變得難以找到
對錯誤檢查一絲不苟,並對您的錯誤消息非常明確。 確保可能使用您的代碼的任何其他程序員讀取錯誤消息。 嘗試指示元數據何時丟失或錯誤以及程序員應如何更新元數據 - 包括元數據文件的位置。
問題:沒有類型安全
是的,這有時令人討厭。 我最終在元數據中包含類型信息,這樣如果有人在字段中輸入了錯誤的值,就可以檢測到它 - 基本上這會將類型安全從構建時間移動到運行時間,這在我的情況下很好。
問題:在對象的整個生命周期中需要重復元數據
我不會在每次使用時按名稱查找它,而是在開頭解析元數據並將其放在一個對象中(稱之為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.