上一篇文章中提到,怎样造一个轮子既适用于文件的排序又适用于商品的排序。Java给我们提供了两个很强大的功能:反射、注解。
思路:用注解声明对象属性的排序要求,再用反射获取到对象属性的值,进行排序比较。
1 定义排序注解类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Sort {
int sortType() default CommonComparator.SORT_TYPE_ASC;
int priority() default 0; }
|
Sort
类有两个属性:sortType
定义字段的排序类型,默认升序, priority
自定字段的排序优先级。多个字段进行关联排序时,未定义优先级或者优先级相同的两个字段按照该字段在类中定义的顺序进行优先级排序。
单从注解的定义上看,有可能觉得想的太简单的。在介绍CommonComparator
之前(这里的CommonComparator
是重新定义的),先看下怎么用在File类中,以及对File进行排序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| private static final class File { String name; @Sort(sortType = CommonComparator.SORT_TYPE_DES) String type; long size; @Sort(sortType = CommonComparator.SORT_TYPE_ASC) long createTime;
public File(String name, String type, long size, long createTime) { this.name = name; this.type = type; this.size = size; this.createTime = createTime; }
@Override public String toString() { return name + " " + type + " " + size + " " + createTime; }
}
|
排序结果:
1 2 3 4 5 6 7 8 9 10
| qq exe 10000 242434235 wxin exe 10000 24243424 picture png 100 111111 qqExter txt 1000 24243455
对文件类型降序、创建时间升序排序: qqExter txt 1000 24243455 picture png 100 111111 wxin exe 10000 24243424 qq exe 10000 242434235
|
由此可见,不仅是想的太简单了,用起来也很简单。
2 定义通用排序器
通用排序器用来排序被Sort
定义过的对象属性。因此,需要通过对象类型解析对象的属性字段,获取定义的排序信息和对象的属性值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| public final class CommonComparator<T> implements Comparator<T> {
public static final int SORT_TYPE_ASC = 0; public static final int SORT_TYPE_DES = 1; public static final int SORT_TYPE_INV = -1; private List<SortField> sortFileds = new ArrayList<SortField>();
public CommonComparator(Class<T> clazz) { initSortClass(clazz); }
private void initSortClass(Class<T> clazz) {
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; fields != null && i < fields.length; i++) { Field field = fields[i]; if (!field.isAnnotationPresent(Sort.class)) continue; Sort sort = (Sort) field.getAnnotation(Sort.class); int sortType = sort.sortType(); int priority = sort.priority(); SortField sortField = new SortField(field, priority, sortType); sortFileds.add(sortField); }
Collections.sort(sortFileds); } @Override public int compare(T o1, T o2) { for (SortField sortField : sortFileds) { Field field = sortField.getField(); int sortType = sortField.getSortType(); try { Object value1 = field.get(o1); Object value2 = field.get(o2); if (compareValue(value1, value2) == 0) continue; if (sortType == SORT_TYPE_ASC) { return compareValue(value1, value2); } else { return compareValue(value2, value1); } } catch (IllegalAccessException e) { e.printStackTrace(); } }
return 0; }
private int compareValue(Object value1, Object value2) { if (value1 instanceof String) {
char[] chars1 = value1.toString().toCharArray(); char[] chars2 = value2.toString().toCharArray(); for (int i = 0; i < chars1.length && i < chars2.length; i++) { if (chars1[i] == chars2[i]) continue; return chars1[i] - chars2[i]; } return chars1.length - chars2.length; } else { return value1.hashCode() - value2.hashCode(); } } }
|
compareValue
方法在前一篇文章中用到,compare
方法逐个对比要排序的属性,initSortClass
解析被排序类型中,用Sort
注解定义的字段。
这里用到一个SortField
类,是对待排序字段的分装,该类实现Comparable
接口,按照优先级进行排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
class SortField implements Comparable<SortField> {
private Field field; private int priority; private int sortType;
public SortField(Field field, int priority, int sortType) { this.field = field; this.priority = priority; this.sortType = sortType; }
public Field getField() { return field; }
public int getSortType() { return sortType; }
@Override public int compareTo(@NonNull SortField o) { return o.priority - this.priority; } }
|
2.1 测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static final void main(String[] args) { List<File> files = new ArrayList<>();
files.add(new File("qq", "exe", 10000, 242434235)); files.add(new File("wxin", "exe", 10000, 24243424)); files.add(new File("picture", "png", 100, 111111)); files.add(new File("qqExter", "txt", 1000, 24243455)); System.out.println("原始数据:"); for (File f : files) System.out.println(f);
Collections.sort(files,new CommonComparator<File>(File.class));
System.out.println(); System.out.println(); System.out.println("对文件类型降序、创建时间升序排序:"); for (File f : files) System.out.println(f); }
|
2.2 扩展
还是之前的问题,要对文件名称、类型、大小、创建(修改)时间进行排序,上一篇文章中使用的方法是定义四个排序器。那么在这里怎样对四个属性分别进行排序呢?
解决方法也很简单,在Sort
注解中定义id
属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Sort {
int id();
int sortType() default CommonComparator.SORT_TYPE_ASC;
int priority() default 0; }
|
给File类的每个字段定义一个id
值,不能重复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private static final class File { @Sort(id = 1) String name; @Sort(id=2,sortType = CommonComparator.SORT_TYPE_DES) String type; @Sort(id = 3) long size; @Sort(id=4,sortType = CommonComparator.SORT_TYPE_ASC) long createTime;
public File(String name, String type, long size, long createTime) { this.name = name; this.type = type; this.size = size; this.createTime = createTime; }
@Override public String toString() { return name + " " + type + " " + size + " " + createTime; }
}
|
最后在通用排序其中,添加根据 id
解析 待排序字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
public CommonComparator(Class<T> clazz, int[] ids) {
initSortClass(clazz, ids); }
private void initSortClass(Class<T> clazz, int[] ids) {
if (ids == null) { initSortClass(clazz); return; }
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; fields != null && i < fields.length; i++) { Field field = fields[i]; if (!field.isAnnotationPresent(Sort.class)) continue;
Sort sort = (Sort) field.getAnnotation(Sort.class); int id = sort.id(); int sortType = SORT_TYPE_INV; int priority = -1; for (int j = 0; j < ids.length; j++) { if (id == Math.abs(ids[j])) { sortType = ids[j] > 0 ? SORT_TYPE_ASC : SORT_TYPE_DES; priority = ids.length - j; break; } } if (sortType == SORT_TYPE_INV || priority == -1) continue; SortField sortField = new SortField(field, priority, sortType); sortFileds.add(sortField); }
Collections.sort(sortFileds); }
|
测试代码:
1
| Collections.sort(files,new CommonComparator<File>(File.class),new Int[]{1});
|
觉得有用?那打赏一个呗。[去打赏](/donate/)