7

我有一个List对象[VO]。这些对象有许多属性和相应的 get/set 方法。我想List根据我将在运行时获得的属性对其进行排序。让我详细解释一下...

我的VO是这样的:

public class Employee {
    String name;
    String id;

    private String getName() {
        return name;
    }

    private String getId() {
        return id;
    }
}

我将sortType在运行时得到一个字符串,它可以是"id""name"。我想根据String.

我曾尝试同时使用Comparator和反射,但没有运气。可能是我没有正确使用它。我不想使用条件if块分支来创建Comparator需要的任何新的特定[匿名内部类](在运行时)。还有其他想法吗?


try catch 应该在新类中。这是工作代码。如果您想为 使用单独的类Comparator,请在下面的@Bohemian 评论中找到它。

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

4 回答 4

18

为作业创建一个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”+类型(大写)的对象上寻找一个方法并调用它并将其硬转换为 Comparable 并使用 compareTo(我将尝试显示代码,但我我正在使用我的 iPhone,这有点牵强,但这里)

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

好的......这是在创建类的情况下使用匿名类(具有异常处理以便代码编译)的方法:

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);
        }
    }
});
于 2012-11-27T05:13:21.470 回答
2

请执行下列操作:

  • 从客户端获取字段名称
  • 构建 getter 的名称 -> "get" + 字段名称(在第一个字符大写之后)
  • 尝试使用Class.getDeclaredMethod()找到具有反射的方法
  • 如果找到,在您的VO类的两个实例上调用返回的 Method 对象
  • 使用调用的 getter 方法的结果进行排序
于 2012-11-27T05:10:54.927 回答
1

把事情简单化!

如果选择只有idname——使用 if 语句。

在两个选择之间进行选择。这就是如果被发明的目的。

或者,如果它有很多属性,那么使用反射,或者Map首先将数据存储在 a 中。有时Map比一堂课更好。特别是如果您的 VO 没有除 getter 和 setter 之外的方法。

但请注意,在这种情况下使用反射可能是不安全的,因为您的客户端可能会在类似于 SQL 注入的攻击中在 CGI 参数中注入任何术语。

于 2012-11-27T05:02:41.443 回答
0

无论出于何种原因,您都不想使用if语句......利用 usingjava.lang.reflect.Field

String sortType = "name"; // determined at runtime
Comparator<Employee> comparator = new Comparator<Employee>(){
    public int compare(Employee e0, Employee e1){
        try {
            Field sortField = e0.getClass().getField(sortType);
            return sortField.get(e0).toString()
                       .compareTo(sortField.get(e1).toString()));

        } catch(Exception e) {
            throw new RuntimeException(
                "Couldn't get field with name " + sortType, e);
        }
    };
}

但这仅适用于字符串字段-下面处理任何类型的字段(或至少,Comparable字段)

String sortType = "name"; // determined at runtime
Comparator<Employee> comparator = new Comparator<Employee>(){
    public int compare(Employee e0, Employee e1){
        try {
            Field sortField = e0.getClass().getField(sortType);
            Comparable<Object> comparable0
                = (Comparable<Object>) sortField.get(e0);
            Comparable<Object> comparable1
                = (Comparable<Object>) sortField.get(e1);

            return comparable0.compareTo(comparable1);

        } catch(Exception e) {
            throw new RuntimeException(
                          "Couldn't get field with name " + sortType, e);
        }
    };
}

** 但是请注意,它不会忽略String/ Character/char的大小写(尽管它会考虑负数) - 例如,它将"Z"在小写之前排序大写"a"。如果您想考虑这两种情况,我看不到解决方法(等待它......)if声明!

JavaSortAnyTopLevelValueObject您可以在我的Github 项目中看到处理所有这些情况的完整实现,以及以下情况(在依赖项 JAR 中也可用):

  • 处理多个sort-tie优先级字段(即:首先按优先级 0 排序,按优先级 1 排序第二个 [如果有关联],按...排序第三个)
  • 按每个排序参数处理升序/降序排序
  • 处理 { 、或}的任何顶级public(或调用位置中可见的修饰符)字段类型primitiveBoxed PrimitiveString
  • 忽略字符大小写
于 2020-05-20T07:04:32.740 回答