我有一个对象列表,我想通过传递对象的字段名称和顺序(升序或降序)进行排序。例如,我的目标是:
class Person{
private String name;
private String age;
//getters and setters
..........
}
我将List personList
,String name
和布尔isAscending
传递给API方法,以便对personList
进行排序。我可以通过为Comparator编写实现类来实现它,但我希望有一个泛型方法。
也就是说,如果我有Address
个对象,我应该可以按其字段名称对Address
对象列表进行排序(例如streetName
)。
基本上,我正在寻找一种通用排序方法来排序任何类型的列表。有没有这样的API?
答案 0 :(得分:4)
我假设你实际上有你想要使用的属性的getter和setter。无论如何直接使用私有字段可能是一个坏主意。
您可以使用commons-beanutils中的BeanComparator。要对升序进行排序,请使用new BeanComparator("name")
降序new BeanCompartor("name", Collections.reverseOrder())
答案 1 :(得分:1)
@Wouter Coekaerts的答案是最简单的方法。
<强>然而!强>
任何使用反射的解决方案的问题在于,反射操作比非反射(编译代码)等价物要昂贵得多。通常1到2个数量级更贵。
在您的情况下,每次对对象列表进行排序时,比较器将被调用O(NlogN)
次。如果你的应用程序要对很多次排序大型列表......或小列表......使用反射式比较器的开销可能会对应用程序的整体性能产生很大影响。
如果性能成为一个问题(并且分析会告诉您反射比较器有问题),则替代方案是:
手动编写比较器。无论您认为它是否优雅,这都是最简单,最高效的解决方案。
使用运行时源代码生成生成比较器类,然后编译并加载它们。
使用运行时字节码生成生成比较器类并加载它们。
这些可以与查找/缓存机制结合使用,该机制使用组合了类和字段名称的键将比较器存储在哈希表中。 (如果使用代码生成方法,缓存是必不可少的。但是您仍然需要考虑是否经常使用任何给定生成的比较器来证明生成/编译/加载的大一次性开销的合理性一堂课。)
答案 2 :(得分:0)
传递“字符串”以识别字段存在功能障碍。但是如果有一个通用的api方式,它可能会要求你使用一个map或者有一个get(“fieldname”)方法来获得它所依据的字段。
如果您要更改排序方式,我会使用Comparator而不是Comparable。
答案 3 :(得分:0)
好像你需要一个reflection API。
import java.lang.reflect.Field;
String fieldValue(Object obj, String fieldName) {
Class c = obj.class;
Field f = c.getField(fieldName);
return (String)f.get(obj);
}
可能会有一些输入泄漏,但您可以通过f.getType()
检查字段的类型来手动修复它。