2012-11-26 376 views
5

我有一個VO的數組列表。這些對象有很多屬性和相應的get/set方法。我想根據我將在運行時獲得的屬性對這個數組列表進行排序。 讓我詳細解釋一下。我的VO是這樣的根據運行時屬性對對象列表進行排序

public class Employee { 
    String name; 
    String id; 

    private String getName() { 
     return name; 
    } 

    private String getId() { 
     return id; 
    } 
} 

我將在運行時得到一個字符串'sortType',它可以是'id'或'name'。我想根據字符串的值對列表進行排序。

我試圖一起使用比較器和反射,但沒有運氣。可能是我沒有正確使用它。我不想使用if循環並創建新的比較器類。任何其他想法?

try catch應該在新類中。這是工作代碼。如果你想使用一個單獨的比較器類,請在下面@波希米亞的評論中找到它。

 String sortType = "name"; // determined at runtime 
     Collections.sort(results, new Comparator<Employee>() { 
     public int compare(Employee c1, Employee c2) { 
      try{ 
      Method m = c1.getClass().getMethod("get" + StringUtils.capitalize(sortType)); 
      String s1 = (String)m.invoke(c1); 
      String s2 = (String)m.invoke(c2); 
      return s1.compareTo(s2); 
      } 
      catch (Exception e) { 
       return 0; 
      } 
     } 
     }); 
+2

請使用適當的語言標籤。 – NPE

+0

哎呀..我已經添加了。 – jijo

+0

如果您發佈使用反射的代碼,我們可能會告訴您哪裏出了問題... – akuhn

回答

15

創建作業的Comparator

public class EmployeeComparator implements Comparator<Employee> { 

    private final String type; 

    public EmployeeComparator (String type) { 
     this.type = type; 
    } 

    public int compare(Employee e1, Employee e2) { 
     if (type.equals("name")) { 
      return e1.getName().compareTo(e2.getName()); 
     } 
     return e1.getId().compareTo(e2.getId()); 
    } 

} 

然後用它

String type = "name"; // determined at runtime 
Collections.sort(list, new EmployeeComparator(type)); 

反射版本是相似的,除了你會在「get」+ type(大寫)的對象上尋找一個方法,然後調用它,並將其強制轉換爲Comparable並使用compareTo(我將嘗試顯示代碼,但是我正在使用我的iPhone及其a一點點的拉伸,b UT這裏去)

public class DynamicComparator implements Comparator<Object> { 
    private final String type; 
    // pass in type capitalised, eg "Name" 
    // ie the getter method name minus the "get" 
    public DynamicComparator (String type) { 
     this.type = type; 
    } 
    public int compare(Object o1, Object o2) { 
     // try-catch omitted 
     Method m = o1.getClass().getMethod("get" + type); 
     String s1 = (String)m.invoke(o1); 
     String s2 = (String)m.invoke(o2); 
     return s1.compareTo(s2); 
    } 
} 

OK ...以下是如何做到這一點沒有創建一個類,使用匿名類(例外處理的代碼編譯):

List<?> list; 
final String attribute = "Name"; // for example. Also, this is case-sensitive 
Collections.sort(list, new Comparator<Object>() { 
    public int compare(Object o1, Object o2) { 
     try { 
      Method m = o1.getClass().getMethod("get" + attribute); 
      // Assume String type. If different, you must handle each type 
      String s1 = (String) m.invoke(o1); 
      String s2 = (String) m.invoke(o2); 
      return s1.compareTo(s2); 
     // simply re-throw checked exceptions wrapped in an unchecked exception 
     } catch (SecurityException e) { 
      throw new RuntimeException(e); 
     } catch (NoSuchMethodException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } catch (InvocationTargetException e) { 
      throw new RuntimeException(e); 
     } 
    } 
}); 
+1

這看起來不錯,很簡單。謝謝 !!會嘗試讓你知道。 – jijo

+0

這絕對是更清潔,爲+1 ... –

+0

真棒的人..!這正是我一直在尋找的!讓我試試看。 – jijo

0

Keep it simple!

如果選擇僅僅idname次使用的if語句。

選擇兩種選擇。這就是如果被髮明的。

或者,如果它有很多屬性,則首先使用反射或將數據存儲在Map中。有時Map比一個班更好。特別是如果你的VO除了getter和setter之外沒有其他方法。

注意,雖然在這種情況下使用反射可能是不安全的,因爲您的客戶端可能會在類似於SQL注入的攻擊中的CGI參數中注入任何術語。

+0

OP指出他的類具有_many_屬性。我想他只是展示了其中的兩個來保持簡單。 – jahroy

+0

這就是問題所在。它不僅僅是id和名字,我的VO非常大,有10多個屬性。 – jijo

+0

添加合理性爲什麼*不*使用反射。 – akuhn

1

執行以下操作:

  • 從客戶
  • 建立吸氣名獲得字段的名稱 - >「獲得」 +字段名(大寫的第一個字符後)
  • 嘗試使用Class.getDeclaredMethod()
  • 如果發現找到反射的方法,調用你的VO類的兩個實例返回Method對象
  • 使用的調用getter方法的結果進行排序
+0

你可能也可以訪問這些字段(如果getters真的很微不足道)。 – akuhn

相關問題