将对象类型和字段传递给比较器 [英] Passing Object type and Field to Comparator

查看:78
本文介绍了将对象类型和字段传递给比较器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to write a Comparator so that I can pass the Object type, the field type and the field I like to sort on? I've made some small changes to http://www.davekoelle.com/files/AlphanumComparator.java to accommodate sorting on the field email of type String in the Object type User . I have this code that works.

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

如何将对象类型,字段类型和我希望从Main类中的Collections.sort(users, new AlphanumComparator());排序的字段传递给AlphanumComparator,以及如何在AlphanumComparator中容纳此内容?因此,在这种情况下,我将传递对象类型User字段email和字段类型String.但是,如果我想对id进行排序,则可以传递对象类型User,字段email和字段类型int.

How can I pass Object type, field type and the field that I like to sort on from Collections.sort(users, new AlphanumComparator()); in the Main class to AlphanumComparator and how can I accommodate for this in AlphanumComparator? So in this case I would pass object type User field email and field type String. But if I like to sort on id I would pass object type User, field email and field type int.

推荐答案

我将保持AlphanumComparator不变,并创建一个新的FieldComparator类:

I would keep the AlphanumComparator as is, and create a new class 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());
        }
    }
}

更新:

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

To deal with primitive types, you can change one line of method compare:

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

这篇关于将对象类型和字段传递给比较器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆