У меня есть образец объекта Student, который имеет несколько полей (номер индекса, имя, фамилия и т.д.). Я хотел бы сравнить два объекта Student, но я хотел бы определить, что является приоритетом для сравнения полей. Для этой цели я использую аннотации полей, как в примере ниже:
Определение интерфейса аннотации:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CompareOrder {
int order();
}
Использование:
@CompareOrder(order = 3)
private int indexNumber;
@CompareOrder(order = 2)
private String name;
@CompareOrder(order = 1)
private String familyName;
private ArrayList <Float> marks;
@CompareOrder(order = 5)
private float average;
@CompareOrder(order = 4)
private boolean fullTime;
Некоторые поля не содержат аннотации и игнорируются в сравнении. Первое, что я сделал, - это извлечение всех полей класса с использованием отражения и сортировка их в соответствии с порядком сравнения, который соответствует первой части моего compareTo overriden function body:
@Override
public int compareTo(Student other) {
// TODO Auto-generated method stub
Class<? extends Student> clazz = this.getClass();
Field[] fields = clazz.getDeclaredFields();
List <Field> fieldList = new ArrayList<Field> ();
//ommiting unannotated fields
for (Field f : fields)
{
if(f.getAnnotation(CompareOrder.class) != null) fieldList.add(f);
}
//sorting fields by compare order
Collections.sort(fieldList, new Comparator <Field> (){
@Override
public int compare(Field f0, Field f1) {
CompareOrder compOrder0 = f0.getAnnotation(CompareOrder.class);
CompareOrder compOrder1 = f1.getAnnotation(CompareOrder.class);
return compOrder0.order() - compOrder1.order();
}
});
for (Field f : fieldList)
{
// HERE GOES COMPARISON OF OBJECTS FIELD BY FIELD, ACCORDING TO THE ORDERING
}
return 0;
}
И теперь я застрял. Потому что в этот момент мне нужно решить, больше или меньше поле этого и другого ученика. И я не могу сделать это с помощью raw Object type, единственное, что я могу сделать, это метод equals, который недостаточно. Мне нужно знать, больше или меньше. Мне нужно как-то бросить... да, что именно? Как извлечь тип поля, а затем бросить? Это даже выполнимо?
PS. Я знаю, что, возможно, более простой подход - использовать аннотации методов и вызывать методы getter, но мне просто интересно, насколько это выполнимо, как я пытаюсь это сделать.
Я думаю, вы можете использовать Class.isAssignableFrom(Class)
и что-то вроде
Class<Comparable> cls = Comparable.class;
for (Field f : fieldList) {
if (cls.isAssignableFrom(f.getType())) {
Comparable c = (Comparable) f.get(this);
int r = c.compareTo((Comparable) f.get(other));
if (r != 0) {
return r;
}
}
}
get
возвращает экземпляры классов-оболочек), но давайте помнить, что не все классы реализуют этот интерфейс (например, коллекции).
По мере того, как вы уже находитесь в размышлении, вы можете проверить, могут ли поля, которые вы комментируете, также реализовать интерфейс Comparable. Затем вы можете сравнить их с методом compareTo, который они реализуют.
Если у вас есть поле, которое аннотируется и не реализует Comparable, это должно быть ошибкой (можно ли ограничить аннотацию полями, реализующими специальный интерфейс?).
Измените int-поля на Integer и другие примитивные типы, а также на их сопоставления с объектами и не забудьте проверить нуль при сравнении.