Appearance
Access Fields
For any Object
instance, as long as we obtain its Class
, we can obtain all its information.
Let's first look at how to obtain field information through Class
instances. The Class
class provides the following methods to obtain fields:
- Field getField(name): Get a public field (including parent class) based on the field name
- Field getDeclaredField(name): Get a field of the current class based on the field name (excluding the parent class)
- Field[] getFields(): Get all public fields (including parent classes)
- Field[] getDeclaredFields(): Get all fields of the current class (excluding parent classes)
Let's take a look at the sample code:
java
// reflection
public class Main {
public static void main(String[] args) throws Exception {
Class stdClass = Student.class;
// Get the public field "score":
System.out.println(stdClass.getField("score"));
// Get the inherited public field "name":
System.out.println(stdClass.getField("name"));
// Get the private field "grade":
System.out.println(stdClass.getDeclaredField("grade"));
}
}
class Student extends Person {
public int score;
private int grade;
}
class Person {
public String name;
}
The above code first obtains Student
's Class
instance, and then obtains public
field, inherited public
field, and private
field respectively. The printed Field
is similar:
public int Student.score
public java.lang.String Person.name
private int Student.grade
A Field
object contains all the information of a field:
getName()
: Returns the field name, for example,"name"
;getType()
: Returns the field type, which is also aClass
instance, for example,String.class
;getModifiers()
: Returns the modifiers of the field, which is anint
. Different bits represent different meanings.
Taking the value
field of the String
class as an example, its definition is:
java
public final class String {
private final byte[] value;
}
We use reflection to obtain the information of this field. The code is as follows:
java
Field f = String.class.getDeclaredField("value");
f.getName(); // "value"
f.getType(); // class [B represents byte[] type
int m = f.getModifiers();
Modifier.isFinal(m); // true
Modifier.isPublic(m); // false
Modifier.isProtected(m); // false
Modifier.isPrivate(m); // true
Modifier.isStatic(m); // false
Get field value
Using reflection to get a Field
instance of the field is only the first step. We can also get the value of the field corresponding to an instance.
For example, for a Person
instance, we can first get Field
corresponding to name
field, and then get the value of name
field of this instance:
java
// reflection
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) throws Exception {
Object p = new Person("Xiao Ming");
Class c = p.getClass();
Field f = c.getDeclaredField("name");
Object value = f.get(p);
System.out.println(value); // "Xiao Ming"
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
The above code first obtains Class
instance, then Field
instance, and then uses Field.get(Object)
to obtain the value of the specified field of the specified instance.
Run the code, and if nothing goes wrong, you will get an IllegalAccessException
. This is because name
is defined as a private
field. Under normal circumstances, the Main
class cannot access private
field of Person
class. To fix the error, you can change private
to public
, or write a sentence before calling Object value = f.get(p)
;
java
f.setAccessible(true);
Calling Field.setAccessible(true)
means that access is allowed regardless of whether the field is public
or not.
You can try adding the above statement and then running the code to print out the value of the private
field.
Some children may ask: If reflection can be used to obtain the value of a private
field, then what is the meaning of class encapsulation?
The answer is that under normal circumstances, we always access Person
's name field through p.name
. The compiler will decide whether to allow access to the field based on public
, protected
and private
, thus achieving the purpose of data encapsulation.
Reflection is an unconventional usage. When using reflection, first of all, the code is very cumbersome. Secondly, it is more used by tools or underlying frameworks. The purpose is to obtain specific fields without knowing any information about the target instance. value.
Additionally, setAccessible(true)
may fail. If SecurityManager
exists during the JVM runtime, it will be checked according to the rules and may prevent setAccessible(true)
. For example, a SecurityManager
may not allow calling setAccessible(true)
on package
classes starting with java
and javax
, which can ensure the security of the JVM core library.
Set field value
Since the field value of the specified instance can be obtained through the Field instance, naturally the field value can also be set.
Setting the field value is implemented through Field.set(Object, Object)
, where the first Object
parameter is the specified instance, and the second Object
parameter is the value to be modified. The sample code is as follows:
java
// reflection
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) throws Exception {
Person p = new Person("Xiao Ming");
System.out.println(p.getName()); // "Xiao Ming"
Class c = p.getClass();
Field f = c.getDeclaredField("name");
f.setAccessible(true);
f.set(p, "Xiao Hong");
System.out.println(p.getName()); // "Xiao Hong"
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
After running the above code, the printed name
field changes from Xiao Ming
to Xiao Hong
, indicating that the value of the field can be directly modified through reflection.
Similarly, to modify non-public
fields, you need to call setAccessible(true)
first.
Summary
Field
class provided by Java's reflection API encapsulates all information about the field:
Field
instances can be obtained through the methods of Class
instances: getField()
, getFields()
, getDeclaredField()
, getDeclaredFields()
;
Field
information can be obtained through Field instances: getName()
, getType()
, getModifiers()
;
Fields of an object can be read or set through Field instances. If there are access restrictions, setAccessible(true)
must be called first to access non-public
fields.
Reading and writing fields via reflection is an unconventional approach that breaks the object's encapsulation.