[英]Cast generic object to generic class
我想將一個通用對象傳遞到我的方法中,並讓它獲取屬性名稱,類型和值。
這是我的課
public class Login {
public String token;
public String customerid;
public Class1 class1;
public Class2 class2;
public class Class1 {
public Class3 class3;
public String string1;
public class Class3 {
public int int1;
public String string2;
public String string3;
}
}
public class Class2 {
public int int1;
public String string2;
public String string3;
}
}
我希望輸出看起來像這樣
User Preferences customerid - class java.lang.String - 586969
User Preferences token - class java.lang.String - token1
User Preferences string1 - class java.lang.String - string1Value
User Preferences string2 - class java.lang.String - string2Value
User Preferences string3 - class java.lang.String - string3Value
我現在擁有的代碼給了我一些問題。 這是代碼:
try {
// Loop over all the fields and add the info for each field
for (Field field : obj.getClass().getDeclaredFields()) {
if(!field.isSynthetic()){
field.setAccessible(true);
System.out.println("User Preferences " + field.getName() + " - " + field.getType() + " - " + field.get(obj));
}
}
// For any internal classes, recursively call this method and add the results
// (which will in turn do this for all of that subclass's subclasses)
for (Class<?> subClass : obj.getClass().getDeclaredClasses()) {
Object subObject = subClass.cast(obj); // ISSUE
addUserPreferences(subObject, prefs);
}
}catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}catch(ClassCastException e) {
e.printStackTrace();
}
Im遇到了問題,獲取子對象(在本例中為Class1
或Class2
)並將其傳遞給方法。 我嘗試使用類而不是對象,但是后來我無法從類中獲取對象。
無論如何,有沒有將我傳遞給子類的對象強制轉換?
謝謝
您有幾種選擇:
一種選擇是考慮定義一些接口,該接口定義提供用戶首選項的對象,例如:
interface UserPreferenceProvider {
Map<String,Object> getUserPrefences();
}
然后,您可以使您的類實現該接口,例如:
public class Login implements UserPreferenceProvider {
...
public class Class1 implements UserPreferenceProvider {
...
public class Class2 implements UserPreferenceProvider {
...
}
}
}
他們的getUserPreferences()
實現在何處返回要寫入的首選項。
然后,您可以將addUserPreferences()
更改為UserPreferenceProvider
,並在遍歷字段時檢查是否找到UserPreferenceProvider
,如果是,則將其addUserPreferences()
轉換為該值並將其傳遞給addUserPreferences()
。
這也將更准確地代表您的意圖。 我相信這里的根本問題是,您要嘗試使用這些任意對象,雖然從概念上講它們具有某些共同點,但是您的代碼並不代表該概念。 我知道這有點含糊,但是由於沒有讓您的代碼反映出來,您現在面臨着笨拙的任務,即必須找到一種方法來強制以通用方式對待任意對象。
第二種選擇是創建一個自定義批注,例如@UserPreference
,並使用它來標記您要編寫的字段。 然后,您可以遍歷字段,並在帶有此批注的字段中找到時,將其單個鍵/值添加到用戶首選項(即,對字段本身進行操作,而不是將整個容器類傳遞給addUserPreferences()
)。
這可能比您設計的第一個選項更為合適。 它的優點是不必強迫您使用這些接口,也不必編寫代碼即可將數據打包到映射或getUserPreferences()
; 它還可以讓您更精細地控制導出哪些屬性的方法-本質上,這會將您的關注點從對象轉移到各個屬性本身。 這將是使用最少的代碼的一種非常干凈的方法。
如果您已經具有bean風格的getter,則使此操作更方便的一種可能方法是使用例如Apache BeanUtils獲取值,而不是滾動自己的值。 但是對於您的情況,這是反射的相當基本的用途,可能不值得附加的依賴。
這是獲取使用自定義注釋標記的對象的字段名稱和值的示例。 第二個注釋用於標記包含應遞歸地放入並掃描的對象的字段。 非常簡單:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
// @UserPreference marks a field that should be exported.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface UserPreference {
}
// @HasUserPreferences marks a field that should be recursively scanned.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface HasUserPreferences {
}
// Your example Login class, with added annotations.
class Login {
@UserPreference public String token; // <= a preference
@UserPreference public String customerid; // <= a preference
@HasUserPreferences public Class1 class1; // <= contains preferences
public class Class1 {
@HasUserPreferences public Class2 class2; // <= contains preferences
@UserPreference public String string1; // <= a preference
public class Class2 {
public int int1; // <= not a preference
@UserPreference public String string2; // <= a preference
@UserPreference public String string3; // <= a preference
}
}
// Construct example:
public Login () {
token = "token1";
customerid = "586969";
class1 = new Class1();
class1.string1 = "string1Value";
class1.class2 = class1.new Class2();
class1.class2.string2 = "string2Value";
class1.class2.string3 = "string3Value";
}
}
public class ValueScanExample {
// Recursively print user preferences.
// Fields tagged with @UserPreference are printed.
// Fields tagged with @HasUserPreferences are recursively scanned.
static void printUserPreferences (Object obj) throws Exception {
for (Field field : obj.getClass().getDeclaredFields()) {
// Is it a @UserPreference?
if (field.getAnnotation(UserPreference.class) != null) {
String name = field.getName();
Class<?> type = field.getType();
Object value = field.get(obj);
System.out.println(name + " - " + type + " - " + value);
}
// Is it tagged with @HasUserPreferences?
if (field.getAnnotation(HasUserPreferences.class) != null) {
printUserPreferences(field.get(obj)); // <= note: no casts
}
}
}
public static void main (String[] args) throws Exception {
printUserPreferences(new Login());
}
}
輸出為:
token - class java.lang.String - token1
customerid - class java.lang.String - 586969
string2 - class java.lang.String - string2Value
string3 - class java.lang.String - string3Value
string1 - class java.lang.String - string1Value
請注意,輸出中不存在“ int1”,因為它沒有被標記。 您可以在ideone上運行該示例 。
原始的基本注釋示例仍可以在此處找到。
順便說一下,您可以使用批注來做各種有趣的事情,例如,添加可讓您覆蓋首選項中的字段名稱的可選參數,添加可讓您指定自定義對象的參數->用戶首選項字符串轉換器,等等。
我已經想出一種簡單的方法來做到這一點。 如果有人對您的建議有所改進,或者對代碼有疑問,請發表評論。 下面的代碼對我有用
try {
Class<?> objClass = obj.getClass();
List<Object> subObjectList = new ArrayList<Object>();
// Loop over all the fields and add the info for each field
for (Field field: objClass.getDeclaredFields()) {
if(!field.isSynthetic()){
if(isWrapperType(field.getType())){
System.out.println("Name: " + field.getName() + " Value: " + field.get(obj));
}
else{
if(field.getType().isArray()){
Object[] fieldArray = (Object[]) field.get(obj);
for(int i = 0; i < fieldArray.length; i++){
subObjectList.add(fieldArray[i]);
}
}
else{
subObjectList.add(field.get(obj));
}
}
}
}
for(Object subObj: subObjectList){
printObjectFields(subObj);
}
}catch(IllegalArgumentException e){
// TODO Auto-generated catch block
e.getLocalizedMessage();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.getLocalizedMessage();
}
isWrapperType
來自我在此堆棧溢出問題中找到的代碼。 我所做的就是將String
和int
添加到集合中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.