Java中反射的應(yīng)用
反射的應(yīng)用
1. 獲取運(yùn)行時(shí)類的完整結(jié)構(gòu)
通過反射獲取運(yùn)行時(shí)類的完整結(jié)構(gòu),包括一下所列都是可以獲取的,下面來試試
- Interface:實(shí)現(xiàn)的全部接口
- Superclass:所繼承的父類
- Constructor:全部的構(gòu)造器
- Method:全部的方法
- Field:全部的屬性
- Annotation:注解
新建一個(gè) Person.java 類
package com.javabasic.reflection;
/**
* @Description
* @ClassName Person
* @Author yuhuofei
* @Date 2022/9/25 16:44
* @Version 1.0
*/
public class Person {
private String name;
private Integer age;
private String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
private Integer getAge() {
return age;
}
private void setAge(Integer age) {
this.age = age;
}
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
新建 TestReflection.java 類,測試一下通過反射獲取上面這個(gè)類的信息
package com.javabasic.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @Description 反射的應(yīng)用
* @ClassName TestReflection
* @Author yuhuofei
* @Date 2022/10/2 15:57
* @Version 1.0
*/
public class TestReflection {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class<?> aClass = Class.forName("com.javabasic.reflection.Person");
System.out.println("==================獲取類名=====================");
//獲取類的名字
System.out.println("類名:" + aClass.getSimpleName());
//獲取包名+類名
System.out.println("包名及類名:" + aClass.getName());
System.out.println("==================獲取類的屬性=====================");
//獲取類的public類型屬性
Field[] fields1 = aClass.getFields();
for (Field field : fields1) {
System.out.println("類的public類型屬性:" + field);
}
//獲取類的所有屬性
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
System.out.println("類的所有屬性:" + field);
}
//獲取指定的屬性
Field name = aClass.getDeclaredField("name");
System.out.println("類的指定屬性:" + name);
System.out.println("==================獲取類的方法=====================");
//獲取本類及父類的所有public類型方法
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println("本類及父類的所有public類型方法:" + method);
}
//獲取本類及父類的所有方法
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println("本類父類的所有方法:" + method);
}
//獲取指定方法
Method getName = aClass.getDeclaredMethod("getName", null);
Method setName = aClass.getDeclaredMethod("setName", String.class);
System.out.println("獲取指定的getName方法:" + getName);
System.out.println("獲取指定的setName方法:" + setName);
System.out.println("==================獲取類的構(gòu)造器=====================");
//獲取所有public類型構(gòu)造器
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("獲取所有public類型構(gòu)造器:" + constructor);
}
//獲取所有構(gòu)造器
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println("獲取所有構(gòu)造器:" + constructor);
}
//獲取指定的構(gòu)造器
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, Integer.class);
System.out.println("獲取指定的構(gòu)造器:" + declaredConstructor);
}
}
結(jié)果如下

2. 動(dòng)態(tài)創(chuàng)建對(duì)象動(dòng)態(tài)操作方法及屬性
2.1 動(dòng)態(tài)創(chuàng)建對(duì)象
通過調(diào)用 Class 對(duì)象的 newInstance() 方法,可以創(chuàng)建類的對(duì)象
有了類的對(duì)象,就可以通過對(duì)象.方法名的形式使用方法了,這和平常的使用方式一樣,但需要注意設(shè)置的訪問權(quán)限問題
使用 Class 對(duì)象創(chuàng)建類的對(duì)象是需要條件的,不同情況下,條件不同
使用無參構(gòu)造器時(shí)的條件
- 無參構(gòu)造器存在
- 無參構(gòu)造器的訪問權(quán)限要足夠
//獲取Class對(duì)象
Class<?> aClass = Class.forName("com.javabasic.reflection.Person");
//通過一個(gè)無參構(gòu)造器創(chuàng)建一個(gè)Person的對(duì)象
Person person01 = (Person) aClass.newInstance();
System.out.println(person01);
使用有參構(gòu)造器時(shí)的條件
- 通過 Class 類的 getDeclaredConstructor(Class<?>… parameterTypes) 獲取當(dāng)前類的指定有參構(gòu)造器
- 向構(gòu)造器的形參中傳遞一個(gè)對(duì)象數(shù)組進(jìn)去,里面要包含構(gòu)造器中所需的各個(gè)參數(shù)
- 通過 Constructor 實(shí)例化對(duì)象
//獲取Class對(duì)象
Class<?> aClass = Class.forName("com.javabasic.reflection.Person");
//通過有參構(gòu)造器創(chuàng)建對(duì)象
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, Integer.class);
Person person02 = (Person) declaredConstructor.newInstance("張三", 20);
System.out.println(person02);
2.2 動(dòng)態(tài)操作方法及屬性
這里延用上面的 Person.java 類,然后新建一個(gè)測試類來測試
package com.javabasic.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @Description
* @ClassName Test01
* @Author yuhuofei
* @Date 2022/10/2 17:08
* @Version 1.0
*/
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//獲取Class對(duì)象
Class<?> aClass = Class.forName("com.javabasic.reflection.Person");
//通過一個(gè)無參構(gòu)造器創(chuàng)建一個(gè)Person的對(duì)象
Person person01 = (Person) aClass.newInstance();
System.out.println(person01);
//通過有參構(gòu)造器創(chuàng)建對(duì)象
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, Integer.class);
Person person02 = (Person) declaredConstructor.newInstance("張三", 20);
System.out.println(person02);
//通過反射調(diào)用普通方法
Method method = aClass.getDeclaredMethod("setName", String.class);
method.setAccessible(true); //關(guān)閉安全檢測,允許訪問private方法
Person person03 = (Person) aClass.newInstance();
method.invoke(person03, "李四"); //向person03對(duì)象中的setName方法傳參
System.out.println(person03);
//通過反射調(diào)用屬性
Field field01 = aClass.getDeclaredField("name");
Field field02 = aClass.getDeclaredField("age");
field01.setAccessible(true); //關(guān)閉安全檢測,允許訪問private屬性
field02.setAccessible(true);
Person person04 = (Person) aClass.newInstance();
field01.set(person04, "王五"); //設(shè)置名字
field02.set(person04, 19); //設(shè)置年齡
System.out.println(person04);
}
}
值得注意的是,如果方法或者屬性的訪問權(quán)限是 private,那么需要配置 .setAccessible(true);,不然無法訪問
3. 反射操作泛型
java 采用泛型擦除的機(jī)制來引入泛型,但卻只是給編譯器 javac 使用的,用于確保數(shù)據(jù)的安全性和免去強(qiáng)制類型轉(zhuǎn)換的問題,而一旦編譯完成,所有與泛型相關(guān)的類型會(huì)全部擦除
為了通過反射能操作這些類型,java 新增了 ParameterizedType、GenericArrayType、TypeVariable、WildcardType 這幾種類型來代表不能被歸一到 Class 類中的類型但又和原始類型齊名的類型
- ParameterizedType:表示一種參數(shù)化類型,比如 Collection< String >
- GenericArrayType:表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型
- TypeVariable:各種類型變量的公共父接口
- WildcardType :代表一種通配符類型表達(dá)式
下面寫一個(gè)類來實(shí)踐一下,這里還是延用前面的 Person 類
package com.javabasic.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* @Description 測試反射獲取泛型
* @ClassName Test02
* @Author yuhuofei
* @Date 2022/10/2 20:06
* @Version 1.0
*/
public class Test02 {
public void getData(Map<String, Person> map, List<Person> list) {
System.out.println("getData()");
}
public Map<String, Person> getMap() {
System.out.println("getMap()");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
//獲取入?yún)⒎盒?
Method method = Test02.class.getMethod("getData", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("泛型:" + genericParameterType);
//判斷拿到的是不是參數(shù)化類型,即是不是前面定義的Map或者List
if (genericParameterType instanceof ParameterizedType) {
//獲取真實(shí)參數(shù)
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
System.out.println("============分割線===========");
//獲取返回值泛型
method = Test02.class.getMethod("getMap", null);
Type genericReturnType = method.getGenericReturnType();
System.out.println("返回值類型:" + genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type at : actualTypeArguments) {
System.out.println(at);
}
}
}
}
得到的結(jié)果如下:

4. 反射操作注解
定義一個(gè)注解,如下:
package com.javabasic.annotation;
import java.lang.annotation.*;
/**
* @Description 自定義注解
* @InterfaceName MyAnnotation
* @Author yuhuofei
* @Date 2022/9/18 11:26
* @Version 1.0
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
/**
* 描述信息
*/
String value() default "";
}
定義一個(gè)使用上面的注解的類,如下:
package com.javabasic.annotation;
/**
* @Description 測試自定義注解的使用
* @ClassName TestAnnotation
* @Author yuhuofei
* @Date 2022/9/18 11:32
* @Version 1.0
*/
@MyAnnotation(value = "打印出兩個(gè)整數(shù)之和,這是標(biāo)記在類上的注解")
public class TestAnnotation {
@MyAnnotation(value = "打印出兩個(gè)整數(shù)之和,這是標(biāo)記在方法上的注解")
public static void printResult() {
int a = 39;
int b = 54;
int result = a + b;
System.out.println(result);
}
public static void main(String[] args) {
printResult();
}
}
定義一個(gè)測試類,測試通過反射操作注解,如下:
package com.javabasic.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* @Description 測試反射獲得注解
* @ClassName Test03
* @Author yuhuofei
* @Date 2022/10/2 20:36
* @Version 1.0
*/
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class c = Class.forName("com.javabasic.annotation.TestAnnotation");
//通過反射獲得注解
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//獲得注解的value
MyAnnotation annotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
String value = annotation.value();
System.out.println(value);
//獲得類中方法或者屬性上指定的注解
System.out.println("============分割線===========");
Method method = c.getMethod("printResult", null);
MyAnnotation an = method.getAnnotation(MyAnnotation.class);
System.out.println(an);
System.out.println(an.value());
}
}
運(yùn)行結(jié)果:

到此這篇關(guān)于Java中反射的應(yīng)用的文章就介紹到這了,更多相關(guān)Java反射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java class文件格式之屬性詳解_動(dòng)力節(jié)點(diǎn)java學(xué)院整理
這篇文章主要介紹了Java class文件格式之屬性詳解,需要的朋友可以參考下2017-06-06
Java 內(nèi)省(Introspector)深入理解
這篇文章主要介紹了Java 內(nèi)省(Introspector)深入理解的相關(guān)資料,需要的朋友可以參考下2017-03-03
SpringBoot為啥不用配置啟動(dòng)類的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot為啥不用配置啟動(dòng)類的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Spring4下validation數(shù)據(jù)校驗(yàn)無效(maven)的解決
這篇文章主要介紹了Spring4下validation數(shù)據(jù)校驗(yàn)無效(maven)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java調(diào)用opencv實(shí)現(xiàn)圖片矯正功能
這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用opencv實(shí)現(xiàn)圖片矯正功能,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-09-09
Spring boot詳解緩存redis實(shí)現(xiàn)定時(shí)過期方法
本篇文章分享的就是spring boot中的一個(gè)輪子,spring cache注解的方式實(shí)現(xiàn)接口數(shù)據(jù)緩存。默認(rèn)的配置想非常簡單,但是有一個(gè)弊端是緩存數(shù)據(jù)為永久緩存,本次將介紹如何設(shè)置接口緩存數(shù)據(jù)的過期時(shí)間2022-07-07
Java中數(shù)組與集合的相互轉(zhuǎn)換實(shí)現(xiàn)解析
這篇文章主要介紹了Java中數(shù)組與集合的相互轉(zhuǎn)換實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Java中JSONObject與JSONArray的使用區(qū)別詳解
這篇文章主要介紹了Java中JSONObject與JSONArray的使用區(qū)別詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11

