0

When called this.getClass().getFields() to return an array of Field objects, would it return the same objects in subsequent calls?

In case someone wondering why this is asked, I am trying to put the Field objects as key and their current value as value in a HashMap to be retrieved later on while changes can be made to the field values, the old values are kept for comparison.

user1589188
  • 5,316
  • 17
  • 67
  • 130
  • What happened when you tried? – Sotirios Delimanolis Nov 02 '17 at 04:07
  • @SotiriosDelimanolis they seem the same, don't know if it was by luck or what, thats why I ask. – user1589188 Nov 02 '17 at 04:13
  • The [docs](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getFields--) say: " The elements in the returned array are not sorted and are not in any particular order." So it seems there is no guarantee about the order and it is probably JVM dependent – jrook Nov 02 '17 at 04:32
  • Look at [this question](https://stackoverflow.com/questions/20461851/how-is-reflection-implemented-in-java) too. The method responsible for filling the `Field[]` array is a native method. It makes sense to assume that most implementations fetch fields by the order they are declared. You would have to refer to the source code for each JDK to make sure. – jrook Nov 02 '17 at 04:49

1 Answers1

1

There is no guarantee that you will get the same objects from different calls and the chances are that you won't. One thing you can do is check the source code for the Class class.

In my installation of jdk1.8.0_131 has the following as the code for getFields()

public Field[] getFields() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyFields(privateGetPublicFields(null));
}

Now you can follow that further, but I'm thinking that this makes a copy of some internal data.

This doesn't mean that the values wont work as keys in a HashMap however, because the HashMap will use the .equals() and .hashCode() methods to determine if two keys are the same, and not the equals operator '=='.

So here is some clunky code to investigate this:

public static void main(String... none) throws Exception {
    Field[] fields1 = Point.class.getFields();
    Field[] fields2 = Point.class.getFields();
    for (int i = 0; i < fields1.length; ++i) {
        compare(fields1[i], fields2[i]);
    }
}

static void compare(Field field1, Field field2) {
    System.out.format("Field  %s\n", field1.getName());
    System.out.format("field1 == field2 -> %s\n", field1 == field2);
    System.out.format("field1.equals(field2) -> %s\n", field1.equals(field2));
    System.out.format("field1.hashCode() == field2.hashCode() -> %s\n", field1.hashCode() == field2.hashCode());
    System.out.println();
}

Which for me has the output:

Field  x
field1 == field2 -> false
field1.equals(field2) -> true
field1.hashCode()==field2.hashCode() -> true

Field  y
field1 == field2 -> false
field1.equals(field2) -> true
field1.hashCode() == field2.hashCode() -> true    

So it looks like you may be ok to use the Field instances as keys. Furthermore if you look at the documentation for .equals() on Field it reads:

/**
 * Compares this {@code Field} against the specified object.  Returns
 * true if the objects are the same.  Two {@code Field} objects are the same if
 * they were declared by the same class and have the same name
 * and type.
 */ 

There is similar documentation for .hashCode() so you'll probably be ok using the field as a key.

Evan Jones
  • 876
  • 4
  • 9
  • Great answer! A role model on SO. +1 for pointing out the possibility to use it as key as equals and hashCode return true. As far as the question goes, the answer is not the same object. – user1589188 Nov 02 '17 at 06:03