2014-04-14 156 views
1

我想將一個泛型對象傳入我的方法,並讓它獲得屬性名稱,類型和值。將泛型對象轉換爲泛型類

這裏是我的

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(); 
    } 

獲取子對象,在這種情況下Class1Class2,並將它傳遞給該方法具有一個問題就是即時通訊。我已經嘗試了一個類而不是一個對象,但是我無法從類中獲取對象。

有無論如何投射我傳入子類的對象?

感謝

回答

0

我已經想出了一個簡單的方法來做到這一點>用戶首選項字符串轉換器等。任何人有任何建議,使這個更好或有問題的代碼請評論。下面的代碼不爲我工作

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來自碼我this堆棧溢出問題找到。我所做的只是將Stringint添加到集合中。

0

您有幾種選擇:


一種選擇是考慮定義一些接口定義了一個對象,它提供用戶偏好,如:

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()

這樣可以更準確地表示你的意圖。我相信這裏的根本問題是你有這些隨意的對象,你試圖去處理,而在概念上他們有一些共同的東西,你的代碼並不代表這個概念;我知道這有些含糊,但是由於沒有讓代碼反映出來,你現在面臨着一個尷尬的任務:必須找到一種方法來強制你的任意對象以一種常見的方式來對待。


第二個選項可以是創建自定義註釋,例如, @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」是不存在的輸出,因爲它不標記。你可以run the example on ideone

原來的基本註解例如仍然可以發現here

你可以做各種有趣的事情說明,順便說一下,例如補充一點,讓你在首選項覆蓋字段名可選參數,添加參數,可以讓你指定一個自定義對象 -

+0

對於第二種情況,我怎麼會叫從註釋'addUserPreferences()''@ UserPreference'?我對註釋不熟悉,所以我有點失落。 – BigT

+0

@BigT它的工作方式是使用反射掃描對象的所有字段。你會檢查每個字段,看它是否有*註釋,例如通過使用['Field.getAnnotation(UserPreference.class)'](http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Field.html#getAnnotation(java.lang.Class中))。如果確實如此,那麼現在您可以爲該字段指定一個「String」名稱,併爲該字段指定一個「Object」值,您可以將其作爲單獨的首選項進行編寫。當然,你仍然通過內部課程遞歸併繼續尋找這些領域,就像你現在正在做的那樣。這是否更有意義? –

+0

@BigT查看我添加的註釋示例。 –