目錄
前言:
?反射:
?使用反射的步驟:
1.獲取階段:
2.使用階段:
反射的應(yīng)用場(chǎng)景:
使用反射的優(yōu)缺點(diǎn):
總結(jié):
前言:
Java中的反射是一項(xiàng)強(qiáng)大而靈活的功能,它允許程序在運(yùn)行時(shí)動(dòng)態(tài)地獲取、操作和利用類的信息。通過(guò)反射,我們可以在運(yùn)行時(shí)檢查和修改類的屬性、調(diào)用類的方法,甚至創(chuàng)建和操作對(duì)象實(shí)例。這種能力為Java提供了很多靈活性和擴(kuò)展性,使得我們能夠編寫更加通用、可插拔和動(dòng)態(tài)的代碼。然而,反射也是一種高級(jí)特性,需要謹(jǐn)慎使用,因?yàn)樗赡軤奚艘恍┬阅芎皖愋桶踩?。在本文中,我們將深入探究Java反射的原理、用法和最佳實(shí)踐。
反射:
????????????????反射是一種在運(yùn)行時(shí)動(dòng)態(tài)獲取、檢查和操作類的信息的能力。它允許程序在運(yùn)行時(shí)通過(guò)類的名稱獲取其完整結(jié)構(gòu),并可以實(shí)例化對(duì)象、調(diào)用方法、訪問(wèn)屬性和執(zhí)行其他與類相關(guān)的操作,而無(wú)需在編譯時(shí)明確引用這些類。反射的核心是java.lang.reflect包,它提供了一組類和接口,用于實(shí)現(xiàn)反射功能。使用反射,可以實(shí)現(xiàn)一些靈活和通用的編程技術(shù),如動(dòng)態(tài)加載類、配置文件解析、框架擴(kuò)展和代碼生成。然而,反射也會(huì)帶來(lái)性能上的開銷,并且破壞了編譯時(shí)類型檢查,因此在使用時(shí)需要注意適度和合理性。
也就是說(shuō):反射可以把類中的成員變量,成員方法和構(gòu)造方法單獨(dú)拿出來(lái)進(jìn)行訪問(wèn),我們是否會(huì)好奇我們自定義類之后,idea為什么會(huì)有提示功能?
其實(shí)這就是通過(guò)反射來(lái)實(shí)現(xiàn)的。?
?使用反射的步驟:
1.獲取階段:
在獲取階段,我們使用反射機(jī)制來(lái)獲取與類、方法、字段等相關(guān)的信息。這包括獲取類的Class對(duì)象、構(gòu)造方法、方法、字段等,并可以檢查類的繼承關(guān)系、接口實(shí)現(xiàn)以及注解等元數(shù)據(jù)信息。獲取階段提供了對(duì)類結(jié)構(gòu)的探索和解析的能力,讓我們能夠動(dòng)態(tài)地獲取類的結(jié)構(gòu)信息。
(1)利用反射獲取class對(duì)象
public class test01 {
public static void main(String[] args) throws ClassNotFoundException {
//獲取class文件:
//第一種
Class<?> aClass = Class.forName("Myrflect.student");
System.out.println(aClass);
//第二種:
Class<student> studentClass = student.class;
System.out.println(studentClass);
//第三種:
student st = new student();
Class<? extends student> aClass1 = st.getClass();
System.out.println(aClass1);
}
}
(2)利用反射獲得構(gòu)造方法
public class getcontrbute {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//1.獲取字節(jié)碼文件對(duì)象
Class<?> aClass = Class.forName("Myrflect.student");
//1.獲取公共的構(gòu)造方法:
Constructor<?>[] constructors = aClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("-------------------------");
//2.獲取私有的構(gòu)造方法
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> cons : declaredConstructors) {
System.out.println(cons);
}
System.out.println("-------------------------");
//3.獲取單個(gè)的構(gòu)造方法
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
System.out.println(declaredConstructor);
Constructor<?> declaredConstructor1 = aClass.getDeclaredConstructor(String.class,int.class,String.class);
System.out.println(declaredConstructor1);
}
}
(3)反射獲取成員變量
public class getmember {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
//1.獲取Class字節(jié)碼文件對(duì)象
Class<?> aClass = Class.forName("Myrflect.student");
//1.獲取所有公告成員變量對(duì)象的數(shù)組
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------------");
//2.獲取所有成員變量對(duì)象的數(shù)組
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
System.out.println("---------------");
//3.獲取單個(gè)成員變量
Field name = aClass.getField("name");
System.out.println(name);
}
}
?(4)反射獲取成員方法
public class getway {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class<?> aClass = Class.forName("Myrflect.student");
//1.獲取所有公共方法對(duì)象(包含父類,而每一個(gè)類都繼承Object類,因此打印會(huì)出現(xiàn)很多方法)
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("-----------------------------");
//2.獲取所有方法對(duì)象(不包含父類)
Method[] declaredMethods = aClass.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
System.out.println("-----------------------------");
//3.獲取單個(gè)方法
Method method = aClass.getMethod("getAge");
System.out.println(method);
}
}
2.使用階段:
在獲取了類的結(jié)構(gòu)信息后,我們可以使用反射機(jī)制來(lái)動(dòng)態(tài)地實(shí)例化對(duì)象、調(diào)用方法、訪問(wèn)字段等操作。使用階段利用獲取階段得到的信息,通過(guò)反射來(lái)操作類的成員,實(shí)現(xiàn)靈活、通用和動(dòng)態(tài)的功能。使用階段可以根據(jù)實(shí)際需求來(lái)動(dòng)態(tài)地操作類的成員,而無(wú)需在編譯時(shí)提前確定具體的類和成員。
public class ReflectionExample {
public static void main(String[] args) {
try {
// 讀取和寫入字段
MyClass obj = new MyClass();
Class<?> clazz = obj.getClass();
// 獲取公共字段
Field publicField = clazz.getField("publicField");
System.out.println("Public Field Initial Value: " + publicField.get(obj));
// 設(shè)置字段的值
publicField.set(obj, "New Value");
System.out.println("Public Field Updated Value: " + publicField.get(obj));
// 獲取私有字段
Field privateField = clazz.getDeclaredField("privateField");
privateField.setAccessible(true); // 設(shè)置私有字段可訪問(wèn)
System.out.println("Private Field Initial Value: " + privateField.get(obj));
// 設(shè)置私有字段的值
privateField.set(obj, 123);
System.out.println("Private Field Updated Value: " + privateField.get(obj));
// 調(diào)用方法
Method method = clazz.getMethod("publicMethod");
method.invoke(obj); // 執(zhí)行公共方法
// 創(chuàng)建對(duì)象
Constructor<?> constructor = clazz.getConstructor();
Object newObj = constructor.newInstance();
System.out.println("New Object: " + newObj);
} catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}
}
反射還提供了許多其他功能,如獲取類的構(gòu)造方法、接口、父類,獲取注解信息等。
需要注意的是,使用反射時(shí)要注意權(quán)限的限制(如私有成員的訪問(wèn))以及性能問(wèn)題(反射操作比直接調(diào)用性能較差)。另外,運(yùn)用反射應(yīng)盡量遵循設(shè)計(jì)原則,避免濫用反射,保證代碼的可讀性和可維護(hù)性。
反射的應(yīng)用場(chǎng)景:
-
框架開發(fā):反射常被用于框架的開發(fā),通過(guò)讀取配置文件或注解來(lái)動(dòng)態(tài)地加載類、創(chuàng)建對(duì)象、調(diào)用方法和訪問(wèn)字段,從而實(shí)現(xiàn)靈活可擴(kuò)展的框架結(jié)構(gòu)。
-
對(duì)象實(shí)例化:通過(guò)反射可以實(shí)現(xiàn)動(dòng)態(tài)地創(chuàng)建對(duì)象實(shí)例。通過(guò)類的
Constructor
對(duì)象可以調(diào)用不同的構(gòu)造方法,為對(duì)象傳遞不同的參數(shù),從而根據(jù)需要來(lái)創(chuàng)建對(duì)象。 -
調(diào)用方法和訪問(wèn)字段:反射可以用于調(diào)用類的方法和訪問(wèn)類的字段。通過(guò)方法的
Method
對(duì)象可以調(diào)用類的不同方法,通過(guò)字段的Field
對(duì)象可以讀取和寫入類的字段值。 -
探索類的信息:通過(guò)反射可以獲取類的詳細(xì)信息,如類名、父類、接口、方法和字段等。這對(duì)于編寫通用的代碼和進(jìn)行類似于文檔生成、序列化和驗(yàn)證等操作非常有用。
-
動(dòng)態(tài)代理:反射在實(shí)現(xiàn)動(dòng)態(tài)代理時(shí)發(fā)揮了重要作用。通過(guò)反射可以動(dòng)態(tài)地生成代理類,并在代理類的方法調(diào)用中添加額外的邏輯,如日志記錄、權(quán)限驗(yàn)證等。
-
單元測(cè)試:反射可以用于編寫單元測(cè)試時(shí)的Mock對(duì)象。通過(guò)反射可以創(chuàng)建假對(duì)象并模擬實(shí)際對(duì)象的行為,從而進(jìn)行更全面的單元測(cè)試。
使用反射的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
-
動(dòng)態(tài)性:反射提供了在運(yùn)行時(shí)動(dòng)態(tài)獲取和操作類的能力??梢詣?dòng)態(tài)地創(chuàng)建對(duì)象、調(diào)用方法和訪問(wèn)字段,這使得代碼更具靈活性和可擴(kuò)展性。
-
通用性:通過(guò)反射可以編寫通用的代碼,不依賴于具體的類和接口。可以在不了解類結(jié)構(gòu)的情況下獲取類的信息,并根據(jù)需要來(lái)操作類的成員。
-
框架支持:反射被廣泛應(yīng)用于框架的開發(fā),框架可以通過(guò)讀取配置文件或注解來(lái)動(dòng)態(tài)加載類和創(chuàng)建對(duì)象,從而實(shí)現(xiàn)靈活可配置的框架結(jié)構(gòu)。
-
靈活性:反射使得可以在運(yùn)行時(shí)根據(jù)條件來(lái)動(dòng)態(tài)地選擇和執(zhí)行代碼,而不是在編譯時(shí)進(jìn)行靜態(tài)綁定。這在某些特定的業(yè)務(wù)場(chǎng)景下非常有用。例如,根據(jù)配置文件動(dòng)態(tài)選擇不同的實(shí)現(xiàn)類。
缺點(diǎn):
-
性能開銷:反射通常比直接調(diào)用代碼要慢,因?yàn)樗枰M(jìn)行額外的查找、檢查和調(diào)用。反射調(diào)用的性能開銷相對(duì)較高,可能對(duì)性能敏感的應(yīng)用程序需要謹(jǐn)慎使用。
-
安全性問(wèn)題:使用反射可以繞過(guò)類的訪問(wèn)控制和安全檢查機(jī)制,這可能導(dǎo)致安全漏洞。因此,在使用反射時(shí),需要保證代碼的安全性,并確保只有受信任的代碼可以訪問(wèn)敏感操作。
-
編譯器檢查缺失:反射可以讓代碼更加動(dòng)態(tài),但也會(huì)失去編譯器在代碼編譯階段進(jìn)行錯(cuò)誤檢查的能力。一些錯(cuò)誤可能在運(yùn)行時(shí)才能被發(fā)現(xiàn),增加了調(diào)試的困難性。
總結(jié):
反射是Java中的一項(xiàng)強(qiáng)大功能,通過(guò)它我們可以在運(yùn)行時(shí)動(dòng)態(tài)地獲取和操作類的成員。使用反射可以實(shí)現(xiàn)靈活性、通用性和動(dòng)態(tài)性,提供了諸如創(chuàng)建對(duì)象、調(diào)用方法和訪問(wèn)字段等功能。然而,反射也有一些缺點(diǎn),如性能開銷和安全性問(wèn)題。因此,在使用反射時(shí)需要權(quán)衡利弊,確保使用安全可靠,并遵循最佳實(shí)踐。總之,反射為Java程序提供了更大的靈活性和擴(kuò)展性,使代碼編寫更加通用且適應(yīng)動(dòng)態(tài)變化的需求。
如果我的內(nèi)容對(duì)你有幫助,請(qǐng)點(diǎn)贊,評(píng)論,收藏。創(chuàng)作不易,大家的支持就是我堅(jiān)持下去的動(dòng)力!
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-642333.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-642333.html
到了這里,關(guān)于【從零開始學(xué)習(xí)JAVA | 第四十五篇】反射的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!