微信搜索:碼農(nóng)StayUp
主頁(yè)地址:https://gozhuyinglong.github.io
源碼分享:https://github.com/gozhuyinglong/blog-demos
1. 前言
在OOP的世界里,萬(wàn)物皆對(duì)象灵临。也就是說(shuō),我們可以將任何東西抽象成一個(gè)對(duì)象。
比如人洪鸭,可以抽象成一個(gè)Person類了牛,通過(guò)new Person()來(lái)實(shí)例化一個(gè)對(duì)象;再比如鴨子,可以抽象成一個(gè)Duck類艘绍,也可以對(duì)其進(jìn)行實(shí)例化……那么這一個(gè)個(gè)類本身是不是也可以抽象成一個(gè)類呢?Java提供了一個(gè)特殊的類Class
秫筏,用來(lái)描述類的內(nèi)部信息诱鞠,是反射的核心類。
下圖是本篇講述內(nèi)容:
2. Java反射機(jī)制概述
Java反射(Reflection)允許應(yīng)用程序在運(yùn)行時(shí)借助于反射API这敬,來(lái)獲取所有類或接口的內(nèi)部信息航夺,并且能直接操作任意對(duì)象的內(nèi)部屬性及方法。反射機(jī)制的核心類為java.lang.Class
崔涂。
- 類加載完后晶密,會(huì)在堆內(nèi)存的方法區(qū)中產(chǎn)生一個(gè)
Class
類型的對(duì)象侨赡。 -
Class
類沒(méi)有公開的構(gòu)造函數(shù)淡诗,是由類加載器的defineClass
方法構(gòu)造而成痘番。所以Class
對(duì)象不是“new”出來(lái)的,而是通過(guò)方法來(lái)獲取的蝙茶。 - 這個(gè)
Class
對(duì)象具有類的完整結(jié)構(gòu)信息艺骂,并且一個(gè)類只有一個(gè)Class
對(duì)象。
3. 獲取Class對(duì)象
獲取Class
對(duì)象有以下四種方式:
- 通過(guò)類對(duì)象獲仁ⅰ彻亲;
- 通過(guò)類直接調(diào)用class獲仍谐吮廉;
- 通過(guò)Class.forName獲取畸肆;
- 通過(guò)類加載器獲取宦芦。
下面使用代碼展示獲取 Person 類的Class
對(duì)象的四種方式:
@Test
public void testClassFor() {
// 1.通過(guò)類實(shí)例獲取
Person person = new Person();
Class<? extends Person> clazz1 = person.getClass();
System.out.println("01 - " + clazz1);
// 2.通過(guò)類直接調(diào)用class獲取
Class<Person> clazz2 = Person.class;
System.out.println("02 - " + clazz2);
// 3.通過(guò)Class.forName獲取
Class<?> clazz3 = null;
try {
clazz3 = Class.forName("io.github.gozhuyinglong.reflection.Person");
} catch (ClassNotFoundException e) {
// 當(dāng)找不到指定類時(shí),會(huì)拋出此異常
e.printStackTrace();
}
System.out.println("03 - " + clazz3);
// 4.通過(guò)類加載器獲取
ClassLoader classLoader = this.getClass().getClassLoader();
Class<?> clazz4 = null;
try {
clazz4 = classLoader.loadClass("io.github.gozhuyinglong.reflection.Person");
} catch (ClassNotFoundException e) {
// 當(dāng)找不到指定類時(shí)轴脐,會(huì)拋出此異常
e.printStackTrace();
}
System.out.println("04 - " + clazz4);
// hashCode相等调卑,說(shuō)明這四種方式獲取的是同一個(gè)實(shí)例
System.out.println("05 - " + clazz1.hashCode());
System.out.println("06 - " + clazz2.hashCode());
System.out.println("07 - " + clazz3.hashCode());
System.out.println("08 - " + clazz4.hashCode());
}
輸出結(jié)果:
01 - class io.github.gozhuyinglong.reflection.Person
02 - class io.github.gozhuyinglong.reflection.Person
03 - class io.github.gozhuyinglong.reflection.Person
04 - class io.github.gozhuyinglong.reflection.Person
05 - 721748895
06 - 721748895
07 - 721748895
08 - 721748895
通過(guò)上面的輸出結(jié)果可以看出抡砂,這四個(gè)Class
對(duì)象的hashCode
相同,說(shuō)明使用這四種方式獲取的是同一個(gè)對(duì)象恬涧。
4. 一些特殊的類和接口的Class對(duì)象
在源碼注釋中提到一些特殊的類和接口:
- 枚舉是一種類注益。
- 注解是一種接口。
- 數(shù)組也屬于一個(gè)反映為
Class
對(duì)象的類溯捆。具有相同元素類型和維數(shù)的數(shù)組丑搔,也具有相同的Class
對(duì)象(也就是說(shuō),元素類型不同提揍,或數(shù)組維數(shù)不同啤月,其Class
對(duì)象也不同)。 - 原始Java類型(
boolean
,byte
,char
,short
,int
,long
,float
,double
)和關(guān)鍵字void
也表示為Class
對(duì)象劳跃。
下面通過(guò)代碼來(lái)驗(yàn)證:
@Test
public void testClassOther() {
// 枚舉是一種類
Class<PersonEnum> clazz1 = PersonEnum.class;
System.out.println("01 - " + clazz1);
// 注解是一種接口
Class<PersonAnnotation> clazz2 = PersonAnnotation.class;
System.out.println("02 - " + clazz2);
// 數(shù)組也屬于一個(gè)反應(yīng) Class 實(shí)例的類
Person[] personArray3 = new Person[1];
Class<? extends Person[]> clazz3 = personArray3.getClass();
System.out.println("03 - " + clazz3);
// 具有相同元素類型和維數(shù)的數(shù)組谎仲,也具有相同的 Class 實(shí)例
Person[] personArray4 = new Person[4];
Class<?> clazz4 = personArray4.getClass();
Person[][] personArray5 = new Person[1][];
Class<?> clazz5 = personArray5.getClass();
// 兩個(gè)一維數(shù)組的 hashCode 相等,說(shuō)明是同一實(shí)例
System.out.println("04 - " + clazz3.hashCode());
System.out.println("05 - " + clazz4.hashCode());
// 一維數(shù)組與二維數(shù)組的 hashCode 不相等刨仑,說(shuō)明不是同一實(shí)例
System.out.println("06 - " + clazz5.hashCode());
// 原始 Java 類型和關(guān)鍵字 void 也表示為 Class 實(shí)例
Class<Integer> clazz6 = int.class;
System.out.println("07 - " + clazz6);
Class<Double> clazz7 = double.class;
System.out.println("08 - " + clazz7);
Class<Void> clazz8 = void.class;
System.out.println("09 - " + clazz8);
}
輸出結(jié)果:
01 - class io.github.gozhuyinglong.reflection.PersonEnum
02 - interface io.github.gozhuyinglong.reflection.PersonAnnotation
03 - class [Lio.github.gozhuyinglong.reflection.Person;
04 - 721748895
05 - 721748895
06 - 1642534850
07 - int
08 - double
09 - void
通過(guò)輸出結(jié)果可以看出郑诺,確如源碼中描述那樣。
5. Java反射API
Java提供了一套反射API杉武,該API由Class
類與java.lang.reflect
類庫(kù)組成间景。該類庫(kù)包含了Field
、Method
艺智、Constructor
等類倘要。這些類型的對(duì)象是由JVM在運(yùn)行時(shí)創(chuàng)建的,用以表示未知類里對(duì)應(yīng)的成員十拣。
反射允許以編程的方式訪問(wèn)已加載類的字段封拧、方法和構(gòu)造函數(shù)信息,并在安全限制內(nèi)利用反射對(duì)其進(jìn)行操作夭问。
下面將介紹一些常用的類:
5.1 Class(類)
java.lang.Class
類用來(lái)描述類的內(nèi)部信息泽西,Class
的實(shí)例可以獲取類的包、注解缰趋、修飾符捧杉、名稱、超類秘血、接口等味抖。
@Test
public void testClass() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 獲取該類所在包路徑
Package aPackage = clazz.getPackage();
System.out.println("01 - " + aPackage);
// 獲取該類上所有注解
Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
for (Annotation temp : declaredAnnotations) {
System.out.println("02 - " + temp);
}
// 獲取類上的修飾符
int modifiers = clazz.getModifiers();
String modifier = Modifier.toString(modifiers);
System.out.println("03 - " + modifier);
// 獲取類名稱
String name = clazz.getName();
System.out.println("04 - " + name);
// 獲取簡(jiǎn)單類名
String simpleName = clazz.getSimpleName();
System.out.println("05 - " + simpleName);
// 獲取直屬超類
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println("06 - " + genericSuperclass);
// 獲取直屬實(shí)現(xiàn)的接口
Type[] genericInterfaces = clazz.getGenericInterfaces();
for (Type temp : genericInterfaces) {
System.out.println("07 - " + temp);
}
}
輸出結(jié)果:
01 - package io.github.gozhuyinglong.reflection
02 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
03 - public final
04 - io.github.gozhuyinglong.reflection.Person
05 - Person
06 - class io.github.gozhuyinglong.reflection.PersonParent
07 - interface io.github.gozhuyinglong.reflection.PersonInterface
5.2 Constructor(構(gòu)造函數(shù))
java.lang.reflect.Constructor
提供了類的構(gòu)造函數(shù)信息』伊福可以獲取構(gòu)造函數(shù)上的注解信息仔涩、參數(shù)類型等。
@Test
public void testConstructor() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 獲取一個(gè)聲明為 public 構(gòu)造函數(shù)實(shí)例
Constructor<?> constructor1 = clazz.getConstructor(String.class, int.class, PersonEnum.class);
System.out.println("01 - " + constructor1);
// 獲取所有聲明為 public 構(gòu)造函數(shù)實(shí)例
Constructor<?>[] constructorArray1 = clazz.getConstructors();
for (Constructor<?> constructor : constructorArray1) {
System.out.println("02 - " + constructor);
}
// 獲取一個(gè)聲明的構(gòu)造函數(shù)實(shí)例
Constructor<?> constructor2 = clazz.getDeclaredConstructor(String.class);
System.out.println("03 - " + constructor2);
// 獲取所有聲明的構(gòu)造函數(shù)實(shí)例
Constructor<?>[] constructorArray2 = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructorArray2) {
System.out.println("04 - " + constructor);
}
// 根據(jù)構(gòu)造函數(shù)創(chuàng)建一個(gè)實(shí)例
Object o1 = constructor1.newInstance("楊過(guò)", 25, PersonEnum.MAN);
System.out.println("05 - " + o1);
// 將構(gòu)造函數(shù)的可訪問(wèn)標(biāo)志設(shè)為 true 后粘舟,可以通過(guò)私有構(gòu)造函數(shù)創(chuàng)建實(shí)例
constructor2.setAccessible(true);
Object o2 = constructor2.newInstance("小龍女");
System.out.println("06 - " + o2);
// 獲取該構(gòu)造函數(shù)上的所有注解
Annotation[] annotations = constructor1.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
System.out.println("07 - " + annotation);
}
// 獲取該構(gòu)造函數(shù)上的所有參數(shù)類型
Type[] genericParameterTypes = constructor1.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("08 - " + genericParameterType);
}
}
輸出結(jié)果:
01 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum)
02 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum)
02 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int)
02 - public io.github.gozhuyinglong.reflection.Person()
03 - private io.github.gozhuyinglong.reflection.Person(java.lang.String)
04 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum)
04 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int)
04 - private io.github.gozhuyinglong.reflection.Person(java.lang.String)
04 - public io.github.gozhuyinglong.reflection.Person()
05 - Person{name='楊過(guò)', age=25, sex='MAN'}
06 - Person{name='小龍女', age=0, sex='null'}
07 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
08 - class java.lang.String
08 - int
08 - class io.github.gozhuyinglong.reflection.PersonEnum
5.3 Field(屬性)
java.lang.reflect.Field
提供了類的屬性信息熔脂∨逖校可以獲取屬性上的注解、修飾符霞揉、屬性類型旬薯、屬性名等。
@Test
public void testField() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 獲取一個(gè)該類或父類中聲明為 public 的屬性
Field field1 = clazz.getField("hobby");
System.out.println("01 - " + field1);
// 獲取該類及父類中所有聲明為 public 的屬性
Field[] fieldArray1 = clazz.getFields();
for (Field field : fieldArray1) {
System.out.println("02 - " + field);
}
// 獲取一個(gè)該類中聲明的屬性
Field field2 = clazz.getDeclaredField("name");
System.out.println("03 - " + field2);
// 獲取該類中所有聲明的屬性
Field[] fieldArray2 = clazz.getDeclaredFields();
for (Field field : fieldArray2) {
System.out.println("04 - " + field);
}
// 獲取該屬性上的所有注解
Annotation[] declaredAnnotations = field2.getDeclaredAnnotations();
for (Annotation declaredAnnotation : declaredAnnotations) {
System.out.println("05 - " + declaredAnnotation);
}
// 獲取修飾符
String modifier = Modifier.toString(field2.getModifiers());
System.out.println("06 - " + modifier);
// 獲取屬性類型适秩,返回類對(duì)象
Class<?> type = field2.getType();
System.out.println("07 - " + type);
// 獲取屬性類型袍暴,返回Type對(duì)象
Type genericType = field2.getGenericType();
System.out.println("08 - " + genericType);
// 獲取屬性名稱
String name = field2.getName();
System.out.println("09 - " + name);
}
輸出結(jié)果:
01 - public java.lang.String io.github.gozhuyinglong.reflection.PersonParent.hobby
02 - public int io.github.gozhuyinglong.reflection.Person.height
02 - public java.lang.String io.github.gozhuyinglong.reflection.PersonParent.hobby
03 - private java.lang.String io.github.gozhuyinglong.reflection.Person.name
04 - private java.lang.String io.github.gozhuyinglong.reflection.Person.name
04 - private int io.github.gozhuyinglong.reflection.Person.age
04 - public int io.github.gozhuyinglong.reflection.Person.height
05 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
06 - private
07 - class java.lang.String
08 - class java.lang.String
09 - name
5.4 Method(方法)
java.lang.reflect.Method
提供了類的方法信息×ブⅲ可以獲取方法上的注解政模、修飾符、返回值類型蚂会、方法名稱淋样、所有參數(shù)。
@Test
public void testMethod() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 獲取一個(gè)該類及父類中聲明為 public 的方法胁住,需要指定方法的入?yún)㈩愋? Method method = clazz.getMethod("setName", String.class);
System.out.println("01 - " + method);
// 獲取該類及父類中所有聲明為 public 的方法
Method[] methods = clazz.getMethods();
for (Method temp : methods) {
System.out.println("02 - " + temp);
}
// 獲取一個(gè)在該類中聲明的方法
Method declaredMethod = clazz.getDeclaredMethod("display");
System.out.println("03 - " + declaredMethod);
// 獲取所有在該類中聲明的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method temp : declaredMethods) {
System.out.println("04 - " + temp);
}
// 獲取該方法上的所有注解
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
for (Annotation temp : declaredAnnotations) {
System.out.println("05 - " + temp);
}
// 獲取修飾符
String modifier = Modifier.toString(method.getModifiers());
System.out.println("06 - " + modifier);
// 獲取返回值類型趁猴,返回類對(duì)象
Class<?> returnType = method.getReturnType();
System.out.println("07 - " + returnType);
// 獲取返回值類型,返回Type對(duì)象
Type genericReturnType = method.getGenericReturnType();
System.out.println("08 - " + genericReturnType);
// 獲取方法名稱
String name = method.getName();
System.out.println("09 - " + name);
// 獲取所有入?yún)? Parameter[] parameters = method.getParameters();
for (Parameter temp : parameters) {
System.out.println("10 - " + temp);
}
}
輸出結(jié)果:
01 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.toString()
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.getName()
02 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
02 - public int io.github.gozhuyinglong.reflection.Person.getAge()
02 - public void io.github.gozhuyinglong.reflection.Person.setAge(int)
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.sayHello()
02 - public io.github.gozhuyinglong.reflection.PersonEnum io.github.gozhuyinglong.reflection.PersonParent.getSex()
02 - public void io.github.gozhuyinglong.reflection.PersonParent.setSex(io.github.gozhuyinglong.reflection.PersonEnum)
02 - public final void java.lang.Object.wait() throws java.lang.InterruptedException
02 - public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
02 - public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
02 - public boolean java.lang.Object.equals(java.lang.Object)
02 - public native int java.lang.Object.hashCode()
02 - public final native java.lang.Class java.lang.Object.getClass()
02 - public final native void java.lang.Object.notify()
02 - public final native void java.lang.Object.notifyAll()
03 - private java.lang.String io.github.gozhuyinglong.reflection.Person.display()
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.toString()
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.getName()
04 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
04 - private java.lang.String io.github.gozhuyinglong.reflection.Person.display()
04 - public int io.github.gozhuyinglong.reflection.Person.getAge()
04 - public void io.github.gozhuyinglong.reflection.Person.setAge(int)
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.sayHello()
05 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
06 - public
07 - void
08 - void
09 - setName
10 - java.lang.String arg0
5.5 Modifier(修飾符)
java.lang.reflect.Modifier
提供了訪問(wèn)修飾符信息彪见。通過(guò)Class
儡司、Field
、Method
余指、Constructor
等對(duì)象都可以獲取修飾符捕犬,這個(gè)訪問(wèn)修飾符是一個(gè)整數(shù),可以通過(guò)Modifier.toString
方法來(lái)查看修飾符描述酵镜。并且該類提供了一些靜態(tài)方法和常量來(lái)解碼訪問(wèn)修飾符碉碉。
@Test
public void testModifier() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 獲取類的修飾符值
int modifiers1 = clazz.getModifiers();
System.out.println("01 - " + modifiers1);
// 獲取屬性的修飾符值
int modifiers2 = clazz.getDeclaredField("name").getModifiers();
System.out.println("02 - " + modifiers2);
// 獲取構(gòu)造函數(shù)的修飾符值
int modifiers3 = clazz.getDeclaredConstructor(String.class).getModifiers();
System.out.println("03 - " + modifiers3);
// 獲取方法的修飾符值
int modifiers4 = clazz.getDeclaredMethod("display").getModifiers();
System.out.println("04 - " + modifiers4);
// 判斷修飾符值是否 final 類型
boolean isFinal = Modifier.isFinal(modifiers1);
System.out.println("05 - " + isFinal);
// 判斷修飾符值是否 public 類型
boolean isPublic = Modifier.isPublic(modifiers2);
System.out.println("06 - " + isPublic);
// 根據(jù)修飾符值,獲取修飾符標(biāo)志的字符串
String modifier = Modifier.toString(modifiers1);
System.out.println("07 - " + modifier);
System.out.println("08 - " + Modifier.toString(modifiers2));
}
輸出結(jié)果:
01 - 17
02 - 2
03 - 2
04 - 2
05 - true
06 - false
07 - public final
08 - private
5.6 Parameter(參數(shù))
java.lang.reflect.Parameter
提供了方法的參數(shù)信息淮韭」噶福可以獲取方法上的注解、參數(shù)名稱靠粪、參數(shù)類型等蜡吧。
@Test
public void testParameter() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 獲取構(gòu)造函數(shù)的參數(shù)
Constructor<?> constructor = clazz.getConstructor(String.class, int.class, PersonEnum.class);
Parameter[] parameterArray1 = constructor.getParameters();
for (Parameter temp : parameterArray1) {
System.out.println("01 - " + temp);
}
// 獲取方法的參數(shù)
Method method = clazz.getMethod("setName", String.class);
Parameter[] parameterArray2 = method.getParameters();
for (Parameter temp : parameterArray2) {
System.out.println("02 - " + temp);
}
Parameter parameter = parameterArray1[0];
// 獲取參數(shù)上的注解
Annotation[] annotationArray = parameter.getAnnotations();
for (Annotation temp : annotationArray) {
System.out.println("02 - " + temp);
}
// 獲取參數(shù)名稱
String name = parameter.getName();
System.out.println("03 - " + name);
// 獲取參數(shù)類型
Type parameterizedType = parameter.getParameterizedType();
System.out.println("04 - " + parameterizedType);
Class<?> type = parameter.getType();
System.out.println("05 - " + type);
}
輸出結(jié)果:
01 - java.lang.String arg0
01 - int arg1
01 - io.github.gozhuyinglong.reflection.PersonEnum arg2
02 - java.lang.String arg0
02 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
03 - arg0
04 - class java.lang.String
05 - class java.lang.String
5.7 AccessibleObject(可訪問(wèn)標(biāo)志)
java.lang.reflect.AccessibleObject
類是Field
、Method
和Constructor
類的超類占键。
該類提供了對(duì)類昔善、方法、構(gòu)造函數(shù)的訪問(wèn)控制檢查的能力(如:私有方法只允許當(dāng)前類訪問(wèn))捞慌。
該訪問(wèn)檢查在設(shè)置/獲取屬性耀鸦、調(diào)用方法、創(chuàng)建/初始化類的實(shí)例時(shí)執(zhí)行啸澡。
可以通過(guò)setAccessible
方法將可訪問(wèn)標(biāo)志設(shè)為true
(默認(rèn)為false
)袖订,會(huì)關(guān)閉訪問(wèn)檢查。這樣即使是私有的屬性嗅虏、方法或構(gòu)造函數(shù)洛姑,也可以訪問(wèn)。
6. 通過(guò)反射動(dòng)態(tài)創(chuàng)建對(duì)象并執(zhí)行方法
可以利用反射來(lái)創(chuàng)建對(duì)象皮服,并可執(zhí)行方法楞艾,下面看代碼示例:
- 通過(guò)
Class
類的newInstance
創(chuàng)建一個(gè)實(shí)例。(該方法調(diào)用無(wú)參構(gòu)造器)龄广。 - 通過(guò)構(gòu)造函數(shù)
Constructor
類創(chuàng)建一個(gè)實(shí)例硫眯。 - 獲取方法,再通過(guò)
invoke
方法來(lái)調(diào)用择同,第一個(gè)參數(shù)為實(shí)例两入,后面參數(shù)為方法的Parameter
。 - 獲取字段敲才,因?yàn)?age 字段是私有的裹纳,所以將其設(shè)置為可訪問(wèn)(不設(shè)置會(huì)報(bào)異常)。并通過(guò)
set
方法來(lái)賦值紧武。
@Test
public void testInvoke() throws Exception {
Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");
// 通過(guò)Class類的newInstance創(chuàng)建一個(gè)實(shí)例剃氧。(該方法調(diào)用無(wú)參構(gòu)造器)
Object o1 = clazz.newInstance();
System.out.println("01 - " + o1.toString());
// 通過(guò)構(gòu)造函數(shù)Constructor類創(chuàng)建一個(gè)實(shí)例
Constructor<?> constructor = clazz.getConstructor(String.class, int.class, PersonEnum.class);
Object o2 = constructor.newInstance("楊過(guò)", 25, PersonEnum.MAN);
System.out.println("02 - " + o2.toString());
// 先獲取方法,再通過(guò) invoke 方法來(lái)調(diào)用阻星,第一個(gè)參數(shù)為實(shí)例朋鞍,后面參數(shù)為方法的Parameter
Method method = clazz.getMethod("setName", String.class);
method.invoke(o1, "小龍女");
System.out.println("03 - " + o1.toString());
// 獲取字段,因?yàn)?age 字段是私有的妥箕,所以將其設(shè)置為可訪問(wèn)(不設(shè)置會(huì)報(bào)異常)番舆。并通過(guò) set 方法來(lái)賦值
Field field = clazz.getDeclaredField("age");
field.setAccessible(true);
field.set(o1, 28);
System.out.println("04 - " + o1.toString());
}
執(zhí)行結(jié)果:
01 - Person{name='null', age=0, sex='null'}
02 - Person{name='楊過(guò)', age=25, sex='MAN'}
03 - Person{name='小龍女', age=0, sex='null'}
04 - Person{name='小龍女', age=28, sex='null'}
7. 反射的缺點(diǎn)
引自官方指南:https://docs.oracle.com/javase/tutorial/reflect/index.html
反射雖是強(qiáng)大的,但不可隨意使用矾踱。如果可以在不使用反射的情況下執(zhí)行操作恨狈,則應(yīng)避免使用它。因?yàn)橥ㄟ^(guò)反射訪問(wèn)代碼時(shí)呛讲,會(huì)有以下缺點(diǎn)禾怠。
7.1 性能開銷
反射包括了一些動(dòng)態(tài)類型,所以JVM無(wú)法對(duì)這些代碼進(jìn)行優(yōu)化贝搁。因此吗氏,反射操作的效率要比那些非反射操作低得多。我們應(yīng)該避免在經(jīng)常被執(zhí)行的代碼或?qū)π阅芤蠛芨叩某绦蛑惺褂梅瓷洹?/p>
7.2 安全限制
使用反射技術(shù)要求程序必須在一個(gè)沒(méi)有安全限制的環(huán)境中運(yùn)行雷逆。如果一個(gè)程序必須在有安全限制的環(huán)境中運(yùn)行弦讽,如Applet,那么這就是個(gè)問(wèn)題了。
7.3 內(nèi)部暴露
由于反射允許代碼執(zhí)行一些在正常情況下不被允許的操作往产,比如訪問(wèn)私有的屬性和方法被碗。所以使用反射可能會(huì)導(dǎo)致意料之外的副作用:代碼有功能上的錯(cuò)誤,降低可移植性仿村。反射代碼破壞了抽象性锐朴,因此當(dāng)平臺(tái)發(fā)生改變的時(shí)候,代碼的行為就有可能也隨著變化蔼囊。
8. 完整代碼
完整代碼請(qǐng)?jiān)L問(wèn)我的Github焚志,若對(duì)你有幫助,歡迎給個(gè)?畏鼓,感謝~~??????