近来由于项目的需要,准备实现对象集合的排序问题,了解一下互联网上的排序方式,都是先声明一个类实现Comparator接口,在compare方法中对某一个具体的属性进行处理,然后通过Collections的排序方法进行集合排序。
这样做的确能实现对象集合按对象某个已知的属性进行排序,譬如我实现姓名的排序(假定此对象拥有name属性),那么我可以这么写:
//实现一个内部类实现Comparator,并重写其compare方法
static class NameComparator implements Comparator<Object> {
/**
* 根据name的ASCII比较对象
*/
public int compare(Object o1, Object o2) {
return (o1.getName()).compareTo(o2.getName());
}
}
/**
* 对指定的集合按照name属性进行排序
* @param list
* @return
*/
public static List<Object> TransmitSort(List<Object> list) {
NameComparator wt = new NameComparator();
Collections.sort(list, wt);
return list;
}
这样的确可以实现集合按name属性进行排序,那么如果系统希望按age年龄这个属性进行排序呢,我们是不是还要写个AgeComparator来实现Comparator并重写其compare方法呢,答案是肯定的。
那将来系统需求发生变更,需要对其它属性进行类似的功能呢,我不得不为这排序的策略感到头疼,这无止境的实现并重写可不是一个明智的选择。不过在了解了Java反射的机制后,我突然有一种想法,能不能通过反射的手段在compare方法中做文章呢,这样,一旦我在实现Comparator的类中传递了某个属性,我就可以及时的获取相应的method并进行操作,这样可以吗?答案是肯定的,下面是我的代码实现:
package com.ysb.services.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.ysb.services.entity.Resume;
/**
* SortUtil.java verson 1.0 Aug 5, 2011
*
* @author 贾世雄
*
*/
public class SortUtil {
// 按任意属性进行排序
static class AnyProperComparator implements Comparator<Object> {
private String properName;// 根据此关键字属性排序
private boolean flag;// 为true的时候是正序,为false的时候是倒序
public AnyProperComparator(String properName, boolean flag) {
super();
this.properName = properName;
this.flag = flag;
}
public void setProperName(String properName) {
this.properName = properName;
}
public String getProperName() {
return properName;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
/**
* 实现Comparator的对比方法
*
* @param r1
* @param r2
*/
@SuppressWarnings("unchecked")
public int compare(Object r1, Object r2) {
Class c = r1.getClass();
double result = 0;
try {
Field field = c.getDeclaredField(properName);
String classType = field.getType().getSimpleName();
Method method = null;
// 这里仅根据方法的返回值类型的名称来判定,比较方便
if ("String".equals(classType)) {
method = c.getMethod("get" + properName.substring(0, 1).toUpperCase() + properName.substring(1), new Class[] {});
if (flag) {
result = ((String) method.invoke(r1)).compareTo((String) method.invoke(r2));
} else {
result = ((String) method.invoke(r2)).compareTo((String) method.invoke(r1));
}
} else if ("Integer".equals(classType) || "int".equals(classType)) {
method = c.getMethod("get" + properName.substring(0, 1).toUpperCase() + properName.substring(1), new Class[] {});
if (flag) {
result = ((Integer) method.invoke(r1)) - ((Integer) method.invoke(r2));
} else {
result = ((Integer) method.invoke(r2)) - ((Integer) method.invoke(r1));
}
} else if ("Double".equals(classType) || "double".equals(classType)) {
method = c.getMethod("get" + properName.substring(0, 1).toUpperCase() + properName.substring(1), new Class[] {});
if (flag) {
result = ((Double) method.invoke(r1)) - ((Double) method.invoke(r2));
} else {
result = ((Double) method.invoke(r2)) - ((Double) method.invoke(r1));
}
} else if ("Float".equals(classType) || "float".equals(classType)) {
method = c.getMethod("get" + properName.substring(0, 1).toUpperCase() + properName.substring(1), new Class[] {});
if (flag) {
result = ((Float) method.invoke(r1)) - ((Float) method.invoke(r2));
} else {
result = ((Float) method.invoke(r2)) - ((Float) method.invoke(r1));
}
} else {
System.out.println("属性排序只支持数据类型和String类型,其它类型暂不支持。");
result = -100;
}
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
// 确定返回值
if (result > 0) {
return 1;
} else if (result < 0) {
return -1;
}
return 0;
}
}
/**
* 按任意给定的字段进行排序,升序或降序由flag决定
*
* @param list
* @param properName
* @param flag
* @return
*/
@SuppressWarnings("unchecked")
public static List<Resume> anyProperSort(List<Resume> list, String properName, boolean flag) {
AnyProperComparator comparator = new AnyProperComparator(properName, flag);
Collections.sort(list, comparator);
return list;
}
}
这样一来,我想对某个集合排序,只需要调用SortUtil的方法anyProperSort即可,这样就可以大大的提高系统的扩展性,将来不用再为用户需求的变更而头疼了。
不过需要注意的是反射一般比直接写性能要降低大约一倍,所以请读者慎重。