JAVA反射簡介與使用示例
JAVA中的反射,所說的意思就是我們可以在程式執行期間內,動態獲取某一個Class物件的所有資訊,包括修飾符(modifiers),屬性(fields),方法(methods)等。
舉個例子就好比家裡的防盜門,各種Class物件就是來敲門的各種人,當我們獲取到一個未知其內容的Class物件的時候,就好比有一個沒有預約的人來敲門,此時我們無法感知門外面的人是誰,他有可能是物業,有可能是外賣小哥,也有可能是查水錶的。而反射就好比門眼,我們通過反射來觀察未知其內容的Class物件,就好比通過門眼來觀察門外的未知的人,這時,門外人的所有資訊我們就可以通過門眼知曉了,他可能是穿著黃衣服的美團小哥,也可能是藍衣服的餓了麼小哥,而且高矮胖瘦,顏值如何,盡在我們的掌握。
但是反射也會消耗系統性能、增加程式複雜度,就好比你去把門眼的時候不得不放棄你正在進行的DOTA團戰一樣,所以,需要在合理的情形下使用才是最好的。
我們先建立需要用到的示例Class類:
ReflectTest:
package reflecttest; public class ReflectTest { static{ System.out.println("ReflectTest is init"); } public String isPublicField = "defaultPublicField"; protected String isProtectedField = "defaultprotectedField"; String isDefaultField = "defaultDefaultField"; private String isPrivateField = "defaultPrivateField"; ReflectTest() { System.out.println("ReflectTest Constructor for no args"); } public ReflectTest(String arg1) { System.out.println("ReflectTest Constructor for String arg1"); } private ReflectTest(String arg1, String arg2) { System.out.println("ReflectTest Constructor for String arg1 and String arg2"); } public void isReloadMethod(String arg1) { System.out.println("isReloadMethod for String arg1"); } private void isReloadMethod(String arg1, String arg2) { System.out.println("isReloadMethod for String arg1 and String arg2"); } public void isPublicMethod() { System.out.println("isPublicMethod"); } protected void isProtectedMethod() { System.out.println("isProtectedMethod"); } void isDefaultMethod() { System.out.println("isDefaultMethod"); } private void isPrivateMethod() { System.out.println("isPrivateMethod"); } public String getIsPublicField() { return isPublicField; } public void setIsPublicField(String isPublicField) { this.isPublicField = isPublicField; } public String getIsPrivateField() { return isPrivateField; } public void setIsPrivateField(String isPrivateField) { this.isPrivateField = isPrivateField; } public String getIsProtectedField() { return isProtectedField; } public void setIsProtectedField(String isProtectedField) { this.isProtectedField = isProtectedField; } public String getIsDefaultField() { return isDefaultField; } public void setIsDefaultField(String isDefaultField) { this.isDefaultField = isDefaultField; } }
1. 進行反射,首先也是必要的,就是獲取Class物件,一共有三種方法:
public static void main(String[] args) { /* 注意:這種通過 類名.class 方式來獲取class物件的方式並不會初始化ReflectTest類 */ Class c1 = ReflectTest.class; System.out.println("====================="); /* 當我們獲取到了一個Object物件,但是我們無法確定它屬於哪個物件時 我們可以通過 物件.getClass()的方式來獲取這個物件的Class物件 */ Object reflectTest = new ReflectTest(); Class c2 = reflectTest.getClass(); System.out.println("====================="); try { /** * 當我們已知某個類的完整類路徑名稱的時候,可以通過Class.forName()方法來獲取Class物件 * 但是可能會丟擲 ClassNotFoundException 異常 */ Class c3 = Class.forName("reflecttest.ReflectTest"); /* * 每個類只會有一個class物件,因此通過以上三種方法得到的 c1、c2、c3 其實是同一個物件 * 因此互相之間equals為true */ System.out.println(c1.equals(c2)); System.out.println(c1.equals(c3)); System.out.println(c2.equals(c3)); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
控制檯列印如下:
2. 獲取到Class物件後,通過Class物件獲取Class內容的常用方法如下:
getName():獲取類的名稱(包名 . 類名)
getFields():獲取類的所有public修飾的屬性
getField(String name):獲取類的符合指定名稱的public修飾的屬性,無法獲取default、protected、private修飾的屬性
getDeclaredFields():獲取類的所有屬性,包含public、protected、default、private修飾的屬性
getDeclaredField(String name):獲取指定名稱的field屬性,包含public、protected、default、private修飾的屬性
getMethods():獲取所有的public修飾的方法
getMethod(String name, Class<T>... parameterTypes):獲取符合指定方法名稱與引數列表的public修飾的方法,第一個引數為方法名稱,其餘後面的引數都依次為引數列表的各個引數型別
getDeclaredMethods():獲取類的所有方法,包含public、protected、default、private修飾的方法
getDeclaredMethod(String name, Class<T>... parameterTypes):獲取符合指定名稱與引數列表的方法,包含public、protected、default、private修飾的方法,第一個引數為方法名稱,其餘後面的引數都依次為引數列表的各個引數型別
getConstructors():獲取類的所有的public修飾的建構函式
getConstructor(Class<T>... parameterTypes):獲取類的符合指定引數列表的public修飾的構造方法
getDeclaredConstructors():獲取類的所有的建構函式,包含public、protected、default、private修飾的建構函式
getDeclaredConstructor(Class<T>... parameterTypes):獲取類的符合指定引數列表的構造方法,包含public、protected、default、private修飾的構造方法
newInstance():通過該類的無參建構函式進行物件例項化
程式碼示例:
getName():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getName() 方法獲取類的完整類路徑名稱
System.out.println(classObj.getName());
}
執行結果:
getFields():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getFields() 方法獲取所有的 public 修飾符修飾的field屬性
Field[] publicFields = classObj.getFields();
Arrays.stream(publicFields).forEach(System.out::println);
}
執行結果:
getField(String name):
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getField(String name) 方法獲取指定名稱的 public 修飾的field屬性,無法獲取非public修飾的field
try {
Field publicField = classObj.getField("isPublicField");
System.out.println("publicField:"+ publicField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field protectedField = classObj.getField("isProtectedField");
System.out.println("protectedField:"+ protectedField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field defaultField = classObj.getField("isDefaultField");
System.out.println("defaultField:"+ defaultField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field privateField = classObj.getField("isPrivateField");
System.out.println("privateField:"+ privateField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
執行結果:
getDeclaredFields():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getFields() 方法獲取所有的 public 修飾符修飾的field屬性
Field[] publicFields = classObj.getDeclaredFields();
Arrays.stream(publicFields).forEach(System.out::println);
}
執行結果:
getDeclaredFields():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getDeclaredField(String name) 方法獲取指定名稱的field屬性,包含public、protected、default、private修飾的屬性
try {
Field publicField = classObj.getDeclaredField("isPublicField");
System.out.println("publicField:" + publicField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field protectedField = classObj.getDeclaredField("isProtectedField");
System.out.println("protectedField:" + protectedField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field defaultField = classObj.getDeclaredField("isDefaultField");
System.out.println("defaultField:" + defaultField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field privateField = classObj.getDeclaredField("isPrivateField");
System.out.println("privateField:" + privateField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
執行結果:
getMethods():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getMethods()方法會獲取所有的public修飾的方法
Method[] methods = classObj.getMethods();
Arrays.stream(methods).forEach(System.out::println);
}
執行結果:
getMethod(String name, Class<T>... parameterTypes):
public static void main(String[] args) {
Class classObj = ReflectTest.class;
Method method;
// getMethod(String name, Class<T>... parameterTypes)方法會獲取符合指定名稱與引數列表的public修飾的方法
try {
method = classObj.getMethod("isReloadMethod", String.class);
System.out.println("String.class(public):" + method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
method = classObj.getMethod("isReloadMethod", String.class, String.class);
System.out.println("String.class, String.class(private):" + method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
// 因為本身ReflectTest類就不具備引數列表為只接受一個Integer型別的isReloadMethod方法,所以會報出沒有目標方法的異常
method = classObj.getMethod("isReloadMethod", Integer.class);
System.out.println("Integer.class(not exits):" + method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
執行結果:
getDeclaredMethods():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// getDeclaredMethods()方法會獲取所有的方法
Method[] methods = classObj.getDeclaredMethods();
Arrays.stream(methods).forEach(System.out::println);
}
執行結果:
getDeclaredMethod(String name, Class<T>... parameterTypes):
public static void main(String[] args) {
Class classObj = ReflectTest.class;
Method method;
// getDeclaredMethod(String name, Class<T>... parameterTypes)方法會獲取符合指定名稱與引數列表的方法
try {
method = classObj.getDeclaredMethod("isReloadMethod", String.class);
System.out.println("String.class(public):"+method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
method = classObj.getDeclaredMethod("isReloadMethod", String.class, String.class);
System.out.println("String.class, String.class(private):"+method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
// 因為本身ReflectTest類就不具備引數列表為只接受一個Integer型別的isReloadMethod方法,所以會報出沒有目標方法的異常
method = classObj.getDeclaredMethod("isReloadMethod", Integer.class);
System.out.println("Integer.class(not exits):"+method);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
執行結果:
getConstructors():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
Constructor[] constructors = classObj.getConstructors();
Arrays.stream(constructors).forEach(System.out::println);
}
執行結果:
getConstructor(Class<T>... parameterTypes):
public static void main(String[] args) {
Class classObj = ReflectTest.class;
Constructor constructor;
// getConstructor(Class<T>... parameterTypes)方法會獲取符合指定引數列表的public修飾的構造方法
try {
constructor = classObj.getConstructor();
System.out.println("no args(default):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
constructor = classObj.getConstructor(String.class);
System.out.println("String.class(public):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
constructor = classObj.getConstructor(String.class, String.class);
System.out.println("String.class, String.class(private):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
// 因為本身ReflectTest類就不具備引數列表為只接受一個Integer型別的建構函式,所以會報出沒有目標方法的異常
constructor = classObj.getConstructor(Integer.class);
System.out.println("Integer.class(not exits):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
執行結果:
getDeclaredConstructors():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
Constructor[] constructors = classObj.getDeclaredConstructors();
Arrays.stream(constructors).forEach(System.out::println);
}
執行結果:
getDeclaredConstructor(Class<T>... parameterTypes):
public static void main(String[] args) {
Class classObj = ReflectTest.class;
Constructor constructor;
// getDeclaredConstructor(Class<T>... parameterTypes)方法會獲取符合指定引數列表的構造方法
try {
constructor = classObj.getDeclaredConstructor();
System.out.println("no args(default):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
constructor = classObj.getDeclaredConstructor(String.class);
System.out.println("String.class(public):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
constructor = classObj.getDeclaredConstructor(String.class, String.class);
System.out.println("String.class, String.class(private):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
constructor = classObj.getDeclaredConstructor(Integer.class);
System.out.println("Integer.class(not exits):" + constructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
執行結果:
newInstance():
public static void main(String[] args) {
Class classObj = ReflectTest.class;
// newInstance()方法會通過該類的無參建構函式進行物件例項化
try {
Object reflectTest = classObj.newInstance();
System.out.println(reflectTest);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
執行結果: