2012-11-26 310 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

相关问题