目錄
定義:
用途:
反射基本信息:
反射相關(guān)的類(important):
Class類(反射機制的起源 )
Class類中的相關(guān)方法:
常用獲得類相關(guān)的方法(重要)
常用獲得類中屬性相關(guān)的方法(重要)
獲得類中注解相關(guān)的方法(了解)
獲得類中構(gòu)造器相關(guān)的方法(重要)
獲得該類所有構(gòu)造方法(重要)
反射示例:
獲得Class對象的三種方式
反射的使用:
反射--創(chuàng)建對象
反射--調(diào)用私有的構(gòu)造方法
反射--私有屬性?
反射--私有方法
反射優(yōu)點和缺點 ?
優(yōu)點:
缺點:?
重點總結(jié):
結(jié)語:
定義:
Java的反射(re?ection)機制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意方法和屬性,既然能拿到那么,我們就可以修改部分類型信息;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為java語言的反射機制。
用途:
(1)在日常的第三方應(yīng)用開發(fā)過程中,經(jīng)常會遇到某個類的某個成員變量、方法或是屬性是私有的或是只對系統(tǒng)應(yīng)用開放,這時候就可以利用Java的反射機制通過反射來獲取所需的私有成員或是方法 。
(2)反射最重要的用途就是開發(fā)各種通用框架,比如在spring中,我們將所有的類Bean交給spring容器管理,無 論是XML配置Bean還是注解配置,當我們從容器中獲取Bean來依賴注入時,容器會讀取配置,而配置中給的 就是類的信息,spring根據(jù)這些信息,需要創(chuàng)建那些Bean,spring就動態(tài)的創(chuàng)建這些類。
反射基本信息:
Java程序中許多對象在運行時會出現(xiàn)兩種類型:運行時類型(RTTI)和編譯時類型,例如Person p = new Student();這句代碼中p在編譯時類型為Person,運行時類型為Student。程序需要在運行時發(fā)現(xiàn)對象和類的真實信息。而通過使用反射程序就能判斷出該對象和類屬于哪些類。
反射相關(guān)的類(important):
類名 | 用途 |
Class類 | 代表類的實體,在運行的Java應(yīng)用程序中表示類和接口 |
Field類 | 代表類的成員變量/類的屬性 |
Method類 | 代表類的方法 |
Constructor類 | 代表類的構(gòu)造方法 |
Class類(反射機制的起源 )
代表類的實體,在運行的Java應(yīng)用程序中表示類和接口. Class的官方文檔:Class文檔
Java文件被編譯后,生成了.class文件,JVM此時就要去解讀.class文件 ,被編譯后的Java文件.class也被JVM解析為一個對象,這個對象就是 java.lang.Class .這樣當程序在運行時,每個java文件就最終變成了Class類對象的一個實例。我們通過Java的反射機制應(yīng)用到這個實例,就可以去獲得甚至去添加改變這個類的屬性和動作,使得這個類成為一個動態(tài)的類 .(如果覺得抽象沒關(guān)系看下面演示后再看這個就明白了??????)
Class類中的相關(guān)方法:
常用獲得類相關(guān)的方法(重要)
方法 | 用途 |
getClassLoader() | 獲得類的加載器 |
getDeclaredClasses() | 返回一個數(shù)組,數(shù)組中包含該類中所有類和接口類的對象(包括私有的) |
forName(String className) | 根據(jù)類名返回類的對象 |
newInstance() | 創(chuàng)建類的實例 |
getName() | 獲得類的完整路徑名字 |
常用獲得類中屬性相關(guān)的方法(重要)
Field的官方文檔:Field官方文檔
方法 | 用途 |
getField(String name) | 獲得某個公有的屬性對象 |
getFields() | 獲得所有公有的屬性對象 |
getDeclaredField(String name) | 獲得某個屬性對象 |
getDeclaredFields() | 獲得所有屬性對象 |
獲得類中注解相關(guān)的方法(了解)
方法 | 用途 |
getAnnotation(Class annotationClass) | 返回該類中與參數(shù)類型匹配的公有注解對象 |
getAnnotations() | 返回該類所有的公有注解對象 |
getDeclaredAnnotation(Class annotationClass) | 返回該類中與參數(shù)類型匹配的所有注解對象 |
getDeclaredAnnotations() | 返回該類所有的注解對象 |
獲得類中構(gòu)造器相關(guān)的方法(重要)
Constructor的官方文檔:Constructor官方文檔
方法 | 用途 |
getConstructor(Class... parameterTypes) | 獲得該類中與參數(shù)類型匹配的公有構(gòu)造方法 |
getConstructors() | 獲得該類的所有公有構(gòu)造方法 |
getDeclaredConstructor(Class... parameterTypes) | 獲得該類中與參數(shù)類型匹配的構(gòu)造方法 |
getDeclaredConstructors() | 獲得該類所有構(gòu)造方法 |
獲得該類所有構(gòu)造方法(重要)
Method的官方文檔:Method官方文檔
方法 | 用途 |
getMethod(String name, Class... parameterTypes) | 獲得該類某個公有的方法 |
getMethods() | 獲得該類所有公有的方法 |
getDeclaredMethod(String name, Class... parameterTypes) | 獲得該類某個方法 |
getDeclaredMethods() | 獲得該類所有方法 |
反射示例:
獲得Class對象的三種方式
在反射之前,我們需要做的第一步就是先拿到當前需要反射的類的Class對象,然后通過Class對象的核心方法,達到反射的目的,即:在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象, 都能夠調(diào)用它的任意方法和屬性,既然能拿到那么,我們就可以修改部分類型信息??????。
第一種:
使用類對象的 getClass() 方法
第二種:
使用 .class 方法。 說明:僅適合在編譯前就已經(jīng)明確要操作的Class
第三種:
使用 Class.forName("類的全路徑名"); 靜態(tài)方法。 前提:已明確類的全路徑名。
注意這里是類的全路徑,如果有包需要加包的路徑例如(domo1.Student).
要聲明異常。
其中第三種使用的最多如果大家要記得話就記下第三種。
class Student{
public int age = 10;
private String name = "gobeyye";
}
public class Main {
public static void main(String[] args) {
Student s1 = new Student();
//第一種
Class c1= s1.getClass();
//第二種
Class c2 = Student.class;
//第三種
Class c3 = null;
try{
c3 = Class.forName("Student");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
System.out.println(c1 == c2);
System.out.println(c1 == c3);
System.out.println(c2 == c3);
}
}
上面的代碼運行結(jié)果如下:
都為true且在==的比較情況下,這說明:一個類在 JVM 中只會有一個 Class 實例。
反射的使用:
注意:所有和反射相關(guān)的包都在 import java.lang.re?ect 包下面。
我們主要運用反射來進行創(chuàng)建類的實例和調(diào)用被private修飾的構(gòu)造方法,方法和成員變量。
為了方便理解下面給出Student類的實現(xiàn)圖片??????。
反射--創(chuàng)建對象
具體創(chuàng)建過程如下,這個不用記憶有用到的時候查資料知道怎么用即可。
下面有些方法是上面表格給出的如果不太了解的話可以向上翻。
public static void reflectNewInstance(){
try{
Class<?> classStudent = Class.forName("Student");
Object objectStudent = classStudent.newInstance();
Student student = (Student)objectStudent;
System.out.println(student);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectNewInstance();
}
結(jié)果如下:可以發(fā)現(xiàn)我們成功通過反射創(chuàng)建了一個Student對象。?
不要怕拋了這么多異常,這個編譯器有快捷鍵的不需要我們自己寫。如下圖我們把鼠標放到報錯處等彈出如下界面是按下Alt + Shift + Enter鍵即可快速catch異常。
反射--調(diào)用私有的構(gòu)造方法
具體過程如下:
和上面一樣看著異常很多我們可以直接使用快捷鍵快速完成,不用記憶這個一般都是在項目里面才會用到,比賽不會有這些東西考試大概率也不會。
eclaredConstructorStudent.setAccessible(true);
這個代碼在后續(xù)演示中會經(jīng)常看到因為基本上用到private修飾的東西要用反射來調(diào)用的話都要把它設(shè)置為true這個方法可以查閱方法庫雙擊shift即可查看。
至于
String.class,int.class
后面為什么要加.class這是語法規(guī)定。
public static void reflectPrivateConstructor(){
try{
Class<?> classStudent = Class.forName("Student");
Constructor<?> declaredConstructorStudent = classStudent.getDeclaredConstructor(String.class,int.class);
declaredConstructorStudent.setAccessible(true);
Object objectStudent = declaredConstructorStudent.newInstance("go",20);
Student student = (Student)objectStudent;
System.out.println(student);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectPrivateConstructor();
}
結(jié)果如下:上面這所以會打印Student(String,name)可以看看我前面給出的Student類的圖,加上這個是為了證明private的帶參數(shù)的構(gòu)造方法被成功調(diào)用,顯然可以被調(diào)用??????。
反射--私有屬性?
改變被private修飾的成員變量的值。
后續(xù)在私有屬性這里會經(jīng)常調(diào)用到set方法,為了防止友友們疑惑這里聲明這個set是人家自帶的。
?具體演示如下:
classStudent.getDeclaredField("name");
傳入要設(shè)置成員變量的標識符。
public static void reflectPrivateField(){
try{
Student student = new Student();
Class<?> classStudent = Class.forName("Student");
Field field = classStudent.getDeclaredField("name");
field.setAccessible(true);
field.set(student,"gobey");
System.out.println(student);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectPrivateField();
}
結(jié)果如下:
可以發(fā)現(xiàn)在用println打印student時我們name成員變量的值成功被修改??????。
反射--私有方法
具體演示如下:
在這個方法中我們第一個參數(shù)傳入的是我們要調(diào)用的方法名稱,后面的參數(shù)是我們方法的參數(shù),由于我們function方法只有一個String參數(shù)故我們傳入一個String類型即可但是一定要記得后面要加一個.class后綴這是語法。?
invoke就是用來調(diào)用對應(yīng)方法的。對應(yīng)源碼如下圖:
代碼如下:?
public static void reflectPrivateMethod(){
try{
Class<?> classStudent = Class.forName("Student");
Method methodStudent = classStudent.getDeclaredMethod("function", String.class);
methodStudent.setAccessible(true);
Object objectStudent = classStudent.newInstance();
Student student = (Student)objectStudent;
methodStudent.invoke(student,"hehehehe");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
reflectPrivateMethod();
}
?對應(yīng)結(jié)果如下:可以看到被private修飾的方法成功被調(diào)用。
到這里我們反射常用的四個方式已經(jīng)全部演示完畢,希望友友們自己可以試著實現(xiàn)一下,這個不是很難的??????。?
反射優(yōu)點和缺點 ?
優(yōu)點:
1. 對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法。
2. 增加程序的靈活性和擴展性,降低耦合性,提高自適應(yīng)能力。
3. 反射已經(jīng)運用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺點:?
1. 使用反射會有效率問題。會導(dǎo)致程序效率降低。
2. 反射技術(shù)繞過了源代碼的技術(shù),因而會帶來維護問題。反射代碼比相應(yīng)的直接代碼更復(fù)雜 。
重點總結(jié):
1. 反射的意義。
2. 反射重要的幾個類: Class類 、Field類、 Method類、 Constructor類。
3. 學(xué)會合理利用反射,一定要在安全環(huán)境下使用。
結(jié)語:
其實寫博客不僅僅是為了教大家,同時這也有利于我鞏固知識點,和做一個學(xué)習(xí)的總結(jié),由于作者水平有限,對文章有任何問題還請指出,非常感謝。如果大家有所收獲的話還請不要吝嗇你們的點贊收藏和關(guān)注,這可以激勵我寫出更加優(yōu)秀的文章。文章來源:http://www.zghlxwxcb.cn/news/detail-853490.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-853490.html
到了這里,關(guān)于【詳解】Java反射機制(打穿封裝)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!