搜尋
首頁Javajava教程java原理—反射機制

java原理—反射機制

Dec 13, 2016 pm 02:06 PM
java反射機制

學習:java原理—反射機制

一、什麼是反射:
反射的概念是由Smith在1982年首次提出的,主要是指程式可以存取、偵測和修改它本身狀態或行為的一種能力。這一概念的提 出很快就引發了計算機科學領域關於應用反射性的研究。它首先被程式語言的設計領域所採用,並在Lisp和物件導向方面取得了成績。其中 LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等都是基於反射機制的語言。最近,反射機制也被應用到了視窗系統、作業系統和檔案系統。

反射本身並不 是一個新概念,儘管電腦科學賦予了反射概念新的意義。在電腦科學領域,反射是指一類應用,它們能夠自我描述和自控制。也就是說,這類應用透過採用某種機制來實現對自己行為的描述(self-representation)和監控(examination),並能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。

二、什麼是Java中的類別反射:
Reflection 是Java 程式開發語言的特徵之一,它允許運行中的Java 程式對自身進行檢查,或者說“自審”,並能直接操作程序的內部屬性和方法。 Java 的這項能力在實際應用中用得不是很多,但是在其它的程式設計語言中根本就不存在這一特性。例如,Pascal、C 或 C++ 中就沒有辦法在程式中取得函數定義相關的資訊。
Reflection 是Java 被視為動態(或準動態)語言的關鍵,允許程式於執行期Reflection APIs 取得任何已知名稱之class 的內部信息,包括package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可於執行期產生instances、變更fields 內容或喚起methods。

三、Java類別反射中所必須的類別:
Java的類別反射所需的類別並不多,它們分別是:Field、Constructor、Method、Class、Object,下面我將對這些類別做一個簡單的說明。
Field類別:提供有關類別或介面的屬性的信息,以及對它的動態存取權限。反射的欄位可能是一個類別(靜態)屬性或實例屬性,簡單的理解可以把它看成一個封裝反射類別的屬性的類別。
Constructor類別:提供關於類別的單一建構方法的資訊以及對它的存取權限。這個類別和Field類別不同,Field類別封裝了反射類別的屬性,而Constructor類別則封裝了反射類別的建構方法。
Method類別:提供關於類別或介面上單獨某個方法的資訊。所反映的方法可能是類別方法或實例方法(包括抽象方法)。 這個類別不難理解,它是用來封裝反射類別方法的一個類別。
Class類別:類別的實例表示正在執行的 Java 應用程式中的類別和介面。枚舉是一種類,註解是一種介面。每個數組屬於被映射為 Class 物件的一個類,所有具有相同元素類型和維數的數組都共用該 Class 物件。
Object類別:每個類別都使用 Object 作為超類別。所有物件(包括數組)都實作這個類別的方法。

四、Java的反射類能做什麼:
看完上面的這麼多我想你已經不耐煩了,你以為我在浪費你的時間,那好吧!下面我們就用一些簡單的小例子來說明它。
首先我們來看看透過Java的反射機制我們能得到什麼。
首先我們來寫一個類別:

java 程式碼

 java.awt.event.ActionListener;  
import java.awt.event.ActionEvent;  
class A extends Object implements ActionListener{  
private int a = 3;  
public Integer b = new Integer(4);  
public A(){}  
public A(int id,String name){}  
public int abc(int id,String name){return 0;}  
public void actionPerformed(ActionEvent e){}  
}

你可能被我這個類弄糊塗了,你看不出我要做什麼,那就不要看這個類了,這個類是用來測試的,你知道知道它繼承了Object類,有一個介面是ActionListener,兩個屬性int和Integer,兩個建構方法和兩個方法,這就夠了。
下面我們把A這個類當作一個反射類,來過去A類中的一些訊息,首先我們先來過去一下反射類中的屬性和屬性值。

java 程式碼

import java.lang.reflect.*;  
class B{  
public static void main(String args[]){  
A r = new A();  
Class temp = r.getClass();  
try{  
System.out.println("反射类中所有公有的属性");  
Field[] fb =temp.getFields();  
for(int j=0;j<fb.length;j++){  
Class cl = fb[j].getType();  
System.out.println("fb:"+cl);  
}  
  
System.out.println("反射类中所有的属性");  
Field[] fa = temp.getDeclaredFields();  
for(int j=0;j<fa.length;j++){  
Class cl = fa[j].getType();  
System.out.println("fa:"+cl);  
}  
System.out.println("反射类中私有属性的值");  
Field f = temp.getDeclaredField("a");  
f.setAccessible(true);  
Integer i = (Integer)f.get(r);  
System.out.println(i);  
}catch(Exception e){  
e.printStackTrace();  
}  
}  
  
}

这里用到了两个方法,getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方法。另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法,要注意的是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到。
这里还用到了Field 类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外 Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。

下面我们来看一下如何获取反射类中的构造方法

java 代码

import java.lang.reflect.*;  
public class SampleConstructor {  
public static void main(String[] args) {  
A r = new A();  
printConstructors(r);  
}  
  
public static void printConstructors(A r) {  
Class c = r.getClass();  
//获取指定类的类名  
String className = c.getName();  
try {  
//获取指定类的构造方法  
Constructor[] theConstructors = c.getConstructors();  
for(int i=0; i<theConstructors.length; i++) {  
//获取指定构造方法的参数的集合  
Class[] parameterTypes = theConstructors[i].getParameterTypes();  
  
System.out.print(className + "(");  
  
for(int j=0; j<parameterTypes.length; j++)  
System.out.print(parameterTypes[j].getName() + " ");  
  
System.out.println(")");  
  
}  
}catch(Exception e) {  
e.printStackTrace();  
}  
}  
}

这个例子很简单,只是用getConstructors()方法获取了反射类的构造方法的集合,并用Constructor类的getParameterTypes()获取该构造方法的参数。

下面我们再来获取一下反射类的父类(超类)和接口

java 代码

import java.io.*;  
import java.lang.reflect.*;  
  
public class SampleInterface {  
public static void main(String[] args) throws Exception {  
A raf = new A();  
printInterfaceNames(raf);  
}  
  
public static void printInterfaceNames(Object o) {  
Class c = o.getClass();  
//获取反射类的接口  
Class[] theInterfaces = c.getInterfaces();  
for(int i=0; i<theInterfaces.length; i++)  
System.out.println(theInterfaces[i].getName());  
//获取反射类的父类(超类)  
Class theSuperclass = c.getSuperclass();  
System.out.println(theSuperclass.getName());  
}  
}

这个例子也很简单,只是用Class类的getInterfaces()方法获取反射类的所有接口,由于接口可以有多个,所以它返回一个 Class数组。用getSuperclass()方法来获取反射类的父类(超类),由于一个类只能继承自一个类,所以它返回一个Class对象。

下面我们来获取一下反射类的方法

java 代码

import java.lang.reflect.*;  
public class SampleMethod {  
  
public static void main(String[] args) {  
A p = new A();  
printMethods(p);  
}  
  
public static void printMethods(Object o) {  
Class c = o.getClass();  
String className = c.getName();  
Method[] m = c.getMethods();  
for(int i=0; i<m.length; i++) {  
//输出方法的返回类型  
System.out.print(m[i].getReturnType().getName());  
//输出方法名  
System.out.print(" "+m[i].getName()+"(");  
//获取方法的参数  
Class[] parameterTypes = m[i].getParameterTypes();  
for(int j=0; j<parameterTypes.length; j++){  
System.out.print(parameterTypes[j].getName());  
if(parameterTypes.length>j+1){  
System.out.print(",");  
}  
}  
  
System.out.println(")");  
}  
  
}  
  
}

这个例子并不难,它只是获得了反射类的所有方法,包括继承自它父类的方法。然后获取方法的返回类型、方法名和方法参数。

接下来让我们回过头来想一想,我们获取了反射类的属性、构造方法、父类、接口和方法,可这些东西能帮我们做些什么呢!!
下面我写一个比较完整的小例子,来说明Java的反射类能做些什么吧!!

java 代码

import java.lang.reflect.Constructor;  
import java.lang.reflect.Method;  
  
public class LoadMethod {  
public Object Load(String cName,String MethodName,String[] type,String[] param){  
Object retobj = null;  
try {  
//加载指定的Java类  
Class cls = Class.forName(cName);  
  
//获取指定对象的实例  
Constructor ct = cls.getConstructor(null);  
Object obj = ct.newInstance(null);  
  
//构建方法参数的数据类型  
Class partypes[] = this.getMethodClass(type);  
  
//在指定类中获取指定的方法  
Method meth = cls.getMethod(MethodName, partypes);  
  
//构建方法的参数值  
Object arglist[] = this.getMethodObject(type,param);  
  
//调用指定的方法并获取返回值为Object类型  
retobj= meth.invoke(obj, arglist);  
  
}  
catch (Throwable e) {  
System.err.println(e);  
}  
return retobj;  
}  
  
//获取参数类型Class[]的方法  
public Class[] getMethodClass(String[] type){  
Class[] cs = new Class[type.length];  
for (int i = 0; i < cs.length; i++) {  
if(!type[i].trim().equals("")||type[i]!=null){  
if(type[i].equals("int")||type[i].equals("Integer")){  
cs[i]=Integer.TYPE;  
}else if(type[i].equals("float")||type[i].equals("Float")){  
cs[i]=Float.TYPE;  
}else if(type[i].equals("double")||type[i].equals("Double")){  
cs[i]=Double.TYPE;  
}else if(type[i].equals("boolean")||type[i].equals("Boolean")){  
cs[i]=Boolean.TYPE;  
}else{  
cs[i]=String.class;  
}  
}  
}  
return cs;  
}  
  
//获取参数Object[]的方法  
public Object[] getMethodObject(String[] type,String[] param){  
Object[] obj = new Object[param.length];  
for (int i = 0; i < obj.length; i++) {  
if(!param[i].trim().equals("")||param[i]!=null){  
if(type[i].equals("int")||type[i].equals("Integer")){  
obj[i]= new Integer(param[i]);  
}else if(type[i].equals("float")||type[i].equals("Float")){  
obj[i]= new Float(param[i]);  
}else if(type[i].equals("double")||type[i].equals("Double")){  
obj[i]= new Double(param[i]);  
}else if(type[i].equals("boolean")||type[i].equals("Boolean")){  
obj[i]=new Boolean(param[i]);  
}else{  
obj[i] = param[i];  
}  
}  
}  
return obj;  
}  
}

这是我在工作中写的一个实现Java在运行时加载指定的类,并调用指定方法的一个小例子。这里没有main方法,你可以自己写一个。
Load方法接收的五个参数分别是,Java的类名,方法名,参数的类型和参数的值。

结束语:
Java 语言反射提供一种动态链接程序组件的多功能方法。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。这些特性使得反射特别适用于创建以非常普通的方式与对象协作的库。Java reflection 非常有用,它使类和数据结构能按名称动态检索相关信息,并允许在运行着的程序中操作这些信息。Java 的这一特性非常强大,并且是其它一些常用语言,如 C、C++、Fortran 或者 Pascal 等都不具备的。

但反射有两个缺点。第一个是性能问题。用于字段和方法接入时反射要远慢于直接代码。性能问题的程度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓慢的性能将不会是一个问题。即使测试中最坏情况下的计时图显示的反射操作只耗用几微秒。仅反射在性能关键的应用的核心逻辑中使用时性能问题才变得至关重要。


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

如何將Java的RMI(遠程方法調用)用於分佈式計算?如何將Java的RMI(遠程方法調用)用於分佈式計算?Mar 11, 2025 pm 05:53 PM

本文解釋了用於構建分佈式應用程序的Java的遠程方法調用(RMI)。 它詳細介紹了接口定義,實現,註冊表設置和客戶端調用,以解決網絡問題和安全性等挑戰。

如何使用Java的插座API進行網絡通信?如何使用Java的插座API進行網絡通信?Mar 11, 2025 pm 05:53 PM

本文詳細介紹了用於網絡通信的Java的套接字API,涵蓋了客戶服務器設置,數據處理和關鍵考慮因素,例如資源管理,錯誤處理和安全性。 它還探索了性能優化技術,我

如何在Java中創建自定義網絡協議?如何在Java中創建自定義網絡協議?Mar 11, 2025 pm 05:52 PM

本文詳細介紹了創建自定義Java網絡協議。 它涵蓋協議定義(數據結構,框架,錯誤處理,版本控制),實現(使用插座),數據序列化和最佳實踐(效率,安全性,維護

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),