java-基於泛型和反射機制的通用比較器實現

1、前言

Java的比較器是用來對List集合進行排序用的,分爲內部比較器和外部比較器兩類java

內部比較器:被排序的類要 implements Comparable 類,並實現compareTo方法。網絡

外部比較器:須要實現一個implements  Comparator的比較器,實現compare方法,並在sort方法中將該比較器當參數傳入。ide

(具體實現,網絡上有不少資料,此處再也不贅述)this

 

2、發現問題

外部比較器雖然相比內部比較器 實現瞭解耦,代碼侵入小,可是二者都不能擺脫同一個麻煩的問題:設計

那就是對每一個待排序的對象,均需單獨實現一個比較器類。若是項目中有不少類都須要排序,那就須要重複勞動,寫不少個比較器類了。對象

本文的目的,即經過泛型和反射機制的應用,來設計實現一個通用的外部比較器。該比較器對任何待排序的對象均能適用,減小低級的重複勞動。blog

3、實現思路

 

4、實現

話很少說,直接貼代碼:排序

 

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;
    }
}ip

 

 

關鍵步驟說明:字符串

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()

爲了實現中文字符串排序功能

 

5、實際應用

項目中使用示例:

根據字段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));
相關文章
相關標籤/搜索