对对象有多种类型的排序

时间:2014-04-16 20:50:04

标签: java

假设我有一个带有多个String字段的java对象。

public class Person {
    private String field1
    // keeps going 

我希望能够根据我选择的任何字段对人员列表进行排序。

我知道我可以使用比较器接口并实现多个compareTo,如主题所述:How do I make 2 comparable methods in only one class?

但在使用Collections.sort()

但是如果没有这些重复的代码,我有什么方法可以做到这一点吗?

4 个答案:

答案 0 :(得分:8)

如果您不喜欢Comparator类的详细程度,那么请使用Java 8及其lambda表达式:

Comparator<Person> byName = Comparator.comparing(Person::getName);
Comparator<Person> byBirthDate = Comparator.comparing(Person::getBirthDate);

答案 1 :(得分:3)

  

我希望能够对人员列表进行排序   取决于我选择的任何领域。

@JB Nizet Java 8 的解决方案将成为一个技巧,但它仅适用于Java 8.低于8的版本怎么样?被大多数人使用?

我将为您提供我认为比Java 8更低版本的简单解决方案。

你真的不需要创建多个Comparator课程(你提到它为#34;重复代码&#34;)。如何使用适当的技术,如条件或枚举?

private Comparator<YourClass> getComparator(MyPropertiesEnum myEnum) {
   return new Comparator<YourClass>() {

      @Override
      public int compare(YourClass o1, YourClass o2) { {
         switch (myEnum) {
            case FIRSTNAME:
               // implementation for firstname
            break;
            case LASTNAME:
              // implementation for lastname
            break;
            default:
               // implementation for default version
            break;           
         }
      }
   };
}

MyPropertiesEnum的位置如下:

public enum MyPropertiesEnum {
   FIRSTNAME, LASTNAME, AGE;
}

注意:如果条件适合您,也可以使用正确的条件。

希望它能帮助您解决问题。

答案 2 :(得分:1)

public class Person {
    private String field1;
    private String field2;
    ...
    private Map<String,String> allFields;

    ...
    public void setField1 (String value) {
        field1 = value;
        allFields.put("field1",value);
    }

    public void setField2 (String value) {
        field2 = value;
        allFields.put("field2",value);
    }

或者你想要的任何名字。或者,您可以使用enum代替String作为地图密钥。这说明为什么顺便说一句,使用getter和setter是一个好主意;你不能通过使用公共成员字段并让客户直接分配给他们来做到这一点。但是,由于您创建字段private并需要设置器来设置它们,因此您可以确保String字段和地图条目始终匹配。

现在,通过在Comparator中查找所需的字段,可以轻松编写单个allFields

答案 3 :(得分:1)

这是一种通用方法的草图。

只要字段的类型实现compareTo方法(也就是说,你应该使用Integer vs int等),它应该可以工作。

免责声明:我没有考虑任何性能问题:)

Sorter.java

package sovflow;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Sorter<ObjectType, FieldType extends Comparable<FieldType>> {

    public List<Wrapper<ObjectType, FieldType>> sort(List<ObjectType> list,
            Field field) {
        field.setAccessible(true);
        List<Wrapper<ObjectType, FieldType>> _list = new ArrayList<Wrapper<ObjectType, FieldType>>();
        for (ObjectType object : list) {
            Wrapper<ObjectType, FieldType> wrapper = new Wrapper<ObjectType, FieldType>(
                    field, object);
            _list.add(wrapper);
        }
        Collections.sort(_list);
        return _list;
    }

}

Wrapper.java

package sovflow;

import java.lang.reflect.Field;

public class Wrapper<ObjectType, FieldType extends Comparable<FieldType>>
        implements Comparable<Wrapper<ObjectType, FieldType>> {

    Field field;
    ObjectType object;

    public Wrapper(Field field, ObjectType object) {
        this.field = field;
        this.object = object;
    }

    @SuppressWarnings("unchecked") // for the field.get. Unavoidable, i'd say :)
    public int compareTo(Wrapper<ObjectType, FieldType> paramT) {
        try {   
            return ((FieldType) field.get(object)).compareTo((FieldType)field.get(paramT.object));
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return 0;
    }

    public void print() {
        System.out.println(object);

    }

}

这是如何使用它的一个例子:

package sovflow;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class Main {
    private static class Person {

        private Integer id;
        private String name;
        public Person(Integer id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        @Override
        public String toString() {
            return "Id = " + id + " name = " + name;
        }       
    }

    public static void main(String[] args) {
        Person p = new Person(1, "B");
        Person p2 = new Person(2, "A");
        List<Person> list = new ArrayList<Person>();
        list.add(p);
        list.add(p2);
        Sorter<Person, String> sorter = new Sorter<Person, String>();
        try {
            Field declaredField = Person.class.getDeclaredField("name");
            // Just to show the result. The sort method could be modified to
            // not having to deal with the wrapper here..
            List<Wrapper<Person,String>> list2 = sorter.sort(list, declaredField);          
            for (Wrapper<Person, String> wrapper : list2) {
                wrapper.print();
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}