java—仅基于字段名对类数组进行排序

xzabzqsa  于 2021-06-30  发布在  Java
关注(0)|答案(3)|浏览(416)

我有一个应用程序,其中一个用户向我提供一个字段的名称,例如 name 或者 costInCents ,我必须按字段排序。我有办法保证字段名是正确的。这个应用程序造成了一个复杂的问题,那就是我根本无法使我的类 Comparable 并实施具体的 compareTo() ,因为使用 compareTo() 我需要知道在实现时要使用哪些字段/方法。
为了实现这个目标,我尝试使用反射来匹配字段和它的访问器。这是我想做的事。
班级 Product 是一个简单的pojo类,我要成对比较其示例:

public class Product
{

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

还有我的 Main 类,当前未完成:

public class Main {

    public static void main(String[] args) {
        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),
                };

        // The following void methods are supposed to sort in-place with something like Arrays.sort() or Collections.sort(),
        // but I am also open to solutions involving stuff like Stream::sorted() or similar ones, which return a sorted array.
        sortByField(productArray, "costInCents");
        sortByField(productArray, "name");
    }

    private void sortByField(final Product[] productArray, final String sorterFieldName)
    {
        final Field sorterField = getSorterField(sorterFieldName, LiteProduct.class); // Gets the Field somehow
        final Method sorterAccessor = getSorterAccessor(sorterField, LiteProduct.class);    // Given the Field, this is easy
        Arrays.sort((Product p1, Product p2)->((Comparable<?>)sorterAccessor.invoke(p1)).compareTo(sorterAccessor.invoke(p2)) > 0); // Capture of ? instead of Object
    }
}

不幸的是 Arrays.sort() 行导致编译时错误,消息 Capture of ? instead of Object . 我试着把第二个论点 Comparable<?> , Comparable<? super sorterField.getType() 等等,没有运气。思想?

sdnqo3pr

sdnqo3pr1#

可能是最好的方法-使用排序策略。无需反射,与更复杂的排序逻辑兼容:

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

8dtrkrch2#

你可以试试这个:

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

在本例中,comparator是一个函数接口,因此我使用lambad表达式。但你也可以这么做

djp7away

djp7away3#

您可以为每个字段编写一个比较器,并通过Map按名称使用它:

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

}

在主课堂上用这个

public class Main {

    public static void main(String[] args) {
        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),
                };

        // The following void methods are supposed to sort in-place with something like Arrays.sort() or Collections.sort(),
        // but I am also open to solutions involving stuff like Stream::sorted() or similar ones, which return a sorted array.
        sortByField(productArray, "costInCents");
        sortByField(productArray, "name");
    }

    private static void sortByField(final Product[] productArray, final String sorterFieldName)
    {
        Arrays.sort(productArray, Product.getComparator(sorterFieldName));
    }
}

您可能需要做一些小的更改,比如使其为空安全的或其他的

相关问题