Java中的排序——高级用法
前言
上一篇文章中提到,怎样造一个轮子既适用于文件的排序又适用于商品的排序。Java给我们提供了两个很强大的功能:反射、注解。
思路:用注解声明对象属性的排序要求,再用反射获取到对象属性的值,进行排序比较。
定义排序注解类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sort {/*** 排序类型,默认升序** @return*/int sortType() default CommonComparator.SORT_TYPE_ASC;/*** 排序优先级,值越大,优先级越高** @return*/int priority() default 0;
}
Sort
类有两个属性:sortType
定义字段的排序类型,默认升序,priority
自定字段的排序优先级。多个字段进行关联排序时,未定义优先级或者优先级相同的两个字段按照该字段在类中定义的顺序进行优先级排序。
单从注解的定义上看,有可能觉得想的太简单的。在介绍CommonComparator
之前(这里的CommonComparator
是重新定义的),先看下怎么用在File类中,以及对File进行排序:
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;}@Overridepublic String toString() {return name + " " + type + " " + size + " " + createTime;}}
排序结果:
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
由此可见,不仅是想的太简单了,用起来也很简单。
定义通用排序器
通用排序器用来排序被Sort
定义过的对象属性。因此,需要通过对象类型解析对象的属性字段,获取定义的排序信息和对象的属性值。
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>();/*** 通用排序器的构造函数** @param clazz*/public CommonComparator(Class<T> clazz) {initSortClass(clazz);}/*** 解析被排序的类型字段,并按照优先级顺序保留在List中* @param 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);}@Overridepublic 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;}/*** 对象比较,string对象比较字符,其余对象比较hash值** @param value1* @param value2* @return*/private int compareValue(Object value1, Object value2) {if (value1 instanceof String) {/*** 字符串,只能逐个比较字符,不使用 hashCode* 是因为 "b".hashCode()<"aa".hashCode()。升序排序时,"b"在"aa"前*/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
接口,按照优先级进行排序。
/*** 排序字段信息保存,并定义排序方法*/
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;}@Overridepublic int compareTo(@NonNull SortField o) {return o.priority - this.priority;}
}
测试代码
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);}
扩展
还是之前的问题,要对文件名称、类型、大小、创建(修改)时间进行排序,上一篇文章中使用的方法是定义四个排序器。那么在这里怎样对四个属性分别进行排序呢?
解决方法也很简单,在Sort
注解中定义id
属性。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Sort {/*** 定义字段id,大于零。排序时,可以根据id动态选择排序字段和排序类型。* @return*/int id();/*** 排序类型,默认升序** @return*/int sortType() default CommonComparator.SORT_TYPE_ASC;/*** 排序优先级,值越大,优先级越高** @return*/int priority() default 0;
}
给File类的每个字段定义一个id
值,不能重复。
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;}@Overridepublic String toString() {return name + " " + type + " " + size + " " + createTime;}}
最后在通用排序其中,添加根据 id
解析 待排序字段。
/*** 通用排序器的构造函数** @param clazz* @param ids 根据字段id动态指定排序字段。默认升序,降序需将 id 乘 -1。根据id先后顺序定义优先级*/public CommonComparator(Class<T> clazz, int[] ids) {initSortClass(clazz, ids);}/*** 初始化待排序的类** @param clazz* @param ids 指定排序id*/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);}
测试代码:
Collections.sort(files,new CommonComparator<File>(File.class),new Int[]{1});
转载于:https://my.oschina.net/flueky/blog/1557714
Java中的排序——高级用法相关推荐
- Java中Steam流的用法及使用备忘
文章目录 Java中Steam流的用法及使用备忘 一. 流的常用创建方法 1-1 使用Collection下的 stream() 和 parallelStream() 方法 1-2 使用Arrays ...
- java中compare语句的用法,compare的用法_java中 compareTo()的程序代码及用法
compare的用法与区别? 一.用法 v. (动词) 1.compare的基本意思是"比较,对照",主要用于比较事物的典型特征及其价值,而不在于比较相同与不同. 2.compar ...
- oracle分类函数总结,oracle中分组排序函数用法
项目开发中,我们有时会碰到需要分组排序来解决问题的情况,如:1.要求取出按field1分组后,并在每组中按照field2排序:2.亦或更加要求取出1中已经分组排序好的前多少行的数据 这里通过一张表的示 ...
- JAVA中的排序函数
JAVA中的排序函数包括java.util.Arrays包中的Arrays.sort();java.util.Collections包中的Collections.sort() 1.Arrays.sor ...
- Java中Date各种相关用法
Java中Date各种相关用法 本文主要介绍Java中Date各种相关用法. AD: Java中Date各种相关用法(一) 1.计算某一月份的最大天数 Java代码 Calendar time=C ...
- java中自然排序和比较器排序
这里所说到的Java中的排序并不是指插入排序.希尔排序.归并排序等具体的排序算法.而是指执行这些排序算法时,比较两个对象"大小"的比较操作.我们很容易理解整型的 i>j 这样 ...
- android studio插入数据表中没有_学Java能拿高薪吗 Java中常见排序算法有哪些
学Java能拿高薪吗?Java中常见排序算法有哪些?作为老牌编程语言,Java拥有广阔的市场占有率,几乎90%以上的大中型互联网应用系统在服务端开发都会首选Java.为了加入到Java这一高薪行业,很 ...
- 详解Vue中watch的高级用法
转载自 详解Vue中watch的高级用法 我们通过实例代码给大家分享了Vue中watch的高级用法,对此知识点有需要的朋友可以跟着学习下. 假设有如下代码: 1 2 3 4 5 6 7 8 9 10 ...
- java中的排序方法,Java中的排序比较方式:自然排序和比较器排序
这里所说到的Java中的排序并不是指插入排序.希尔排序.归并排序等具体的排序算法.而是指执行这些排序算法时,比较两个对象"大小"的比较操作.我们很容易理解整型的 i>j 这样 ...
最新文章
- 五年一贯制专转本c语言真题,江苏省五年一贯制专转本《C语言程序设计》模拟试卷二(晓庄)...
- for循环语句的用法
- Java基于百度API的图片文字识别(支持中文,英文和中英文混合)
- ABAPプログラム開発において使用実績のある汎用モジュール一覧
- 一文总结:抽象类(abstract)与接口(interface)的特点和代码展示
- Java设计模式之创建型:原型模式
- 1024-程序员节快乐!给大家发福利啦!以及向大家讲述节日由来
- [Hadoop]-YARN-伪分布式部署-hadoop-2.6.0-cdh5.7.0
- linux下杀毒工具clamav
- java for each 原理_Java for each实现机制代码原理解析
- 3d激光雷达开发(绘制长方体)
- java拦截器_Java拦截器实现
- 三十四个超级经典小故事
- 加个ing是什么意思_ing是什么意思?
- 指尖心跳,通过手指测量心率波形
- C盘占用空间大如何清理
- 第八届“图灵杯”NEUQ—ACM程序设计竞赛个人赛(同步赛)
- 一直被模仿从未被超越的AWS为什么这么强?
- 匠心铸梦 敏涵控股集团打造民族领军品牌
- 60种数据可视化图表总结(文末送书)