将对象类型和字段传递给比较器

时间:2017-07-28 07:08:41

标签: java sorting comparator

是否可以编写Comparator以便我可以传递Object类型,字段类型和我想要排序的字段?我对http://www.davekoelle.com/files/AlphanumComparator.java进行了一些小的更改,以便在对象类型email中对String类型的字段User进行排序。我有这个代码可行。

public class Main {

    public static void main(String[] args) {

        List<User> users = new ArrayList<>();

        users.add(new User(7, "user1", "user1@c.com"));
        users.add(new User(11, "user20", "user20@c.com"));
        users.add(new User(5, "admin20", "admin20@c.com"));
        users.add(new User(10, "user11", "user11@c.com"));
        users.add(new User(6, "admin21", "admin21@c.com"));
        users.add(new User(12, "user21", "user21@c.com"));
        users.add(new User(8, "user2", "user2@c.com"));
        users.add(new User(1, "admin1", "admin1@c.com"));
        users.add(new User(3, "admin10", "admin10@c.com"));
        users.add(new User(2, "admin2", "admin2@c.com"));
        users.add(new User(9, "user10", "user10@c.com"));
        users.add(new User(4, "admin11", "admin11@c.com"));

        for (User item : users) {
            System.out.println(item.getEmail());
        }

        System.out.println("__________________________");

        Collections.sort(users, new AlphanumComparator());

        for (User item : users) {
            System.out.println(item.getEmail());
        }
    }
}

public class User {

    int id;
    String name;
    String email;

// Constructor, Getters and Setters
}

public class AlphanumComparator implements Comparator<User> {
    private final boolean isDigit(char ch) {
        return ((ch >= 48) && (ch <= 57));
    }

    /**
     * Length of string is passed in for improved efficiency (only need to calculate it once)
     **/
    private final String getChunk(String s, int slength, int marker) {
        StringBuilder chunk = new StringBuilder();
        char c = s.charAt(marker);
        chunk.append(c);
        marker++;
        if (isDigit(c)) {
            while (marker < slength) {
                c = s.charAt(marker);
                if (!isDigit(c))
                    break;
                chunk.append(c);
                marker++;
            }
        } else {
            while (marker < slength) {
                c = s.charAt(marker);
                if (isDigit(c))
                    break;
                chunk.append(c);
                marker++;
            }
        }
        return chunk.toString();
    }

    public int compare(User u1, User u2) {
        if ((u1 == null) || (u2 == null)) {
            return 0;
        }

        int thisMarker = 0;
        int thatMarker = 0;
        int s1Length = u1.getEmail().length();
        int s2Length = u2.getEmail().length();

        while (thisMarker < s1Length && thatMarker < s2Length) {
            String thisChunk = getChunk(u1.getEmail(), s1Length, thisMarker);
            thisMarker += thisChunk.length();

            String thatChunk = getChunk(u2.getEmail(), s2Length, thatMarker);
            thatMarker += thatChunk.length();

            // If both chunks contain numeric characters, sort them numerically
            int result = 0;
            if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
                // Simple chunk comparison by length.
                int thisChunkLength = thisChunk.length();
                result = thisChunkLength - thatChunk.length();
                // If equal, the first different number counts
                if (result == 0) {
                    for (int i = 0; i < thisChunkLength; i++) {
                        result = thisChunk.charAt(i) - thatChunk.charAt(i);
                        if (result != 0) {
                            return result;
                        }
                    }
                }
            } else {
                result = thisChunk.compareTo(thatChunk);
            }

            if (result != 0)
                return result;
        }

        return s1Length - s2Length;
    }
}

如何将Collections.sort(users, new AlphanumComparator());Main中的对象类型,字段类型和我想要排序的字段传递给AlphanumComparator,我如何在{ {1}}?所以在这种情况下,我会传递对象类型AlphanumComparator字段User和字段类型email。但如果我想对String进行排序,我会传递对象类型id,字段User和字段类型email

1 个答案:

答案 0 :(得分:1)

我会按原样保留AlphanumComparator,并创建一个新类FieldComparator:

public class FieldComparator<T> implements Comparator<T> {
    private static final Logger LOG = Logger.getLogger(
            FieldComparator.class.getName());
    private static final AlphanumComparator ALPHANUM = new AlphanumComparator();

    private final Field field;
    private final boolean isString;
    private final boolean isComparable;

    public FieldComparator(Class<T> clazz, String name) {
        try {
            field = clazz.getDeclaredField(name);
            field.setAccessible(true);
            Class<?> fieldType = field.getType();
            isString = fieldType == String.class;
            isComparable = Comparable.class.isAssignableFrom(fieldType);
        } catch (NoSuchFieldException | SecurityException ex) {
            LOG.log(Level.SEVERE, null, ex);
            throw new RuntimeException(ex.getMessage());
        }
    }

    @Override
    public int compare(T o1, T o2) {
        try {
            Object value1 = field.get(o1);
            Object value2 = field.get(o2);
            if (value1 == null) {
                return value2 == null ? 0 : -1;
            } else if (value2 == null) {
                return 1;
            } else if (isString) {
                return ALPHANUM.compare((String)value1, (String)value2);
            } else if (isComparable) {
                return ((Comparable)value1).compareTo(value2);
            } else {
                // don't know how to compare fields
                return 0;
            }
        } catch (IllegalArgumentException | IllegalAccessException ex) {
            LOG.log(Level.SEVERE, null, ex);
            throw new RuntimeException(ex.getMessage());
        }
    }
}

更新:

要处理基本类型,您可以更改方法比较的一行:

    } else if (isComparable || value1 instanceof Comparable) {

更新2:

你的主要方法将成为:

public static void main(String[] args) {

    List<User> users = new ArrayList<>();

    users.add(new User(7, "user1", "user1@c.com"));
    users.add(new User(11, "user20", "user20@c.com"));
    users.add(new User(5, "admin20", "admin20@c.com"));
    users.add(new User(10, "user11", "user11@c.com"));
    users.add(new User(6, "admin21", "admin21@c.com"));
    users.add(new User(12, "user21", "user21@c.com"));
    users.add(new User(8, "user2", "user2@c.com"));
    users.add(new User(1, "admin1", "admin1@c.com"));
    users.add(new User(3, "admin10", "admin10@c.com"));
    users.add(new User(2, "admin2", "admin2@c.com"));
    users.add(new User(9, "user10", "user10@c.com"));
    users.add(new User(4, "admin11", "admin11@c.com"));

    for (User item : users) {
        System.out.println(item.getEmail());
    }

    System.out.println("__________________________");

    Collections.sort(users, new FieldComparator(User.class, "email"));

    for (User item : users) {
        System.out.println(item.getEmail());
    }

    System.out.println("__________________________");

    Collections.sort(users, new FieldComparator(User.class, "name"));

    for (User item : users) {
        System.out.println(item.getEmail());
    }

    System.out.println("__________________________");

    Collections.sort(users, new FieldComparator(User.class, "id"));

    for (User item : users) {
        System.out.println(item.getEmail());
    }
}