文章目錄
- 動態加載機制
- 獲取 `Class` 類的實例
- 訪問、修改字段內容
- public Field getField(String name) (Class.java: 1991)(jdk13)
- public Field[] getFields()(Class.java: 1810)(jdk13)
- public Field getDeclaredField(String name) (Class.java: 2403)(jdk13)
- public Field[] getDeclaredFields() (Class.java: 2244)(jdk13)
- 使用 `Field` 實例訪問修改對象對應字段的值
- 小結
- 調用方法
- 創建新實例
- 參考資料
Java中類是由JVM在運行中動態加載的。JVM在第一次讀取到這個類時,會將它加載進內存,每加載一個類,JVM會創建一個Class類的實例(
java.lang.Class
),這個類的實例只有JVM能夠創建。
在Class類的實例中,會保存加載的類的所有信息,包括類名、方法、包名等。通過這些實例,就能獲取到一個類的所有信息,這就是反射
動態加載機制
JVM只會加載用到的類,還未運行到或者沒用到的類,並不會加載進內存
獲取 Class
類的實例
通過類的class靜態變量獲取
Class cls = String.class;
System.out.println(cls.toString());
//class java.lang.String
通過類的實例獲取
String string = "Hello World";
Class cls = string.getClass();
System.out.println(cls.toString());
//class java.lang.String
從完整類名獲取
Class cls = Class.forName("java.lang.String");
System.out.println(cls.toString());
//class java.lang.String
除了類和接口外,數組和基本數據類型也有對應的Class實例
String[] strings = {"Hello","World"};
Class cls = strings.getClass();
System.out.println(cls.toString());
//class [Ljava.lang.String;
cls = int.class;
System.out.println(cls.toString());
//int
訪問、修改字段內容
public Field getField(String name) (Class.java: 1991)(jdk13)
Returns a Field object that reflects the specified public member field of the class or interface represented by this Class object. The name parameter is a String specifying the simple name of the desired field.
The field to be reflected is determined by the algorithm that follows. Let C be the class or interface represented by this object:
If C declares a public field with the name specified, that is the field to be reflected.
If no field was found in step 1 above, this algorithm is applied recursively to each direct superinterface of C. The direct superinterfaces are searched in the order they were declared.
If no field was found in steps 1 and 2 above, and C has a superclass S, then this algorithm is invoked recursively upon S. If C has no superclass, then a NoSuchFieldException is thrown.
If this Class object represents an array type, then this method does not find the length field of the array type.
該方法需要一個 String
參數,代表一個具體的公共字段名。查找順序爲,先在類中查找,沒有的話按順序查找這個類實現的接口,還找不到的話就去它的父類重複這個過程。對於數組字段,不會返回數組大小
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class cls = C.class;
try {
System.out.println(cls.getField("a"));
//public int example.C.a
System.out.println(cls.getField("b"));
//public static final int example.A.b
System.out.println(cls.getField("c"));
//public int example.B.c
System.out.println(cls.getField("array"));
//public int[] example.C.array
} catch (NoSuchFieldException e) {
System.out.println(e.toString());
}
}
}
interface A{
int a = 101;
int b = 101;
}
class B{
public int a = 202;
public int b = 202;
public int c = 202;
}
class C extends B implements A{
public int a = 303;
public int[] array = {1,2,3,4,5};
}
public Field[] getFields()(Class.java: 1810)(jdk13)
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
If this Class object represents a class or interface with no accessible public fields, then this method returns an array of length 0.
If this Class object represents a class, then this method returns the public fields of the class and of all its superclasses and superinterfaces.
If this Class object represents an interface, then this method returns the fields of the interface and of all its superinterfaces.
If this Class object represents an array type, a primitive type, or void, then this method returns an array of length 0.
The elements in the returned array are not sorted and are not in any particular order.
返回一個類或接口對象能訪問的所有公共字段,包括父類和父接口的公共字段;對於沒有可訪問公共字段的類或接口,還有數組類型、基元類型或void,返回長度爲0的數組。返回的結果不帶有任何排序
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class cls = C.class;
for(var field:cls.getFields())
System.out.println(field);
}
}
interface A{
int a = 101;
int b = 101;
}
class B{
public int a = 202;
public int b = 202;
protected int c = 202;
}
class C extends B implements A{
public int a = 303;
private int d = 303;
public int[] array = {1,2,3,4,5};
}
//打印結果
public int example.C.a
public int[] example.C.array
public static final int example.A.a
public static final int example.A.b
public int example.B.a
public int example.B.b
public Field getDeclaredField(String name) (Class.java: 2403)(jdk13)
Returns a Field object that reflects the specified declared field of the class or interface represented by this Class object. The name parameter is a String that specifies the simple name of the desired field.
If this Class object represents an array type, then this method does not find the length field of the array type.
輸入一個字段名稱,如果在該類中能找到,返回一個 Field
對象。這個字段不再限於公共字段,但是也不會再去它的接口和父類去查找
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class cls = C.class;
System.out.println(cls.getDeclaredField("d"));
//private int example.C.d
}
}
class C{
public int a = 303;
private int d = 303;
public int[] array = {1,2,3,4,5};
}
public Field[] getDeclaredFields() (Class.java: 2244)(jdk13)
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
If this Class object represents a class or interface with no declared fields, then this method returns an array of length 0.
If this Class object represents an array type, a primitive type, or void, then this method returns an array of length 0.
The elements in the returned array are not sorted and are not in any particular order.
返回一個 Field
數組,包含這個類或接口的所有字段,對於沒有字段的對象返回長度爲0的數組,返回結果不帶任何排序
public class Main {
public static void main(String[] args){
Class cls = C.class;
for(var val:cls.getDeclaredFields())
{
System.out.println(val);
//public int example.C.a
//private int example.C.d
//protected int example.C.e
//public int[] example.C.array
}
}
}
class C{
public int a = 303;
private int d = 303;
protected int e = 303;
public int[] array = {1,2,3,4,5};
}
使用 Field
實例訪問修改對象對應字段的值
通過上述四種方法可以獲得 Field
對象,就可以用來修改相應的類的實例的對應字段的內容
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.rmi.MarshalledObject;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
Object object = new C();
Class cls = object.getClass();
Field field = cls.getField("a");
System.out.println("a: "+field.get(object));//a: 303
field.set(object,321);
System.out.println("a: "+field.get(object));//a: 321
//private字段只能通過帶Declared的方法獲取
Field privateField = cls.getDeclaredField("d");
//判斷該字段的訪問權限
System.out.println(Modifier.isPrivate(privateField.getModifiers()));//true
//不調用該方法,修改private對象會拋出IllegalAccessException異常
privateField.setAccessible(true);
//修改private字段內容
privateField.set(object,404);
System.out.println(privateField.get(object));//404
}
}
class C{
public int a = 303;
private int d = 303;
protected int e = 303;
public int[] array = {1,2,3,4,5};
}
小結
- 獲取某一類的
Class
實例 cls - 通過
cls.getFields()
等方法獲得object的屬性字段 field - 通過
field.get(object)
獲取 object 對應字段的值 - 通過
field.set(object,value)
將 object 對應字段的值設置爲 value
調用方法
-
public Method[] getMethods() (Class.java: 1900)(jdk13)
-
public Method getMethod(String name, Class<?>… parameterTypes) (Class.java: 2100)(jdk13)
-
public Method[] getDeclaredMethods() (Class.java: 2305)(jdk13)
-
public Method getDeclaredMethod(String name, Class<?>… parameterTypes) (Class.java: 2467)(jdk13)
這四個方法與上面四個獲取字段的方法類似,參數爲方法名和參數表,返回 Method
實例
使用 Method
實例調用方法
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Object object = new A();
Class cls = object.getClass();
//根據方法名和參數表獲取方法
Method method = cls.getDeclaredMethod("fun", int.class, int.class, C.class);
//調用方法
int ans = (int) method.invoke(object,2, 3, new C(4));
System.out.println(ans);
//24
}
}
class A {
public int fun(int a, int b, C c) {
return a * b * c.getC();
}
}
class C {
private int c;
C(int c) {
this.c = c;
}
int getC() {
return c;
}
}
小結
- 獲取某一類的
Class
實例 cls - 通過
cls.getMethods()
等方法獲得 object 能夠調用的方法 method - 通過
method.invoke(object,args)
調用object的對應方法
創建新實例
調用無參構造函數創建實例
Class cls = object.getClass();
Object c = cls.newInstance();
在JDK13中, newInstance()
方法已被廢棄,替代的方法爲以下創建新實例的一般方法
調用構造函數創建實例
通過 getDeclaredConstructor()
等方法獲得 Constructor
對象後再調用 newInstance(args)
方法創建,也可以對返回單個 Constructor
對象的方法後面鏈式調用 newInstance(args)
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class cls = C.class;
Object object = cls.getDeclaredConstructor().newInstance();
Object object1 = cls.getDeclaredConstructor(String.class).newInstance("object1");
//用Constructor對象構造
Constructor constructor = cls.getDeclaredConstructor(String.class);
Object object2 = constructor.newInstance("object2");
}
}
class C {
C(){
System.out.println("使用無參構造方法產生C的的新實例");
}
C(String name) {
System.out.println("C的新實例: "+name);
}
}
小結
- 獲取某一類的
Class
實例 cls - 通過
cls.getDeclaredConstructor()
等方法獲得Constructor
實例 constructor - 使用
constructor.newInstance(args)
創建新的實例