Java反射:类字段和方法的顺序是否标准化?

57

使用Java类的反射机制访问所有字段、方法等:
这些元素有标准化的顺序(在某个标准中进行了规定)吗?

当然,我可以通过经验检查来确定,但我需要知道它是否总是相同的。

编辑:
我等待问题:我需要这个顺序用来做什么;)
长话短说:我有JAXB注释的类,并希望可视化地表示这些类。虽然XML属性的顺序对于XML标准和JAXB都不相关,但我想要一定的顺序,以便于XML属性的可视化表示。
例如:开始时间在结束时间之后。这违反了人们的直觉。


我同意kd304的观点,这引起了我的兴趣... - Adam Paynter
4
如果这些是你的类,你可以使用 @Order(value=11) 注解来进行标注,并且你的显示将根据该值对字段进行排序。 - akarnokd
@kd304:我认为你应该把最后的评论作为答案,这可能是他正在寻找的解决方案。 - Valentin Rocher
@Bishiboosh:好的,我会写一个小例子。 - akarnokd
顺便提一下,在将JAXB注释类转换为XSD时,顺序很重要。现在,必须在类注释中提供propOrder属性以保证特定顺序。如果XSD顺序是声明顺序,那不是很好吗? - Thomas Jung
3个回答

73
根据文档getFields() 返回一个包含反映此 Class 对象所表示的类或接口的所有可访问公共字段的 Field 对象的数组。返回的数组元素未排序且没有特定顺序。如果类或接口没有可访问的公共字段,或者它表示数组类、原始类型或 void,则此方法返回长度为 0 的数组。 getMethods() 返回一个包含反映此 Class 对象所表示的类或接口的所有公共成员方法的 Method 对象的数组,其中包括由该类或接口声明的及从超类和超接口继承的方法。数组类返回从 Object 类继承的所有(公共的)成员方法。返回的数组元素未排序且没有特定顺序。如果此 Class 对象表示没有公共成员方法的类或接口,或者此 Class 对象表示原始类型或 void,则此方法返回长度为 0 的数组。

9
谢谢。很遗憾,没有定义任何顺序:( - ivan_ivanovich_ivanoff
3
没有特定的顺序,不同虚拟机和版本之间也没有保证。 - akarnokd
但请参见akarnokd的解决方案 - serv-inc

44

我的基于注释的想法的一个示例。

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

}

有点晚了,但我也遇到了同样的问题,这是一个优雅的解决方案。非常好! - user1452076
1
多么美妙的解决方案!谢谢@akarnokd - Ashish Patil

8
尽管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()));
    }

}

1
如果您想按照源代码中编写的顺序进行排序,该怎么办? - Tristan
2
@Tristan 如果有行号信息,你可以按行号排序 - 请参见 http://github.com/orfjackal/classmembersorter - tequilacat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接