zoukankan      html  css  js  c++  java
  • 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));
  • 相关阅读:
    mongodb将mysql数据导入
    mongodb增删改查操作
    mongdb安装
    Python获取两个文件的交集、并集、差集
    java回调函数详解
    java线程锁之synchronized
    mysql知识点汇集
    Springboot2.0实现URL拦截
    idea将springboot打包成jar或者war
    leetcode1128
  • 原文地址:https://www.cnblogs.com/wangzhen-fly/p/11081673.html
Copyright © 2011-2022 走看看