Java反射機(jī)制的實(shí)現(xiàn)詳解
很多主流框架都使用了反射技術(shù).像ssh框架都采用兩種技術(shù) xml做配置文件+反射技術(shù).
與反射有關(guān)的類包.
java.lang.reflect.*;和java.lang.Class;
Java中所有類型(包括基本類型)都對應(yīng)一個Class對象,這個Class就是java.lang.Class。即每一個類型,在Class中都有一個Class對象跟它對應(yīng).Class 沒有公共構(gòu)造方法。注意不是沒有,是沒有公共的.
如何獲得Class對象
.針對每一個對象.getCalss(),可以得到對應(yīng)的Class.
.Class.forName(String),String的寫法:包名.類名.就會創(chuàng)建包名.類名對應(yīng)的那個對象
注:1.2只適用于引用類型
.對于基本類型:封裝類.TYPE代表了對應(yīng)的基本類型的Class對象.Integer.TYPE對應(yīng)的是int的Class對象
注:3只適用于基本類型
.類型,Class。<第4種是通用的.>
上面的4種方法,只有方法2是動態(tài)的,只要換一個包就可以了.它具有動態(tài)潛質(zhì).所以真正意義的想體現(xiàn)動態(tài)編程只能使用方法2.
每種類型的Class對象只有一個,即他們的地址只有一個,但是不同類型是不同的.
所以下面的打印結(jié)果都為true.
//對與引用類型
Class c1 = "".getClass();
Class c2 = Class.forName("java.lang.String");
Class c3 = String.class;
System.out.println(c1 ==c2);//true
//對于基本類型
Class num1 = Integer.TYPE;
Class num2 = int.class;
System.out.println(num1 == num2);//true
反射獲取類中的成員的相關(guān)方法
[獲取構(gòu)造<根據(jù)參數(shù)類型>](使用時一般用不帶declared的)
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構(gòu)造方法。
Constructor<?>[] getConstructors()
返回一個包含某些 Constructor 對象的數(shù)組,這些對象反映此 Class 對象所表示的類的所有公共構(gòu)造方法。
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構(gòu)造方法。
Constructor<?>[] getDeclaredConstructors()
返回 Constructor 對象的一個數(shù)組,這些對象反映此 Class 對象表示的類聲明的所有構(gòu)造方法。
[獲取屬性<根據(jù)屬性名>](使用時一般用是帶declared的,因?yàn)閷傩砸话愣际撬接械?/SPAN>)
Field getField(String name)
返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。
Field[] getFields()
返回一個包含某些 Field 對象的數(shù)組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。
Field getDeclaredField(String name)
返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。
Field[] getDeclaredFields()
返回 Field 對象的一個數(shù)組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。
[獲取方法<方法名加上參數(shù)類型>](使用時一般用不帶declared的)
Method getMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。
Method[] getMethods()
返回一個包含某些 Method 對象的數(shù)組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。
Method[] getDeclaredMethods()
返回 Method 對象的一個數(shù)組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護(hù)、默認(rèn)(包)訪問和私有方法,但不包括繼承的方法。
T newInstance()
創(chuàng)建此 Class 對象所表示的類的一個新實(shí)例。 <new Instance()可以動態(tài)的創(chuàng)建對象>
String toString()
將對象轉(zhuǎn)換為字符串。
注意:
new Instance()調(diào)用的是無參構(gòu)造,如果該類沒有無參構(gòu)造方法,則newInstance()會產(chǎn)生異常.
有declared的方法是支持私有,但是不支持繼承,無declared的方法支持繼承,不支持私有,且只能取出public的東西.
因此取屬性的時候一般來說是帶declared的,因?yàn)閷傩砸话愣际撬接械?取方法時一般是不帶declared的,取構(gòu)造時一般也是不帶declared的.
實(shí)例模擬反射獲取類中的相關(guān)屬性和方法
利用反射對屬性賦值
Field中的方法
Object get(Object obj)
返回指定對象上此 Field 表示的字段的值。
Field f = c.getXXField(屬性名);
值 = f.get(對象);
void set(Object obj, Object value)
將指定對象變量上此 Field 對象表示的字段設(shè)置為指定的新值。
f.set(對象,值);
Class<?> getType()
返回一個 Class 對象,它標(biāo)識了此 Field 對象所表示字段的聲明類型。
用于獲取屬性的類型(返回Class對象).
Class c = Student.class;
Object obj = c.newInstance(); //創(chuàng)建Student類的對象
Field f = c.getDeclaredField("name"); //獲取name屬性
f.setAccessible(true); //設(shè)置私有可以訪問.
f.set(obj, "zhangsan");
System.out.println(f.get(obj)); //獲取obj的name屬性的值.
利用反射調(diào)用構(gòu)造
對于構(gòu)造真正調(diào)用是在調(diào)用newInstance()方法時.
Class c = Class.forName("com.clazz.reflect.Student");
Constructor con = c.getConstructor(); //沒有執(zhí)行構(gòu)造,
Object cObj = c.getConstructor().newInstance();//調(diào)用無參的構(gòu)造方法
Constructor conAll = c.getConstructor(int.class,String.class,int.class);
Object caobj = conAll.newInstance(1001,"zjamgs",234235);//調(diào)用含參的構(gòu)造方法.
System.out.println(caobj); //打印輸出
利用反射調(diào)用方法
對象.方法名(值1,2,3);
Method m = c.getMethoed(方法名,參數(shù)類型...);
m.invoke(對象,方法調(diào)用的參數(shù) )如果底層方法所需的形參數(shù)為 0,則所提供的 args 數(shù)組長度可以為 0 或 null。
Class c = Class.forName("com.clazz.reflect.Student");
Object obj = c.newInstance(); //創(chuàng)建Sutdent對象.
Method msetName = c.getMethod("setName", String.class);//obj無須轉(zhuǎn)換類型
msetName.invoke(obj, "zhangsan");//調(diào)用方法setName, 并傳參.
Method msetId = c.getMethod("setId", int.class);
msetId.invoke(obj, 409090202);
System.out.println(obj);
反射應(yīng)用實(shí)例
實(shí)體類
package org.dennisit.reflect.entity;
import java.io.Serializable;
/**
*
* User.java
*
* @version : 1.1
*
* @author : 蘇若年 <a href="mailto:DennisIT@163.com">發(fā)送郵件</a>
*
* @since : 1.0 創(chuàng)建時間: 2013-2-26 下午01:43:56
*
* TODO : class User.java is used for ...
*
*/
public class User implements Serializable{
private String test;
public void execute(String name,int age){
System.out.println("name=" + name + ",age=" + age);
}
}
反射測試類
package org.dennisit.reflect.main;
import java.lang.reflect.Field;
/**
*
* ReflectEx.java
*
* @version : 1.1
*
* @author : 蘇若年 <a href="mailto:DennisIT@163.com">發(fā)送郵件</a>
*
* @since : 1.0 創(chuàng)建時間: 2013-2-26 下午01:46:00
*
* TODO : class ReflectEx.java is used for ...
*
*/
public class ReflectEx {
public static void main(String[] args)throws Exception {
Class cls = Class.forName("org.dennisit.reflect.entity.User");
Object obj = cls.newInstance(); //創(chuàng)建User的對象
Field f = cls.getDeclaredField("test"); //獲取test屬性
f.setAccessible(true); //打開私有屬性test的訪問權(quán)限
f.set(obj, "zhangsan"); //為test重新復(fù)制
System.out.println(f.get(obj)); //獲取obj的test屬性值
//根據(jù)方法名execute獲取方法
java.lang.reflect.Method m = cls.getMethod("execute", String.class, int.class);
m.invoke(obj, "dennisit",23); //調(diào)用execute方法
}
}
運(yùn)行效果
zhangsan
name=dennisit,age=23
編寫一個反射動態(tài)實(shí)例化類的例子
package org.dennisit.reflect.main;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
/**
*
* DynamicReflect.java
*
* @version : 1.1
*
* @author : 蘇若年 <a href="mailto:DennisIT@163.com">發(fā)送郵件</a>
*
* @since : 1.0 創(chuàng)建時間: 2013-2-26 下午01:58:12
*
* TODO : 利用反射動態(tài)實(shí)例化的例子
*
*/
public class DynamicReflect {
public static Object getInstance(String className,Map<String,Object> map)throws Exception{
Class c = Class.forName(className);
Object obj = c.newInstance(); //對象對象
Set<String> keys = map.keySet(); //獲取對應(yīng)的所有屬性
Field[] fAll = c.getDeclaredFields(); //獲取類中所有屬性
for(int i=0;i<fAll.length;i++){
for(String key:keys){ //循環(huán)匹配
if(fAll[i].getName().equals(key)){ //如果用戶傳入的屬性跟獲取到的類中的屬性名匹配
Field f = c.getDeclaredField(key);//獲取該屬性
//構(gòu)建setXxx()方法名
String methodName = "set" + key.substring(0,1).toUpperCase()+key.substring(1);
Method method = c.getMethod(methodName, f.getType());//根據(jù)構(gòu)建的用戶名獲取對應(yīng)的方法
method.invoke(obj, map.get(key));//方法調(diào)用
}else{
continue;
}
}
}
return obj;
}
}
接下來我們測試我們編寫的動態(tài)反射實(shí)例化例子
實(shí)體類
package org.dennisit.reflect.entity;
import java.io.Serializable;
/**
*
* User.java
*
* @version : 1.1
*
* @author : 蘇若年 <a href="mailto:DennisIT@163.com">發(fā)送郵件</a>
*
* @since : 1.0 創(chuàng)建時間: 2013-2-26 下午01:43:56
*
* TODO : 實(shí)體類
*
*/
public class User implements Serializable{
private String name;
private int age;
private String email;
public User() { //必須有無參構(gòu)造
}
//getter() and setter()
}
主測試類
package org.dennisit.reflect.main;
import java.util.HashMap;
import java.util.Map;
import org.dennisit.reflect.entity.User;
/**
*
* ReflectEx.java
*
* @version : 1.1
*
* @author : 蘇若年 <a href="mailto:DennisIT@163.com">發(fā)送郵件</a>
*
* @since : 1.0 創(chuàng)建時間: 2013-2-26 下午01:46:00
*
* TODO : class ReflectEx.java is used for ...
*
*/
public class ReflectEx {
public static void main(String[] args)throws Exception {
Class cls = Class.forName("org.dennisit.reflect.entity.User");
String className = "org.dennisit.reflect.entity.User";
Map<String,Object> map = new HashMap<String, Object>();
map.put("name", "dennisit");
map.put("age", 22);
map.put("email", "dennisit@163.com");
User user = (User)DynamicReflect.getInstance(className, map);
System.out.println(user.getName() + "," + user.getAge() + "," + user.getEmail());
}
}
程序運(yùn)行結(jié)果
dennisit,22,dennisit@163.com
相關(guān)文章
springboot?vue接口測試定義編輯功能的實(shí)現(xiàn)
這篇文章主要為大家介紹了springboot?vue接口測試定義編輯功能的實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05jackson 如何將實(shí)體轉(zhuǎn)json json字符串轉(zhuǎn)實(shí)體
這篇文章主要介紹了jackson 實(shí)現(xiàn)將實(shí)體轉(zhuǎn)json json字符串轉(zhuǎn)實(shí)體,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot實(shí)現(xiàn)WebSocket服務(wù)并讓客戶端實(shí)時接收
使用SpringBoot和WebSocket可創(chuàng)建實(shí)時消息推送服務(wù),首先添加WebSocket依賴至pom.xml,配置WebSocket端點(diǎn)和邏輯處理器,通過WebSocketHandler處理消息,使用AnnouncementController模擬消息推送,支持HTML和微信小程序客戶端接收消息,感興趣的可以了解一下2024-10-10Spring Boot集成ShedLock分布式定時任務(wù)的實(shí)現(xiàn)示例
ShedLock確保您計(jì)劃的任務(wù)最多同時執(zhí)行一次。如果一個任務(wù)正在一個節(jié)點(diǎn)上執(zhí)行,則它會獲得一個鎖,該鎖將阻止從另一個節(jié)點(diǎn)(或線程)執(zhí)行同一任務(wù)。2021-05-05SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑
本文主要介紹了SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05Springboot實(shí)現(xiàn)獲取實(shí)時天氣
這篇文章主要為大家詳細(xì)介紹了如何使用Springboot實(shí)現(xiàn)獲取實(shí)時天氣功能,文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-04-04基于String不可變字符與StringBuilder可變字符的效率問題
這篇文章主要介紹了String不可變字符與StringBuilder可變字符的效率問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07java數(shù)組及arrays類對數(shù)組的操作實(shí)例
下面小編就為大家?guī)硪黄猨ava數(shù)組及arrays類對數(shù)組的操作實(shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-10-10