提到j(luò)ava語言的高級(jí)特性,反射絕對(duì)是Top1級(jí)別的,在大量開源框架中的應(yīng)用范例比比皆是,那么需要了解清楚反射到底是什么?為什么要使用反射?如何使用反射?(what,why,how)
什么是反射?
正常場景下,java從源碼到運(yùn)行有3個(gè)階段:
source class runtime
反射提供的是runtime階段獲取類的class實(shí)例、方法、屬性、注解,并且能夠調(diào)用類的方法的途徑,這種動(dòng)態(tài)獲取類信息和調(diào)用類方法的機(jī)制被稱之為反射
為什么要使用反射?
正常的實(shí)例化一個(gè)對(duì)象
ClassA objA = new ClassA();
objA.sayHello();
通過反射去實(shí)例化一個(gè)對(duì)象
Class objA = ClassA.class;
Method method = objA.getMethod("sayHello");
method.invoke(objA.newInstance());
在source階段實(shí)際上二者并無任何區(qū)別,反射也沒有體現(xiàn)出任何的優(yōu)勢,那么任何一個(gè)java開發(fā)人員必然會(huì)問為什么要使用反射?
反射的重點(diǎn)在于runtime階段的獲取類信息和調(diào)用類方法,那么當(dāng)你的編碼過程中中有“部分信息是source階段不清晰,需要在runtime階段動(dòng)態(tài)臨時(shí)加載”這種場景,反射就可以派上用場了
我們考慮幾個(gè)編碼場景:
1、編碼階段不知道需要實(shí)例化的類名是哪個(gè),需要在runtime從配置文件中加載:
Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();
2、在runtime階段,需要臨時(shí)訪問類的某個(gè)私有屬性
ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);
所以,反射的優(yōu)點(diǎn)在于“有些編碼需求在source階段無法實(shí)現(xiàn),只能在runtime階段通過反射實(shí)現(xiàn)”,而非“source階段正常編碼方式能解決的,反射的方式能解決的更好”,所以比較反射和正常編碼方式的優(yōu)劣是沒有意義的,反射解決的是正常編碼無法解決的編碼場景,如果正常編碼方式可以解決的,強(qiáng)行使用反射反而是毫無意義的,編碼不是為了show技巧。
反射應(yīng)用范例代碼
實(shí)現(xiàn)對(duì)類或者對(duì)象的構(gòu)造器、方法、屬性、注解的獲取和操作,具體作用見代碼中的注釋描述
public class ReflectionHelper {
/**
* Reflection Test Code
*
* @param args
*/
public static void main(String[] args) {
SSHClient sshClient = new SSHClient();
// 獲取class名稱
System.out.println("01-----獲取class名稱-----");
System.out.println(sshClient.getClass().getName());
System.out.println(sshClient.getClass().getSimpleName());
System.out.println(sshClient.getClass().getTypeName());
Class<?> clazz1 = null;
Class<?> clazz2 = null;
Class<?> clazz3 = null;
// 獲取對(duì)象或者類的Class實(shí)例
try {
clazz1 = Class.forName(sshClient.getClass().getName());
clazz2 = sshClient.getClass();
clazz3 = ReflectionUtils.class;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 獲取類的構(gòu)造函數(shù),用構(gòu)造函數(shù)實(shí)例一個(gè)對(duì)象
for (Constructor<?> clazz1Cstor : clazz1.getConstructors()) {
System.out.println(clazz1Cstor.getName());
try {
SSHClient client1 = (SSHClient) clazz1.newInstance();
SSHClient client2 = (SSHClient) clazz1Cstor.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
// 獲取類定義的方法、屬性
System.out.println("02-----獲取類定義的方法、屬性-----");
try {
SSHClient client = (SSHClient) clazz1.newInstance();
Method setHostMethod = clazz1.getDeclaredMethod("setHost", String.class);
setHostMethod.invoke(client, "111");
Field field = client.getClass().getDeclaredField("host");
field.setAccessible(true);
System.out.println(field.get(client));
field.set(client,"a new host");
System.out.println(field.get(client));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// 獲取類的注解
System.out.println("03-----獲取類使用的注解-----");
for (Annotation annotation : clazz1.getAnnotations()) {
System.out.println(annotation.getClass().getName());
System.out.println(annotation.toString());
System.out.println(annotation.annotationType());
}
}
}
運(yùn)行結(jié)果:
