Сортировать список / вектор любого объекта по полю любого участника? - PullRequest
0 голосов
/ 09 августа 2011

Об этом спрашивали тысячу раз, но все ответы, которые я видел, не работают на переданном Объекте, они всегда жестко запрограммированы, к какому Объекту и какому полю . Я ищу способ сортировки списка / вектора на основе строкового поля. Я не против, если он использует магию отражения или вуду.

Метод, который я написал, приводит к StackOverFlowError (каламбур предназначен!).

Я называю мой метод следующим образом:

StandardComparator.sort("distance",Vector<?>)StaticItems.LocationList,Item.SingleLocation.class);

Класс StandardComparator определен так:

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

Ошибка:

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)

Объект SingleLocation:

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

Ответы [ 4 ]

1 голос
/ 09 августа 2011

Вот пример, который будет работать с любым сопоставимым полем. Вы должны добавить специальную обработку для примитивных типов и несовместимых:

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);
            }
        }
    }
}
1 голос
/ 09 августа 2011

Вы просто вызываете свой собственный метод, вызывая переполнение стека.Поскольку вы знаете, что поля String, просто приведите их к String и используйте метод compareTo().

0 голосов
/ 09 августа 2011

Компаратор бобов должен работать.

0 голосов
/ 09 августа 2011

Вы можете заменить метод сравнения следующим:

return typeOfObject.getField(field).get(object1).compareTo(typeOfObject.getField(field).get(object2));

и учитывать исключения (поле не найдено, нулевой указатель, ...).

...