Java中的反射機制示例詳解
反射
反射就是把Java類中的各個成分映射成一個個的Java對象。即在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所以屬性和方法;對于任意一個對象,都能調(diào)用它的任意一個方法和屬性。這種動態(tài)獲取信息及動態(tài)調(diào)用對象方法的功能叫Java的反射機制
每一個Java程序執(zhí)行必須通過編譯、加載、鏈接和初始化四個階段
1.編譯:將.java.文件編譯成字節(jié)碼.class文件
2.加載:查找并加載類的二進制數(shù)據(jù)
3.鏈接:
- 驗證:確保被加載類的正確性
- 為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認值
- 將類中的符號轉(zhuǎn)換為直接引用
4.初始化:為類的靜態(tài)變量賦予正確的初始值
什么是Class類
在Java中,每個class都有一個相應的Class對象。也就是說,當我們編寫一個類,編譯完成后,在生成的.class文件中,就會產(chǎn)生一個Class對象,用于表示這個類的類型信息
也就是說,無論你是什么對象,總會有有一個隱藏的Class對象與你相對應,而Class的實例表示正在運行的 Java 應用程序中的類和接口。借此,實現(xiàn)了我們Java的反射機制。
獲取Class實例的三種方式
實例化對象調(diào)用getClass()方法
使用Class類的靜態(tài)方法forName(),用類的名字獲取一個Class實例
運用.class的方式來獲取Class實例,對于基本數(shù)據(jù)類型的封裝類,還可以采用.TYPE來獲取相對應的基本數(shù)據(jù)類型的Class實例
用代碼來看一看:
public class reflect {
public static void main(String[] args) throws ClassNotFoundException {
Apple apple = new Apple();
// 使用對象的getClass()方法
Class a1 = apple.getClass();
// 使用Class類的靜態(tài)方法forName()
Class a2 = Class.forName("p1.apple");
// 運用.class的方式來獲取Class實例
Class a3 = Apple.class;
System.out.printf("a1: %s\na2: %s\na3: %s", a1, a2, a3);
}
}
class Apple {
private Integer weight;
private String color;
}
打印結果:
a1: class p1.apple
a2: class p1.apple
a3: class p1.apple
進程已結束,退出代碼0
通過反射創(chuàng)建類對象
通過反射創(chuàng)建類對象主要有兩種方式:通過 Class 對象的 newInstance() 方法、通過 Constructor 對象的 newInstance() 方法。
public class reflect {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 通過 Class 對象的 newInstance() 方法
Class temp1 = Apple.class;
Apple apple1 = (Apple) temp1.newInstance();
// 通過 Constructor 對象的 newInstance() 方法
Class temp2 = Apple.class;
Constructor constructor1 = temp2.getConstructor();
Apple apple2 = (Apple)constructor1.newInstance();
// 通過 Constructor 對象創(chuàng)建類對象可以選擇特定構造方法,而通過 Class 對象則只能使用默認的無參數(shù)構造方法。
Class temp3 = Apple.class;
Constructor constructor2 = temp3.getConstructor(Integer.class,String.class);
Apple apple = (Apple)constructor2.newInstance(2, "Red");
System.out.println(apple);
}
}
class Apple {
private Integer weight;
private String color;
// 無參構造器
public Apple() {
System.out.println("我是無參構造!");
}
// 有參構造器
public Apple(Integer weight,String color) {
this.weight = weight;
this.color = color;
}
// 重寫方法 方便打印顯示對象內(nèi)容
@Override
public String toString() {
return "Apple{" +
"weight=" + weight +
", color='" + color + '\'' +
'}';
}
}
打印結果:
我是無參構造!
我是無參構造!
Apple{weight=2, color='Red'}
進程已結束,退出代碼0
通過反射獲取類屬性、方法、構造器
public class reflect {
public static void main(String[] args) throws NoSuchFieldException {
// 返回一個類中所有可訪問的公共字段,包括該類的公共字段和其繼承的類的公共字段
Field[] fields1 = Apple.class.getFields();
System.out.println("getFields結果");
Arrays.stream(fields1).forEach(System.out::println);
// 返回一個類中全部字段,但只包括該類的字段
Field[] fields2 = Apple.class.getDeclaredFields();
System.out.println("getDeclaredFields結果");
Arrays.stream(fields2).forEach(System.out::println);
// 根據(jù)字段名返回一個公開字段
Field field1 = Apple.class.getField("noThing");
System.out.println("getField結果");
System.out.println(field1);
// 根據(jù)字段名返回一個字段
Field field2 = Apple.class.getDeclaredField("color");
System.out.println("getDeclaredField結果");
System.out.println(field2);
// 同F(xiàn)ield Method也有四種獲取方式
// 這里舉其中一個例子
Method[] methods = Apple.class.getDeclaredMethods();
System.out.println("getDeclaredMethods結果");
Arrays.stream(methods).forEach(System.out::println);
// 同上 舉一個獲取構造器的例子
Constructor[] constructors = Apple.class.getDeclaredConstructors();
System.out.println("getDeclaredConstructors結果");
Arrays.stream(constructors).forEach(System.out::println);
}
}
class Apple {
private Integer weight;
private String color;
public String noThing;
public Apple() {
}
public Apple(Integer weight, String color) {
this.weight = weight;
this.color = color;
}
@Override
public String toString() {
return "Apple{" +
"weight=" + weight +
", color='" + color + '\'' +
'}';
}
}
打印結果:
getFields結果
public java.lang.String p1.Apple.noThing
getDeclaredFields結果
private java.lang.Integer p1.Apple.weight
private java.lang.String p1.Apple.color
public java.lang.String p1.Apple.noThing
getField結果
public java.lang.String p1.Apple.noThing
getDeclaredField結果
private java.lang.String p1.Apple.color
getDeclaredMethods結果
public java.lang.String p1.Apple.toString()
getDeclaredConstructors結果
public p1.Apple()
public p1.Apple(java.lang.Integer,java.lang.String)
更改訪問權限和實例賦值
首先,通過field.setAccessible()可更改屬性的訪問權限

public class reflect {
public static void main(String[] args) throws NoSuchFieldException {
// 實例化一個Apple
Apple apple = new Apple();
// 獲取所有字段 并統(tǒng)一設定為公有屬性
Field[] fields = Apple.class.getDeclaredFields();
Arrays.stream(fields).forEach( field -> {
field.setAccessible(true);
// 打印結果
System.out.println(field);
try {
if (field.getType() == Integer.class) {
field.set(apple, 5);
} else if (field.getType() == String.class) {
field.set(apple, "Red");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
});
// 查看apple結果
System.out.println(apple);
}
}
class Apple {
private Integer weight;
private String color;
@Override
public String toString() {
return "Apple{" +
"weight=" + weight +
", color='" + color + '\'' +
'}';
}
}
打印結果:
private java.lang.Integer p1.Apple.weight
private java.lang.String p1.Apple.color
Apple{weight=5, color='Red'}
進程已結束,退出代碼0
通過源碼文檔和打印結果,可見setAccessable()方法并沒有改變類字段的訪問權限,而是作為一個標志,使得我們反射獲取實例過程中可以對其進行操作
運用場景
在我看來,反射機制實際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式,那反射機制就是上帝偷偷開的后門,只要存在對應的class,一切都能夠被調(diào)用。
眾所周知,語言有靜態(tài)語言和動態(tài)語言兩大分類,靜態(tài)語言例如C/C++、Java、C#等,動態(tài)語言有Python、PHP、JavaScript等。為了讓Java語言也有動態(tài)語言的特性,有了反射機制,解耦以及提高代碼的靈活性。
反射在開發(fā)過中或許并不常見,可我們使用的框架工具底層都有反射的存在。動態(tài)代理設計模式、JDBC 的數(shù)據(jù)庫的連接、Spring 框架的使用等都應用到了反射機制。
以上就是Java中的反射機制示例詳解的詳細內(nèi)容,更多關于Java反射機制的資料請關注腳本之家其它相關文章!
相關文章
聊聊SpringBoot使用Nacos進行服務注冊發(fā)現(xiàn)與配置管理問題
Nacos支持基于DNS和基于RPC的服務發(fā)現(xiàn)(可以作為springcloud的注冊中心)、動態(tài)配置服務(可以做配置中心)、動態(tài)?DNS?服務。本文重點給大家介紹SpringBoot使用Nacos進行服務注冊發(fā)現(xiàn)與配置管理,感興趣的朋友一起看看吧2022-01-01
Activiti7通過代碼動態(tài)生成工作流實現(xiàn)詳解
這篇文章主要為大家介紹了Activiti7通過代碼動態(tài)生成工作流實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
SpringMVC與Mybatis集合實現(xiàn)調(diào)用存儲過程、事務控制實例
這篇文章主要介紹了SpringMVC與Mybatis集合實現(xiàn)調(diào)用存儲過程、事務控制實例,有需要的可以了解一下。2016-11-11

