Отражение в Java: стандартизирован ли порядок полей и методов класса?
Использование отражения в классах Java для доступа ко всем полям, методам и т. Д.
Существует ли стандартизированный порядок этих элементов (который указан в каком-либо стандарте)?
Конечно, я мог бы проверить это эмпирически, но мне нужно знать, всегда ли это одно и то же.
РЕДАКТИРОВАТЬ:
Я ждал вопроса: для чего мне нужен заказ;)
Короче говоря: у меня есть JAXB-аннотированные классы, и я не хочу представлять эти классы визуально. Хотя порядок атрибутов XML не имеет отношения ни к стандарту XML, ни к JAXB, я хочу иметь определенный порядок атрибутов XML для визуального представления.
Например: начало идет после конца. Это вредит своей интуиции.
3 ответа
Согласно документации:
getFields()
Возвращает массив, содержащий объекты Field, отражающие все доступные открытые поля класса или интерфейса, представленные этим объектом Class. Элементы в возвращаемом массиве не отсортированы и расположены не в определенном порядке. Этот метод возвращает массив длины 0, если у класса или интерфейса нет доступных открытых полей или если он представляет класс массива, примитивный тип или void.
getMethods()
Возвращает массив, содержащий объекты Method, отражающие все открытые методы-члены класса или интерфейса, представленные этим объектом Class, включая те, которые объявлены классом или интерфейсом, и те, которые унаследованы от суперклассов и суперинтерфейсов. Классы Array возвращают все (публичные) методы-члены, унаследованные от класса Object. Элементы в возвращаемом массиве не отсортированы и расположены не в определенном порядке. Этот метод возвращает массив длины 0, если этот объект Class представляет класс или интерфейс, у которого нет открытых методов-членов, или если этот объект Class представляет примитивный тип или void.
Образец моей идеи, основанной на аннотациях.
public class FiledOrder {
@Retention(RetentionPolicy.RUNTIME)
public @interface Order {
int value();
}
public class SomeClass {
@Order(value=2)
public int field1;
@Order(value=1)
public int field2;
// no annotation
public int field3;
@Order(value=1)
public void start() { }
@Order(value=2)
public void end() { }
}
/**
* @param args
*/
public static void main(String[] args) {
Field[] fields = SomeClass.class.getFields();
Arrays.sort(fields, new Comparator<Field>() {
@Override
public int compare(Field o1, Field o2) {
Order or1 = o1.getAnnotation(Order.class);
Order or2 = o2.getAnnotation(Order.class);
// nulls last
if (or1 != null && or2 != null) {
return or1.value() - or2.value();
} else
if (or1 != null && or2 == null) {
return -1;
} else
if (or1 == null && or2 != null) {
return 1;
}
return o1.getName().compareTo(o2.getName());
}
});
for (Field f : fields) {
System.out.println(f.getName());
}
Method[] methods = SomeClass.class.getMethods();
Arrays.sort(methods, new Comparator<Method>() {
@Override
public int compare(Method o1, Method o2) {
Order or1 = o1.getAnnotation(Order.class);
Order or2 = o2.getAnnotation(Order.class);
// nulls last
if (or1 != null && or2 != null) {
return or1.value() - or2.value();
} else
if (or1 != null && or2 == null) {
return -1;
} else
if (or1 == null && or2 != null) {
return 1;
}
return o1.getName().compareTo(o2.getName());
}
});
for (Method m : methods) {
System.out.println(m.getName());
}
}
}
Несмотря на то, что getFields() и getMethods() возвращают результаты в произвольном порядке, вы можете добавить элементы в возвращаемых массивах в коллекции и предоставить свой собственный компаратор для их сортировки по своему усмотрению.
В этом примере я просто сортирую поля и методы в алфавитном порядке их имен, но вы можете отсортировать их на основе объявления класса, модификаторов, типов возвращаемых данных и т. Д., Предоставив необходимую логику в соответствующем компараторе.
public void PrintClassData(Class c) {
Field[] fieldArray = c.getFields();
Method[] methodArray = c.getMethods();
SortedSet<Field> fields = new TreeSet<Field>(new FieldComparator());
fields.addAll(Arrays.asList(fieldArray));
SortedSet<Method> methods = new TreeSet<Method>(new MethodComparator());
methods.addAll(Arrays.asList(methodArray));
StringBuffer b = new StringBuffer("All About ");
b.append(c.getName());
b.append("\nFields:\n");
for(Field f : fields) {
b.append("\t");
b.append(Modifier.toString(f.getModifiers()));
b.append(" ");
b.append(f.getType());
b.append(" ");
b.append(f.getName());
b.append("\n");
}
b.append("\nMethods:\n");
for (Method m : methods) {
b.append("\t");
b.append(Modifier.toString(m.getModifiers()));
b.append(" ");
b.append(m.getReturnType());
b.append(" ");
b.append(m.getName());
b.append("( ");
for (Class param : m.getParameterTypes()) {
b.append(param.getName());
b.append(", ");
}
b.deleteCharAt(b.lastIndexOf(","));
b.append(")\n");
}
System.out.println(b.toString());
}
private static class FieldComparator implements Comparator<Field> {
public int compare(Field f1, Field f2) {
return (f1.getName().compareTo(f2.getName()));
}
}
private static class MethodComparator implements Comparator<Method> {
public int compare(Method m1, Method m2) {
return (m1.getName().compareTo(m2.getName()));
}
}