java中的反射機制是什麼?有什麼作用呢?求解,謝謝。
- 2022-08-09
Java反射機制詳解
1. 反射機制是什麼
反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
2. 反射機制能做什麼
反射機制主要提供了以下功能:
在執行時判斷任意一個物件所屬的類;
在執行時構造任意一個類的物件;
在執行時判斷任意一個類所具有的成員變數和方法;
在執行時呼叫任意一個物件的方法;
生成動態代理。
3. 反射機制的相關API
透過一個物件獲得完整的包名和類名
package net。xsoftlab。baike;
public class TestReflect {
public static void main(String[] args) throws Exception {
TestReflect testReflect = new TestReflect();
System。out。println(testReflect。getClass()。getName());
// 結果 net。xsoftlab。baike。TestReflect
}
}
例項化Class類物件
package net。xsoftlab。baike;
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> class1 = null;
Class<?> class2 = null;
Class<?> class3 = null;
// 一般採用這種形式
class1 = Class。forName(“net。xsoftlab。baike。TestReflect”);
class2 = new TestReflect()。getClass();
class3 = TestReflect。class;
System。out。println(“類名稱 ” + class1。getName());
System。out。println(“類名稱 ” + class2。getName());
System。out。println(“類名稱 ” + class3。getName());
}
}
獲取一個物件的父類與實現的介面
package net。xsoftlab。baike;
import java。io。Serializable;
public class TestReflect implements Serializable {
private static final long serialVersionUID = -2862585049955236662L;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class。forName(“net。xsoftlab。baike。TestReflect”);
// 取得父類
Class<?> parentClass = clazz。getSuperclass();
System。out。println(“clazz的父類為:” + parentClass。getName());
// clazz的父類為: java。lang。Object
// 獲取所有的介面
Class<?> intes[] = clazz。getInterfaces();
System。out。println(“clazz實現的介面有:”);
for (int i = 0; i < intes。length; i++) {
System。out。println((i + 1) + “:” + intes[i]。getName());
}
// clazz實現的介面有:
// 1:java。io。Serializable
}
}
獲取某個類中的全部建構函式 - 詳見下例
透過反射機制例項化一個類的物件
package net。xsoftlab。baike;
import java。lang。reflect。Constructor;
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> class1 = null;
class1 = Class。forName(“net。xsoftlab。baike。User”);
// 第一種方法,例項化預設構造方法,呼叫set賦值
User user = (User) class1。newInstance();
user。setAge(20);
user。setName(“Rollen”);
System。out。println(user);
// 結果 User [age=20, name=Rollen]
// 第二種方法 取得全部的建構函式 使用建構函式賦值
Constructor<?> cons[] = class1。getConstructors();
// 檢視每個構造方法需要的引數
for (int i = 0; i < cons。length; i++) {
Class<?> clazzs[] = cons[i]。getParameterTypes();
System。out。print(“cons[” + i + “] (”);
for (int j = 0; j < clazzs。length; j++) {
if (j == clazzs。length - 1)
System。out。print(clazzs[j]。getName());
else
System。out。print(clazzs[j]。getName() + “,”);
}
System。out。println(“)”);
}
// 結果
// cons[0] (java。lang。String)
// cons[1] (int,java。lang。String)
// cons[2] ()
user = (User) cons[0]。newInstance(“Rollen”);
System。out。println(user);
// 結果 User [age=0, name=Rollen]
user = (User) cons[1]。newInstance(20, “Rollen”);
System。out。println(user);
// 結果 User [age=20, name=Rollen]
}
}
class User {
private int age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this。name = name;
}
public User(int age, String name) {
super();
this。age = age;
this。name = name;
}
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 [age=” + age + “, name=” + name + “]”;
}
}
獲取某個類的全部屬性
package net。xsoftlab。baike;
import java。io。Serializable;
import java。lang。reflect。Field;
import java。lang。reflect。Modifier;
public class TestReflect implements Serializable {
private static final long serialVersionUID = -2862585049955236662L;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class。forName(“net。xsoftlab。baike。TestReflect”);
System。out。println(“===============本類屬性===============”);
// 取得本類的全部屬性
Field[] field = clazz。getDeclaredFields();
for (int i = 0; i < field。length; i++) {
// 許可權修飾符
int mo = field[i]。getModifiers();
String priv = Modifier。toString(mo);
// 屬性型別
Class<?> type = field[i]。getType();
System。out。println(priv + “ ” + type。getName() + “ ” + field[i]。getName() + “;”);
}
System。out。println(“==========實現的介面或者父類的屬性==========”);
// 取得實現的介面或者父類的屬性
Field[] filed1 = clazz。getFields();
for (int j = 0; j < filed1。length; j++) {
// 許可權修飾符
int mo = filed1[j]。getModifiers();
String priv = Modifier。toString(mo);
// 屬性型別
Class<?> type = filed1[j]。getType();
System。out。println(priv + “ ” + type。getName() + “ ” + filed1[j]。getName() + “;”);
}
}
}
透過反射機制呼叫某個類的方法
package net。xsoftlab。baike;
import java。lang。reflect。Method;
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class。forName(“net。xsoftlab。baike。TestReflect”);
// 呼叫TestReflect類中的reflect1方法
Method method = clazz。getMethod(“reflect1”);
method。invoke(clazz。newInstance());
// Java 反射機制 - 呼叫某個類的方法1。
// 呼叫TestReflect的reflect2方法
method = clazz。getMethod(“reflect2”, int。class, String。class);
method。invoke(clazz。newInstance(), 20, “張三”);
// Java 反射機制 - 呼叫某個類的方法2。
// age -> 20。 name -> 張三
}
public void reflect1() {
System。out。println(“Java 反射機制 - 呼叫某個類的方法1。”);
}
public void reflect2(int age, String name) {
System。out。println(“Java 反射機制 - 呼叫某個類的方法2。”);
System。out。println(“age -> ” + age + “。 name -> ” + name);
}
}
透過反射機制操作某個類的屬性
package net。xsoftlab。baike;
import java。lang。reflect。Field;
public class TestReflect {
private String proprety = null;
public static void main(String[] args) throws Exception {
Class<?> clazz = Class。forName(“net。xsoftlab。baike。TestReflect”);
Object obj = clazz。newInstance();
// 可以直接對 private 的屬性賦值
Field field = clazz。getDeclaredField(“proprety”);
field。setAccessible(true);
field。set(obj, “Java反射機制”);
System。out。println(field。get(obj));
}
}
4. 反射機制的應用例項
在泛型為Integer的ArrayList中存放一個String型別的物件。
package net。xsoftlab。baike;
import java。lang。reflect。Method;
import java。util。ArrayList;
public class TestReflect {
public static void main(String[] args) throws Exception {
ArrayList
Method method = list。getClass()。getMethod(“add”, Object。class);
method。invoke(list, “Java反射機制例項。”);
System。out。println(list。get(0));
}
}
透過反射取得並修改陣列的資訊
package net。xsoftlab。baike;
import java。lang。reflect。Array;
public class TestReflect {
public static void main(String[] args) throws Exception {
int[] temp = { 1, 2, 3, 4, 5 };
Class<?> demo = temp。getClass()。getComponentType();
System。out。println(“陣列型別: ” + demo。getName());
System。out。println(“陣列長度 ” + Array。getLength(temp));
System。out。println(“陣列的第一個元素: ” + Array。get(temp, 0));
Array。set(temp, 0, 100);
System。out。println(“修改之後陣列第一個元素為: ” + Array。get(temp, 0));
}
}
將反射機制應用於工廠模式
package net。xsoftlab。baike;
interface fruit {
public abstract void eat();
}
class Apple implements fruit {
public void eat() {
System。out。println(“Apple”);
}
}
class Orange implements fruit {
public void eat() {
System。out。println(“Orange”);
}
}
class Factory {
public static fruit getInstance(String ClassName) {
fruit f = null;
try {
f = (fruit) Class。forName(ClassName)。newInstance();
} catch (Exception e) {
e。printStackTrace();
}
return f;
}
}
/**
* 對於普通的工廠模式當我們在新增一個子類的時候,就需要對應的修改工廠類。 當我們新增很多的子類的時候,會很麻煩。
* Java 工廠模式可以參考
* http://baike。xsoftlab。net/view/java-factory-pattern
*
* 現在我們利用反射機制實現工廠模式,可以在不修改工廠類的情況下新增任意多個子類。
*
* 但是有一點仍然很麻煩,就是需要知道完整的包名和類名,這裡可以使用properties配置檔案來完成。
*
* java 讀取 properties 配置檔案 的方法可以參考
* http://baike。xsoftlab。net/view/java-read-the-properties-configuration-file
*
* @author xsoftlab。net
*/
public class TestReflect {
public static void main(String[] args) throws Exception {
fruit f = Factory。getInstance(“net。xsoftlab。baike。Apple”);
if (f != null) {
f。eat();
}
}
}
我有一個微信公眾號,經常會分享一些Java技術相關的乾貨,還有一些學習資源。
如果你喜歡我的分享,可以用微信搜尋“Java團長”或者“javatuanzhang”關注。
反射是java的一種動態執行機制,常見框架底層用的都是反射,隨需而變就是反射,簡單的講,和動態沾邊的都是反射。
反射在什麼時候用呢?
(1)當能確定呼叫執行關係時,不用反射
(2)當出現不確定的情況(不知道類名,不知道屬性名,不知道方法名),就可以使用反射
特殊用途:利用反射訪問私有屬性方法
Java反射-屬性操作
JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。
JAVA反射(放射)機制:“程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言”。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。但是JAVA有著一個非常突出的動態相關機制:Reflection,用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods。
Java反射機制主要提供了以下功能: 在執行時判斷任意一個物件所屬的類;在執行時構造任意一個類的物件;在執行時判斷任意一個類所具有的成員變數和方法;在執行時呼叫任意一個物件的方法;生成動態代理。
有時候我們說某個語言具有很強的動態性,有時候我們會區分動態和靜態的不同技術與作法。我們朗朗上口動態繫結(dynamic binding)、動態連結(dynamic linking)、動態載入(dynamic loading)等。然而“動態”一詞其實沒有絕對而普遍適用的嚴格定義,有時候甚至像面向物件當初被匯入程式設計領域一樣,一人一把號,各吹各的調。
一般而言,開發者社群說到動態語言,大致認同的一個定義是:“程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言”。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。
儘管在這樣的定義與分類下Java不是動態語言,它卻有著一個非常突出的動態相關機制:Reflection。這個字的意思是“反射、映象、倒影”,用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods。這種“看透class”的能力(the ability of the program to examine itself)被稱為introspection(內省、內觀、反省)。Reflection和introspection是常被並提的兩個術語。
Java如何能夠做出上述的動態特性呢?這是一個深遠話題,本文對此只簡單介紹一些概念。整個篇幅最主要還是介紹Reflection APIs,也就是讓讀者知道如何探索class的結構、如何對某個“執行時才獲知名稱的class”生成一份實體、為其fields設值、呼叫其methods。本文將談到java。lang。Class,以及java。lang。reflect中的Method、Field、Constructor等等classes。
JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法;這種動態獲取的以及動態呼叫物件的方法的功能稱為java語言的反射機制。
Java反射機制主要提供了以下功能:在執行時判定任意一個物件所屬的類;在執行時構造任意一個類的物件;在執行時判定任意一個類所具有的成員變數和方法;在執行時呼叫任意一個物件的方法;生成動態代理。