JAVA之反射機(jī)制Reflection的使用
反射機(jī)制Reflection
1、靜態(tài) VS 動(dòng)態(tài)語(yǔ)言
動(dòng)態(tài)語(yǔ)言是一類在運(yùn)行時(shí)可以改變其結(jié)構(gòu)的語(yǔ)言:例如新的函數(shù)、對(duì)象、甚至代碼可以被引進(jìn),已有的函數(shù)可以被刪除或是其他結(jié)構(gòu)上的變化。通俗點(diǎn)說(shuō)就是在運(yùn)行時(shí)代碼可以根據(jù)某些條件改變自身結(jié)構(gòu)。
主要?jiǎng)討B(tài)語(yǔ)言:Object-C、C#、JavaScript、PHP、Python等
//體現(xiàn)動(dòng)態(tài)語(yǔ)言的代碼
function test() {
var x = "var a=3;var b=5;alert(a+b)";
eval(x);
}靜態(tài)語(yǔ)言與動(dòng)態(tài)語(yǔ)言相對(duì)應(yīng)的,運(yùn)行時(shí)結(jié)構(gòu)不可變的語(yǔ)言就是靜態(tài)語(yǔ)言。如Java、C、C++。
Java不是動(dòng)態(tài)語(yǔ)言,但Java可以稱之為“準(zhǔn)動(dòng)態(tài)語(yǔ)言”。即Java有一定的動(dòng)態(tài)性,我們可以利用反射機(jī)制獲得類似動(dòng)態(tài)語(yǔ)言的特性。Java的動(dòng)態(tài)性讓編程的時(shí)候更加靈活!
2、Java Reflection
Reflection(反射)是Java被視為動(dòng)態(tài)語(yǔ)言的關(guān)鍵,反射機(jī)制允許程序在執(zhí)行期借助于Reflection API取得任何類的內(nèi)部信息,并能直接操作任意對(duì)象的內(nèi)部屬性及方法。
Class c = Class.forName("java.lang.String")加載完類之后,在堆內(nèi)存的方法區(qū)中就產(chǎn)生了一個(gè)Class類型的對(duì)象(一個(gè)類只有一個(gè)Class對(duì)象),這個(gè)對(duì)象就包含了完整的類的結(jié)構(gòu)信息。我們可以通過(guò)這個(gè)對(duì)象看到類的結(jié)構(gòu)。
這個(gè)對(duì)象就像一面鏡子,透過(guò)這個(gè)鏡子看到類的結(jié)構(gòu),所以,我們形象的稱之為:反射

package com.reflection;
public class Test2 {
public static void main(String[] args) {
try {
//通過(guò)反射獲取類的Class
//--->查看JDK幫助文檔
Class<?> c1 = Class.forName("com.reflection.User");
//一個(gè)類被加載后 , 類的整個(gè)結(jié)構(gòu)信息會(huì)被放到對(duì)應(yīng)的Class對(duì)象中
System.out.println(c1);
//一個(gè)類只對(duì)應(yīng)一個(gè)Class對(duì)象
Class<?> c2 = Class.forName("com.reflection.User");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//1. 創(chuàng)建一個(gè)實(shí)體類
class User{
private int id;
private int age;
private String name;
public User() {
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name=" + name +
'}';
}
}Java反射機(jī)制提供的功能:
- 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類
- 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象
- 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法
- 在運(yùn)行時(shí)獲取泛型信息
- 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的成員變量和方法
- 在運(yùn)行時(shí)處理注解
- 生成動(dòng)態(tài)代理
Java反射優(yōu)點(diǎn)和缺點(diǎn):
- 優(yōu)點(diǎn):可以實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建對(duì)象和編譯,體現(xiàn)出很大的靈活性 !
- 缺點(diǎn):對(duì)性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿
- 足我們的要求。這類操作總是慢于 直接執(zhí)行相同的操作。
3、反射相關(guān)的主要API
- java.lang.Class : 代表一個(gè)類
- java.lang.reflect.Method : 代表類的方法
- java.lang.reflect.Field : 代表類的成員變量
- java.lang.reflect.Constructor : 代表類的構(gòu)造器
4、Class類
在Object類中定義了該方法,此方法將被所有子類繼承
public final Class getClass();
以上的方法返回值的類型是一個(gè)Class類,此類是Java反射的源頭,實(shí)際上所謂反射從程序的運(yùn)行結(jié)果來(lái)看也很好理解,即:可以通過(guò)對(duì)象反射求出類的名稱。
對(duì)象照鏡子后可以得到的信息:某個(gè)類的屬性、方法和構(gòu)造器、某個(gè)類到底實(shí)現(xiàn)了哪些接口。
對(duì)于每個(gè)類而言,JRE 都為其保留一個(gè)不變的 Class 類型的對(duì)象。一個(gè) Class 對(duì)象包含了特定某個(gè)結(jié)構(gòu)(class/interface/enum/annotation/primitive type/void/[])的有關(guān)信息。
- Class 本身也是一個(gè)類
- Class 對(duì)象只能由系統(tǒng)建立對(duì)象
- 一個(gè)加載的類在 JVM 中只會(huì)有一個(gè)Class實(shí)例
- 一個(gè)Class對(duì)象對(duì)應(yīng)的是一個(gè)加載到JVM中的一個(gè).class文件
- 每個(gè)類的實(shí)例都會(huì)記得自己是由哪個(gè) Class 實(shí)例所生成
- 通過(guò)Class可以完整地得到一個(gè)類中的所有被加載的結(jié)構(gòu)
- Class類是Reflection的根源,針對(duì)任何你想動(dòng)態(tài)加載、運(yùn)行的類,唯有先獲得相應(yīng)的Class對(duì)象
package com.reflection;
//測(cè)試各種類型獲得Class對(duì)象的方式
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Student();
System.out.println("這個(gè)人是:"+person.name);
//獲得class辦法一:通過(guò)對(duì)象獲得
Class clazz1 = person.getClass();
//獲得class辦法二:通過(guò)字符串獲得(包名+類名)
Class clazz2 = Class.forName("com.reflection.Student");
//獲得class辦法三:通過(guò)類的靜態(tài)成員class獲得
Class clazz3 = Person.class;
//獲得class辦法四:只針對(duì)內(nèi)置的基本數(shù)據(jù)類型
Class clazz4 = Integer.TYPE;
//獲得父類類型
Class clazz5 = clazz2.getSuperclass();
System.out.println(clazz1);
System.out.println(clazz2);
System.out.println(clazz3);
System.out.println(clazz4);
System.out.println(clazz5);
}
}
class Person {
public String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name = "學(xué)生";
}
}
class Teacher extends Person{
public Teacher(){
this.name = "老師";
}
}
5、Java內(nèi)存分析

6、創(chuàng)建運(yùn)行時(shí)類的對(duì)象
- 通過(guò)反射獲取運(yùn)行時(shí)類的完整結(jié)構(gòu)
- Field、Method、Constructor、Superclass、Interface、Annotation
- 實(shí)現(xiàn)的全部接口
- 所繼承的父類
- 全部的構(gòu)造器
- 全部的方法
- 全部的Field
- 注解
小結(jié)
- 在實(shí)際的操作中,取得類的信息的操作代碼,并不會(huì)經(jīng)常開發(fā)。
- 一定要熟悉java.lang.reflect包的作用,反射機(jī)制。
7、有了Class對(duì)象,能做什么?
創(chuàng)建類的對(duì)象:調(diào)用Class對(duì)象的newInstance()方法
- 類必須有一個(gè)無(wú)參數(shù)的構(gòu)造器。
- 類的構(gòu)造器的訪問(wèn)權(quán)限需要足夠
思考?難道沒有無(wú)參的構(gòu)造器就不能創(chuàng)建對(duì)象了嗎?只要在操作的時(shí)候明確的調(diào)用類中的構(gòu)造器,并將參數(shù)傳遞進(jìn)去之后,才可以實(shí)例化操作。
步驟如下:
- 通過(guò)Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構(gòu)造器
- 向構(gòu)造器的形參中傳遞一個(gè)對(duì)象數(shù)組進(jìn)去,里面包含了構(gòu)造器中所需的各個(gè)參數(shù)。
- 通過(guò)Constructor實(shí)例化對(duì)象
調(diào)用指定的方法:
- 通過(guò)反射,調(diào)用類中的方法,通過(guò)Method類完成。
- 通過(guò)Class類的getMethod(String name,Class…parameterTypes)方法取得一個(gè)Method對(duì)象,并設(shè)置此方法操作時(shí)所需要的參數(shù)類型。
- 之后使用Object invoke(Object obj, Object[] args)進(jìn)行調(diào)用,并向方法中傳遞要設(shè)置的obj對(duì)象的參數(shù)信息。

8、setAccessible
- Method和Field、Constructor對(duì)象都有setAccessible()方法。
- setAccessible作用是啟動(dòng)和禁用訪問(wèn)安全檢查的開關(guān)。
- 參數(shù)值為true則指示反射的對(duì)象在使用時(shí)應(yīng)該取消Java語(yǔ)言訪問(wèn)檢查。
- 提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調(diào)用,那么請(qǐng)?jiān)O(shè)置為true。
- 使得原本無(wú)法訪問(wèn)的私有成員也可以訪問(wèn)
- 參數(shù)值為false則指示反射的對(duì)象應(yīng)該實(shí)施Java語(yǔ)言訪問(wèn)檢查
9、反射操作泛型
Java采用泛型擦除的機(jī)制來(lái)引入泛型 , Java中的泛型僅僅是給編譯器javac使用的,確保數(shù)據(jù)的安全性 和免去強(qiáng)制類型轉(zhuǎn)換問(wèn)題 , 但是 , 一旦編譯完成 , 所有和泛型有關(guān)的類型全部擦除 為了通過(guò)反射操作這些類型 , Java新增了 ParameterizedType , GenericArrayType , TypeVariable 和 WildcardType 幾種類型來(lái)代表不能被歸一到Class類中的類型但是又和原始類型齊名的類型.
ParameterizedType: 表示一種參數(shù)化類型,比如CollectionGenericArrayType: 表示一種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型TypeVariable: 是各種類型變量的公共父接口WildcardType: 代表一種通配符類型表達(dá)式
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
為什么 Java 8 中不需要 StringBuilder 拼接字符串
java8中,編輯器對(duì)“+”進(jìn)行了優(yōu)化,默認(rèn)使用StringBuilder進(jìn)行拼接,所以不用顯示的使用StringBuilder了,直接用“+”就可以了。下面我們來(lái)詳細(xì)了解一下2019-05-05
SpringBoot集成RedisTemplate的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot集成RedisTemplate的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-09-09
如何使用lamda表達(dá)式對(duì)list進(jìn)行求和
這篇文章主要介紹了如何使用lamda表達(dá)式對(duì)list進(jìn)行求和問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Java創(chuàng)建型設(shè)計(jì)模式之抽象工廠模式(Abstract?Factory)
當(dāng)系統(tǒng)所提供的工廠所需生產(chǎn)的具體產(chǎn)品并不是一個(gè)簡(jiǎn)單的對(duì)象,而是多個(gè)位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中屬于不同類型的具體產(chǎn)品時(shí)需要使用抽象工廠模式,抽象工廠模式是所有形式的工廠模式中最為抽象和最具一般性的一種形態(tài)2022-09-09
SpringBoot集成PDFBox實(shí)現(xiàn)電子簽章的代碼詳解
Apache PDFBox 是一個(gè)開源的 Java 庫(kù),用于處理 PDF 文檔,它提供了一系列強(qiáng)大的功能,包括創(chuàng)建、渲染、拆分、合并、加密、解密 PDF 文件,以及從 PDF 中提取文本和元數(shù)據(jù)等,本文給大家介紹了SpringBoot集成PDFBox實(shí)現(xiàn)電子簽章,需要的朋友可以參考下2024-09-09
SpringBoot啟動(dòng)時(shí)執(zhí)行初始化操作的幾種方式
項(xiàng)目中,經(jīng)常需要在啟動(dòng)過(guò)程中初始化一些數(shù)據(jù),如從數(shù)據(jù)庫(kù)讀取一些配置初始化,或從數(shù)據(jù)庫(kù)讀取一些熱點(diǎn)數(shù)據(jù)到redis進(jìn)行初始化緩存,本文給大家介紹了SpringBoot啟動(dòng)時(shí)執(zhí)行初始化操作的幾種方式的相關(guān)資料,需要的朋友可以參考下2024-05-05
java程序設(shè)計(jì)語(yǔ)言的優(yōu)勢(shì)及特點(diǎn)
在本篇文章里小編給大家分享的是一篇關(guān)于java程序設(shè)計(jì)語(yǔ)言的優(yōu)勢(shì)及特點(diǎn)的內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。2020-02-02
SpringBoot獲取配置文件中的配置項(xiàng)的常用方式
這篇文章主要介紹了SpringBoot獲取配置文件中的配置項(xiàng)的常用方式,并通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-11-11

