java-基于泛型和反射机制的通用比较器实现
一、前言
Java的比较器是用来对List集合进行排序用的,分为内部比较器和外部比较器两类
内部比较器:被排序的类要 implements Comparable 类,并实现compareTo方法。
外部比较器:需要实现一个implements Comparator的比较器,实现compare方法,并在sort方法中将该比较器当参数传入。
(具体实现,网络上有很多资料,此处不再赘述)
二、发现问题
外部比较器虽然相比内部比较器 实现了解耦,代码侵入小,但是两者都不能摆脱同一个麻烦的问题:
那就是对每个待排序的对象,均需单独实现一个比较器类。如果项目中有很多类都需要排序,那就需要重复劳动,写很多个比较器类了。
本文的目的,即通过泛型和反射机制的应用,来设计实现一个通用的外部比较器。该比较器对任何待排序的对象均能适用,减少低级的重复劳动。
三、实现思路
四、实现
话不多说,直接贴代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.text.Collator;
import java.util.Comparator;
/**
* @Description: 指定需根据某字段排序的方法名,进行排序,返回类型自动判断,目前支持Integer 和 String
* @Author: wangzhen3
* @CreationTime: 2018/5/29 15:02
* @ModifiedBy:
*/
public class CompareByFunctionName<T> implements Comparator<T> {
private static
final Logger logger = LoggerFactory.getLogger(CompareByFunctionName.class);
/**
* 需比较字段的方法名 如 getStatus
*/
private String functionName = "";
/**
* 是否倒序
*/
private Boolean invert = false;
public CompareByFunctionName(String functionName){
this.functionName = functionName;
this.invert = false;
}
public CompareByFunctionName(String functionName, Boolean invert){
this.functionName = functionName;
this.invert = invert;
}
@Override
public int compare(T o1, T o2) {
Object ret1;
Object ret2;
Method method;
try {
method = o1.getClass().getMethod(functionName);
ret1 =
method.invoke(o1);
ret2 =
method.invoke(o2);
if(ret1 instanceof Integer){
return !invert? (Integer)ret1 - (Integer)ret2 :
(Integer)ret2 -
(Integer)ret1;
}else if(ret1 instanceof String){
return !invert? Collator.getInstance(java.util.Locale.CHINA).compare(ret1,ret2) :
Collator.getInstance(java.util.Locale.CHINA).compare(ret2,ret1);
}else{
//直接toString 比较
return !invert? Collator.getInstance(java.util.Locale.CHINA).compare(ret1.toString(),ret2.toString())
:
Collator.getInstance(java.util.Locale.CHINA).compare(ret2.toString(),ret1.toString());
}
}catch (Exception e){
logger.error(e.getMessage());
}
logger.error("比较失败,o1={},o2={}",o1.toString(),o2.toString());
return 0;
}
}
关键步骤说明:
1)java反射机制中的Field 和 Method 方法,网上有很多博客介绍,此处不赘述。
2)functionName 必须为public方法,不然无访问权限。
或许你会有疑问,为什么此处反射是使用Method获得数据值 而不直接用字段Field来获取数据值,原因是字段一般被声明为private,所以通过Field一般无访问权限,无法取出数据,而Method ,比如status 字段的getStatus方法,通常是public ,所以能取出数据。
3)当然,functionName 是可以换成 字段名称fieldName 的,只需要新增转换逻辑,根据java的驼峰式命名约定,把fieldName 转换为functionName 即可
4)Collator.getInstance(java.util.Locale.CHINA)
.compare()
为了实现中文字符串排序功能
五、实际应用
项目中使用示例:
根据字段status对List<MonitorAlarmData> 进行倒序排列,使status=1的排在开头,status=-1的排在末尾
public class MonitorAlarmData { private String id; //problem id private Integer status;//当前状态 -1 已忽略; 0 OK; 1 problem; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public Integer getStatus() {
return status;
} public void setStatus(Integer status) {
this.status = status;
}
}
List<MonitorAlarmData> monitorAlarmDataList = new ArrayList<>();
//省略代码,往monitorAlarmDataList 中添加数据
//排序
monitorAlarmDataList.sort(new CompareByFunctionName("getStatus",true));
java-基于泛型和反射机制的通用比较器实现的更多相关文章
- java的泛型与反射机制
什么是泛型? 泛型,即“参数化类型”.顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参) ...
- Java基础系列 - 泛型和反射机制
package com.test5; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Java泛型和反射机 ...
- JAVA动态性之一一反射机制reflection
package com.bjsxt.reflection.test.bean; public class User { private int id; private int age; private ...
- Java 核心类库之反射机制
1:什么是反射机制? 2:反射机制它可以做什么呢? 3:反射机制对应的API又是什么? 1):通过反射机制来获取一个对象的全限定名称(完整包名),和类名: 2):实例化Class对象 3):获取对象的 ...
- Java基于注解和反射导入导出Excel
代码地址如下:http://www.demodashi.com/demo/11995.html 1. 构建项目 使用Spring Boot快速构建一个Web工程,并导入与操作Excel相关的POI包以 ...
- 利用JAVA反射机制设计通用的DAO
利用JAVA反射机制设计一个通用的DAO 反射机制 反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息. 反射机制创建类对象 ...
- 关于Java中泛型、反射和注解的扫盲篇
泛型 泛型概念 泛型是在JDK1.5之后引入的,旨在让我们写出更加通用化,更加灵活的代码.通用化的手段在于让数据类型变得参数化,定义泛型时,对应的数据类型是不确定的,泛型方法被调用时,会指定具体类 ...
- java的RTTI和反射机制
RTTI,即Run-Time Type Identification,运行时类型识别.RTTI能在运行时就能够自动识别每个编译时已知的类型. 很多时候需要进行向上转型,比如Base类派生出Derive ...
- java.lang.Class<T> -- 反射机制
1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
随机推荐
- MyBatis学习 之 三、SQL语句映射文件(2)增删改查、参数、缓存
2.2 select 一个select 元素非常简单.例如: <!-- 查询学生,根据id --> <select id="getStudent" paramet ...
- UI:地图和定位
参考学习链接 各种IOS设备可以使用 Core Location 框架确定它的物理位置.core location 主要使用三种技术来实现功能.GPS.蜂窝基站三角网络定位. wifi 定位服务.这三 ...
- Linux多台服务器间SSH免密码登录配置
SSH实现各个服务器间的文件相互备份,如运行scp命令,可以实现免密码登录,从而可以使用SHELL脚本实现一些自动化的处理. 假如A机要免密码登录B机,具体方法如下: 1.在A机运行:"ss ...
- 用ffmpeg命令将264裸码流封装成mp4(转载)
转自:http://bbs.csdn.net/topics/370256130 ffmpeg -f h264 -i source.264 -vcodec copy out.mp4
- LIS LCS LCIS (主要过一遍,重在做题)
只详细讲解LCS和LCIS,别的不讲-做题优先. 菜鸟能力有限写不了题解,可以留评论,我给你找博客. 先得理解最长上升子序列吧,那个HDOJ拦截导弹系列可以做一下,然后用o(n)log(n)的在做一遍 ...
- python 模块和包的使用方法
一.模块 1.import导入模块 import module1,mudule2... 2.from...import...导入模块 导入指定内容 from modname import name1[ ...
- bzoj 1082: [SCOI2005]栅栏【二分+dfs】
二分答案,dfs判断是否可行,当b[k]==b[k-1]时可以剪枝也就是后移枚举位置 #include<iostream> #include<cstdio> #include& ...
- 如何阻止浏览器的默认事件,你是否也遇到过无法阻止Google默认事件的情况( 原生JS )
如题,话不多话,我们先看怎么解决 根据不同的绑定事件的方法,我们有不同的阻止默认事件的方法 如果你不知到如何绑定事件,请查看我的上一篇文章 关于浏览器滚动的兼容性问题以及事件绑定 1.句柄绑定 只需要 ...
- servlet重定向到jsp后样式无法正常显示
原因是在servlet中转发时css和图片的路径变成相对于这个servlet的相对路径而非相对于web项目的路径了. 解决办法:导入css样式和图片时把css写成动态绝对路径, 如用EL表达式表示: ...
- 突然所有命令都不能用了, /usr/bin不在path里 .bashrc文件
export PATH=/usr/bin:/bin .bashrc文件中多一个空格都不行啊所有的问题都是因为复制的时候多了空格,简直无语,用了两个小时