【问题标题】:Order of Fields returned by Class.getFields()Class.getFields() 返回的字段顺序
【发布时间】:2011-07-08 23:12:11
【问题描述】:

Class.getFields() 的 Javadoc 说:“返回的数组中的元素没有排序,也没有任何特定的顺序。”

关于实际如何确定订单的任何提示?是否有可能当我执行此方法两次时,我得到的字段顺序不同?换句话说,给定编译类的顺序是否稳定,甚至在同一源文件的编译之间是否稳定?

【问题讨论】:

  • 为什么顺序对您的代码很重要?关键是,不要对排序做任何假设,因为没有任何保证。
  • 不值得冒险......假设它们每次都是随机的并且防御性地编码。
  • @skaffman,你甚至不能假设它是随机的。 ;)
  • 为什么我需要它?我正在调试一个序列化程序。刚刚发现它确实在获取后按名称对它们进行了排序,这让我松了一口气。
  • 对不在规范中的假设进行操作是泄漏抽象的定义,这总是有风险并导致意外结果或意外工作代码。

标签: java reflection


【解决方案1】:

它应该是稳定的,对于 Oracle 的 JVM,它的声明顺序是,但你不应该依赖这个。

您应该根据字段的名称(可能还声明类)而不是位置来查找。

【讨论】:

    【解决方案2】:

    创建一个返回排序列表的辅助方法,并在需要字段列表时使用它。或者按名称而不是索引查找。

    【讨论】:

      【解决方案3】:

      属性的自然顺序使用 readKeys() 方法提供 Ujorm framework 及其键值对象。 结果的每个项目都具有类似的功能,例如字段,包括从/向对象读取和写入值。例如看下面的代码:

       public class User extends AbstractUjo implements Serializable {
      
           /** Factory */
           private static final KeyFactory<User> f = newFactory(User.class);
           /** Keys: */
           public static final Key<User, Long> PID = f.newKey();
           public static final Key<User, Integer> CODE = f.newKey();
           public static final Key<User, String> NAME = f.newKey();
           public static final Key<User, Double> CASH = f.newKey();
      
           static {
               f.lock();
           }
      
           // Setters:
           public void setPid(Long pid) {
               PID.setValue(this, pid);
           }
      
           public void setCode(Integer code) {
               CODE.setValue(this, code);
           }
      
           public void setName(String name) {
               NAME.setValue(this, name);
           }
      
           public void setCash(Double cash) {
               CASH.setValue(this, cash);
           }
      
           // Getters ...
       }
      

      键的自然顺序可以通过以下方式迭代:

       for (Key key : new User().readKeys()) {
           System.out.println("Key: " + key);
       }
      

      请参阅documentation 了解更多信息。

      【讨论】:

        【解决方案4】:

        至少在我的 JVM 上,

        Class.getFields() 按声明顺序返回字段。

        另一方面,Class.getMethods() 并不总是如此。它以(我相信)类加载器看到字符串的顺序返回它们。因此,如果两个类具有相同的方法名,则第二个加载的类将在其其他方法之前返回共享方法名。

        javap 确认编译器按声明顺序编写了字段和方法。

        查看此代码示例的输出。

        import java.lang.reflect.Field;
        import java.lang.reflect.Method;
        
        public class OrderTest {
            public static void main(String[] args) {
                // fields are in declaration order
                for (Field field : C1.class.getDeclaredFields()) {
                    System.out.println(field.getName());
                }
                for (Field field : C2.class.getDeclaredFields()) {
                    System.out.println(field.getName());
                }
        
                // methods, on the other hand, are not necessarily in declaration order.
                for (Method method : C1.class.getDeclaredMethods()) {
                    System.out.println(method.getName());
                }
                for (Method method : C2.class.getDeclaredMethods()) {
                    System.out.println(method.getName());
                }
            }
        }
        
        class C1 {
            public int foo;
            public int bar;
            public int getFoo() { return foo; }
            public int getBar() { return bar; }
        }
        
        class C2 {
            public int bar;
            public int foo;
            public int getBar() { return bar; }
            public int getFoo() { return foo; }
        }
        

        在我的 JVM(1.7.0_45,Windows)上返回

        foo
        bar
        bar
        foo
        getFoo
        getBar
        getFoo
        getBar
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-12
          • 1970-01-01
          • 2015-01-03
          • 1970-01-01
          相关资源
          最近更新 更多