How to access a field's value in an object usi

2019-03-22 12:21发布

问题:

My Question: How to overcome an IllegalAccessException to access the value of an object's field using reflection.

Expansion: I'm trying to learn about reflection to make some of my projects more generic. I'm running into an IllegalAccessException when trying to call field.getValue(object) to get the value of that field in that object. I can get the name and type just fine.

If I change the declaration from private to public then this works fine. But in an effort to follow the "rules" of encapsulation I don't want to do this. Any help would be greatly appreciated! Thanks!

My Code:

package main;

import java.lang.reflect.Field;

public class Tester {

  public static void main(String args[]) throws Exception {
    new Tester().reflectionTest();
  }

  public void reflectionTest() throws Exception {
    Person person = new Person("John Doe", "555-123-4567", "Rover");
    Field[] fields = person.getClass().getDeclaredFields();
    for (Field field : fields) {
      System.out.println("Field Name: " + field.getName());
      System.out.println("Field Type: " + field.getType());
      System.out.println("Field Value: " + field.get(person));
      //The line above throws: Exception in thread "main" java.lang.IllegalAccessException: Class main.Tester can not access a member of class main.Tester$Person with modifiers "private final"
    }
  }

  public class Person {

    private final String name;
    private final String phoneNumber;
    private final String dogsName;

    public Person(String name, String phoneNumber, String dogsName) {
      this.name = name;
      this.phoneNumber = phoneNumber;
      this.dogsName = dogsName;
    }
  }
}

The Output:

run:
Field Name: name
Field Type: class java.lang.String
Exception in thread "main" java.lang.IllegalAccessException: Class main.Tester can not access a member of class main.Tester$Person with modifiers "private final"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:95)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
    at java.lang.reflect.Field.doSecurityCheck(Field.java:983)
    at java.lang.reflect.Field.getFieldAccessor(Field.java:927)
    at java.lang.reflect.Field.get(Field.java:372)
    at main.Tester.reflectionTest(Tester.java:17)
    at main.Tester.main(Tester.java:8)
Java Result: 1
BUILD SUCCESSFUL (total time: 0 seconds)

回答1:

Before you get a private field, you need to call setAccessible(true); on the corresponding field:

for (Field field : fields) {
    field.setAccessible(true); // Additional line
    System.out.println("Field Name: " + field.getName());
    System.out.println("Field Type: " + field.getType());
    System.out.println("Field Value: " + field.get(person));
}


回答2:

By default you are not allowed to read non-public fields, but simply invoking field.setAccessible(true); will allow access. In other words, your code should say

for (Field field : fields) {
  field.setAccessible(true);
  // ...
}