Java 仅基于字段名对类数组进行排序
我有一个应用程序,其中用户向我提供一个字段的名称,例如Java 仅基于字段名对类数组进行排序,java,sorting,reflection,Java,Sorting,Reflection,我有一个应用程序,其中用户向我提供一个字段的名称,例如name或costInCents,我必须按该字段排序。我有办法保证字段名是正确的。这个应用程序导致了一个复杂问题,即我无法使我的类具有可比性并实现特定的compareTo(),因为使用compareTo()的自定义实现时,我需要知道在实现时要使用哪些字段/方法 为了实现这个目标,我尝试使用反射来匹配字段和它的访问器。这是我想做的事情 ClassProduct是一个简单的POJO类,我想对其实例进行两两比较: 公共类产品 { 最后的字符串名;
name
或costInCents
,我必须按该字段排序。我有办法保证字段名是正确的。这个应用程序导致了一个复杂问题,即我无法使我的类具有可比性
并实现特定的compareTo()
,因为使用compareTo()
的自定义实现时,我需要知道在实现时要使用哪些字段/方法
为了实现这个目标,我尝试使用反射来匹配字段和它的访问器。这是我想做的事情
ClassProduct
是一个简单的POJO类,我想对其实例进行两两比较:
公共类产品
{
最后的字符串名;
最终整数数量;
最终长期成本激励;
公共产品(最终字符串名称、最终整数数量、最终长成本)
{
this.name=名称;
这个。数量=数量;
this.costInCents=costInCents;
}
公共字符串getName()
{
返回名称;
}
公共整数getQuantity()
{
退货数量;
}
公共长期成本激励()
{
返回成本激励;
}
}
以及我的Main
类,该类当前不完整:
公共类主{
公共静态void main(字符串[]args){
最终产品[]productArray=
{
新产品(“Clorox湿巾”,50700L),
新产品(“桌椅”,1012000L),
新产品(“TV”,53000升),
新产品(“书架”,512000L),
新产品(“水瓶”,20700L),
};
//以下void方法应该使用类似于array.sort()或Collections.sort()的内容进行就地排序,
//但我也乐于接受涉及Stream::sorted()或类似内容的解决方案,它们返回一个排序数组。
sortByField(产品阵列,“成本激励”);
sortByField(productArray,“名称”);
}
私有无效排序字段(最终产品[]productArray,最终字符串排序字段名称)
{
final Field sorterField=getSorterField(sorterFieldName,LiteProduct.class);//以某种方式获取字段
最后一个方法sorterraccessor=getsorterraccessor(sorterField,LiteProduct.class);//给定字段,这很简单
Arrays.sort((产品p1,产品p2)->((可比)sorterraccessor.invoke(p1)).compareTo(sorterraccessor.invoke(p2))>0;//捕获?而不是对象
}
}
不幸的是,Arrays.sort()
行导致编译时错误,消息是Capture of?而不是对象
。我已尝试将第二个参数转换为Comparable
,Comparable,您可以尝试以下方法:
public class Test{
public static void main(String arg[]){
final Product[] productArray =
{
new Product("Clorox wipes", 50, 700L),
new Product("Desk chair", 10, 12000L),
new Product("TV", 5, 30000L),
new Product("Bookcase", 5, 12000L),
new Product("Water bottle", 20, 700L),
};
Arrays.sort(productArray,(p1, p2) -> p1.getName().compareTo(p2.getName()));
for(Product p: productArray){
System.out.println(p.getName());
}
}
}
在本例中,比较器是一个函数接口,所以我使用了lambad表达式。但您也可以这样做您可以为每个字段编写一个比较器,并通过映射按名称使用它:
public class Product
{
private final static Map<String,Comparator<Product>> COMPARATORS;
static {
COMPARATORS = new HashMap<>();
COMPARATORS.put("name", new NameComparator());
COMPARATORS.put("costInCents", new CostInCentsComparator());
}
final String name;
final Integer quantity;
final Long costInCents;
public Product(final String name, final Integer quantity, final Long costInCents)
{
this.name = name;
this.quantity = quantity;
this.costInCents = costInCents;
}
public String getName()
{
return name;
}
public Integer getQuantity()
{
return quantity;
}
public Long getCostInCents()
{
return costInCents;
}
static class NameComparator implements Comparator<Product> {
@Override
public int compare(Product o1, Product o2) {
return o1.getName().compareTo(o2.getName());
}
}
static class CostInCentsComparator implements Comparator<Product> {
@Override
public int compare(Product o1, Product o2) {
return o1.getCostInCents().compareTo(o2.getCostInCents());
}
}
static Comparator<Product> getComparator(String name) {
return COMPARATORS.get(name);
}
}
您可能需要做一些小的更改,比如将其设置为空安全,或者做一些可能是最好的方法—使用排序策略。无需反射,与更复杂的排序逻辑兼容:
Map<String, Comparator<Product>> sortingStrategies = new HashMap<>(){
{
put("costInCents", Comparator.comparingLong(p->p.costInCents));
put("quantity", Comparator.comparingLong(p->p.quantity));
put("name", Comparator.comparing(p->p.name));
}
};
private void sortByField(final Product[] productArray, final String sorterFieldName)
{
Arrays.sort(productArray, sortingStrategies.get(sorterFieldName));
}
Map sortingStrategies=newhashmap(){
{
put(“成本激励”,比较器。比较长(p->p.成本激励));
放置(“数量”,比较器。比较长(p->p.quantity));
put(“name”,Comparator.comparing(p->p.name));
}
};
私有无效排序字段(最终产品[]productArray,最终字符串排序字段名称)
{
sort(productArray,sortingStrategies.get(sorterFieldName));
}
可比性此答案举例说明了为什么我不能使用此方法:我需要按用户提供名称的字段进行排序。您的方法只是按名称排序。@Jason ok。你可以创建两个Comparator的实现并使用你想要的,毕竟你有办法保证由用户提供的字段名称会非常相似,但是使用Comparator会更好,我向上投票,谢谢你的回复。考虑到我事先不知道我的字段将是什么,我认为有必要对Product.getFields()
的结果进行循环,然后填充映射。再次感谢。@Qwer-Izuken如果您使用Comparator.comparating
,在上面使用Comparator.comparingIng/Long
的实例中,比较,可以说是实现上的成功吗?询问排序策略实现自动化的原因。实际上,对于长包装类使用Comparator.compare更好。但是如果您使用的是原语long,那么应该使用comparingLong。这是一种与公认的方法类似的方法,只需要多一点代码:)谢谢@Turo@Jason这段代码的优点是产品知道它的可排序字段,并且只有在那里才有响应性(对于新字段,只有产品更改,而不是Main。并且不需要反射),因此,我认为组合将是最好的:-)
Map<String, Comparator<Product>> sortingStrategies = new HashMap<>(){
{
put("costInCents", Comparator.comparingLong(p->p.costInCents));
put("quantity", Comparator.comparingLong(p->p.quantity));
put("name", Comparator.comparing(p->p.name));
}
};
private void sortByField(final Product[] productArray, final String sorterFieldName)
{
Arrays.sort(productArray, sortingStrategies.get(sorterFieldName));
}