Sort List / Vector of any Object by any member's field?
This has been asked a thousand times, but all of answers I've seen do not work on a passed Object, they are always hard coded to which Object and which field. I'm looking for a way to sort a List / Vector of based on a string field. I don't mind if it uses Reflection or Voodoo magic.
The method I've written results in a StackOverFlowError (pun intended!).
I call my method as follows:
StandardComparator.sort("distance",Vector<?>)StaticItems.LocationList,Item.SingleLocation.class);
StandardComparator class is defined as such:
public class StandardComparator {
public static void sort(final String field, Vector<?> locationList, final Class typeOfObject){
Collections.sort(locationList, new Comparator<Object>() {
@Override
public int compare(Object object1, Object object2) {
try {
return this.compare(typeOfObject.getField(field),typeOfObject.getField(field));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
开发者_运维知识库 e.printStackTrace();
}
return 0;
}
});
}
}
The error:
E/AndroidRuntime(22828): FATAL EXCEPTION: Thread-10
E/AndroidRuntime(22828): java.lang.StackOverflowError
E/AndroidRuntime(22828): at java.lang.reflect.Field.<init>(Field.java:89)
E/AndroidRuntime(22828): at java.lang.reflect.Field.<init>(Field.java:81)
E/AndroidRuntime(22828): at java.lang.reflect.ReflectionAccessImpl.clone(ReflectionAccessImpl.java:42)
E/AndroidRuntime(22828): at java.lang.Class.getField(Class.java:870)
E/AndroidRuntime(22828): at com.AtClass.Extras.StandardComparator$1.compare(StandardComparator.java:24)
A SingleLocation object:
public class SingleLocation {
int id;
public String deviceId;
public String title;
public String message;
public double latCoords;
public double lngCoords;
public String locSeen;
public Bitmap icon;
public double distance;
public String distanceString;
public SingleLocation(String id, String deviceId, String title, String message, String latCoords, String lngCoords, String locSeen){
this.id = Integer.valueOf(id);
this.deviceId = deviceId;
this.title = title;
this.message = message;
this.latCoords = Double.valueOf(latCoords);
this.lngCoords = Double.valueOf(lngCoords);
this.locSeen = locSeen;
}
}
Here's an example that will work on any Comparable field. You'd have to add special handling for primitive types and non-Comparables:
import java.lang.reflect.Field;
import java.util.*;
public class ReflectionBasedComparator {
public static void main(String[] args) {
List<Foo> foos = Arrays.asList(new Foo("a", "z"), new Foo("z", "a"), new Foo("n", "n"));
Collections.sort(foos, new ReflectiveComparator("s"));
System.out.println(foos);
Collections.sort(foos, new ReflectiveComparator("t"));
System.out.println(foos);
}
static class Foo {
private String s;
private String t;
public Foo(String s, String t) {
this.s = s;
this.t = t;
}
@Override
public String toString() {
return "Foo{" +
"s='" + s + '\'' +
", t='" + t + '\'' +
'}';
}
}
private static class ReflectiveComparator implements Comparator<Object> {
private String fieldName;
public ReflectiveComparator(String fieldName) {
this.fieldName = fieldName;
}
@Override
public int compare(Object o1, Object o2) {
try {
Field field = o1.getClass().getDeclaredField(fieldName);
if (!Comparable.class.isAssignableFrom(field.getType())) {
System.out.println(field.getType());
throw new IllegalStateException("Field not Comparable: " + field);
}
field.setAccessible(true);
Comparable o1FieldValue = (Comparable) field.get(o1);
Comparable o2FieldValue = (Comparable) field.get(o2);
return o1FieldValue.compareTo(o2FieldValue);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("Field doesn't exist", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Field inaccessible", e);
}
}
}
}
You are just calling your own method, causing the stack overflow. Since you know the fields are String
's, just cast them to String
and use its compareTo()
method.
You can replace your compare method with this:
return typeOfObject.getField(field).get(object1).compareTo(typeOfObject.getField(field).get(object2));
and cater for exceptions (field not found, null pointer, ...).
The Bean Comparator should work.
精彩评论