0

How can I get a non-static field of an extended class?

I know how to get static fields, but not how to get fields from an instance.


I already tried it with

Field commandName = command.getField("name");

but I get a NoSuchFieldException exception.


These are the classes:

public class A extends B{

    public A(String name){
        super(name);
    }
}

public class B{
    private String name;
    protected B(String name){
        this.name = name;
    }
}

I need to get name from an external class.

Galgo
  • 55
  • 9
  • The `Field` class in Java doesn't store the value of an object. You can however, use it to get the value from an object (if the object contains such field) using the `get(Object obj)` method. – Kröw Oct 06 '17 at 19:42
  • Possible duplicate of [How do I read a private field in Java?](https://stackoverflow.com/questions/1196192/how-do-i-read-a-private-field-in-java) Its not directly about **private** fields but the same works for all fields. – Zabuzard Oct 06 '17 at 19:45
  • Can you post the classes in question, please? – Andreas Oct 06 '17 at 19:52
  • Zabuza my question is not about private fields at all, it is about non-static fields – Galgo Oct 06 '17 at 19:54
  • As already said, the technique does not change. Just access the field by the methods of the reflection-API. `NoSuchFieldException` is obvious, you must have done something wrong (carefully **read the documentation**). Please show us your class. – Zabuzard Oct 06 '17 at 19:55
  • 1
    Note that `getFields()` shows you all **fields** which you can access by `getField(...)`. This are only **public members**, as stated in the documentation. – Zabuzard Oct 06 '17 at 20:00
  • 1
    @Zabuza A `NoSuchFieldException` may be obvious in that a field could not be found, but why it couldn't be found can be an issue. A `NoSuchFieldException` can be thrown when a certain field is not publicly accessible, even if the right name is passed into `getField(String)`. – Kröw Oct 06 '17 at 20:01
  • 1
    @Kröw Absolutely right. And that is, what I think, OP did not consider. – Zabuzard Oct 06 '17 at 20:03
  • 2
    Ah, the edit made it clear, the field is indeed **private**. Then it is a duplicate of: [Access to private inherited fields via reflection in Java](https://stackoverflow.com/questions/3567372/access-to-private-inherited-fields-via-reflection-in-java). – Zabuzard Oct 06 '17 at 20:05
  • This is not a duplicate of "Access to private inherited fields via reflection in Java". This question is about getting a **non-static** value that is also private – Galgo Oct 06 '17 at 20:29
  • @Galgo If an user answered your question please also accept his answer ([Accepting Answers: How does it work?](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)). If not than please specify what remains unanswered, this is a really crucial part of StackOverflow, thank you very much. – Zabuzard Nov 14 '17 at 10:14

2 Answers2

2

With a class, Test, as such:

public class Test {

    public int field1;

}

And a subclass, SubTest, as such:

//This class extends Test
public class SubTest extends Test  {

    public SubTest(int value) {
        field1 = value;//field1 is public, so we can access it from subclass.
    }

}

We can do the following with a Field object:

public static void main(String[] args)
            throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        SubTest t0 = new SubTest(-10), t1 = new SubTest(0), t2 = new SubTest(10);

        Field f = SubTest.class.getField("field1");
        System.out.println(f.get(t0));
        System.out.println(f.get(t1));
        System.out.println(f.get(t2));

    }

Prints:

-10
0
10

Explanation: The Field class in Java can be obtained from a Class object (not an instance of a class) and can be used to manipulate/read the actual field that it represents on objects. In this example we got the Field class that represents field1 and then we used that to get the value of the actual field from each SubTest we created.

Please note the exceptions thrown by the main method. Java reflection can sometimes throw many checked exceptions.

If the field in your superclass (Test) is private, you will need to get the superclass of your class (meaning, the superclass of SubTest) then get the declared fields from that. See this link as Zabuza pointed out for more information.

Aaya
  • 33
  • 1
  • 5
  • I use `Field commandName = commandInstance.getClass().getField("name"); commandName.setAccessible(true); String name = (String) commandName.get(commandInstance);` The problem is that I get `NoSuchFieldException` **exception** – Galgo Oct 06 '17 at 20:05
  • That means that the problem was thrown by your first statement. Specifically the part that says: `getField("name");` Make sure that the `name` field is public and can be accessed from wherever `getField` is called. – Aaya Oct 06 '17 at 20:08
1

By using the reflection API.

The methods are accessible from myObject.getClass() like myObject.getClass().getDeclaredFields().

Here is the documentation of Class.

Note that the method Class#getField also searches in super classes of your object (documentation). But as clearly stated in the documentation, this method only searches for public members.


In your specific example you try to access a private member of the super class. For this you first need to get a reference to that super class and make the field public, else you can not access it. After that you can access the field with said methods:

A a = new A("foo");

// Make name public
Field nameField = a.getClass().getSuperClass().getDeclaredField("name");
nameField.setAccessible(true);

// Access the name
String name = (String) nameField.get(a);
Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • 1
    In the question it states "of an extended class". Does that imply that he wants an inherited field? if so: [getField](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getField-java.lang.String-) may work better. – Andreas Oct 06 '17 at 19:52
  • I get a NoSuchFieldException. I think the problem is because the field isn't static, so I should get it from an instance – Galgo Oct 06 '17 at 19:55
  • `myObject` and `car` (in the example above) are instances of classes and not class names. It should perfectly work. As already commented at your question you probably have done something wrong. E.g. trying to access inaccessible fields or something like that. – Zabuzard Oct 06 '17 at 19:57
  • @Galgo In Java, `Field` objects don't represent the value of an object's field. They represent a data holder in an objects definition: A class. When you're getting a `Field` itself, you can't get it from an instance. It has to be obtained from a class. When you're getting the value of an actual field in an instance, you can use the `Field` which you obtained from the instance's class. – Kröw Oct 06 '17 at 20:05