将对象类型和字段传递给比较器 [英] Passing Object type and Field to Comparator
问题描述
是否可以编写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屋!