日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 反射创建对象并赋值_java使用反射创建并操作对象的方法

發布時間:2025/3/11 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 反射创建对象并赋值_java使用反射创建并操作对象的方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Class 對象可以獲得該類里的方法(由 Method 對象表示)、構造器(由 Constructor 對象表示)、成員變量(由 Field 對象表示),這三個類都位于 java.lang.reflect 包下,并實現了 java.lang.reflect.Member 接口。程序可以通過對象來執行對應的方法,通過 Constructor 對象來調用對應的構造器創建實例,能通過 Field 對象直接訪問并修改對象的成員變量值。

創建對象

通過反射來生成對象需要先使用 Class 對象獲取指定的 Constructor 對象,再調用 Constructor 對象的 newInstance() 方法來創建該 Class 對象對應類的實例。通過這種方式可以選擇使用指定的構造器來創建實例。

在很多 Java EE 框架中都需要根據配置文件信息來創建 Java 對象,從配置文件讀取的只是某個類的字符串類名,程序需要根據該字符串來創建對應的實例,就必須使用反射。

下面程序就實現了一個簡單的對象池,該對象池會根據配置文件讀取 key-value 對,然后創建這些對象,并將這些對象放入一個 HashMap 中。

public class ObjectPoolFactory {

// 定義一個對象池,前面是對象名,后面是實際對象

private Map objectPool = new HashMap<>();

// 定義一個創建對象的方法

// 該方法只要傳入一個字符串類名,程序可以根據該類名生成Java對象

private Object createObject(String clazzName) throws Exception, IllegalAccessException, ClassNotFoundException {

// 根據字符串來獲取對應的Class對象

Class> clazz = Class.forName(clazzName);

// 使用clazz對應類的默認構造器創建實例

return clazz.getConstructor().newInstance();

}

// 該方法根據指定文件來初始化對象池

// 它會根據配置文件來創建對象

public void initPool(String fileName)

throws InstantiationException, IllegalAccessException, ClassNotFoundException {

try (FileInputStream fis = new FileInputStream(fileName)) {

Properties props = new Properties();

props.load(fis);

for (String name : props.stringPropertyNames()) {

// 每取出一對key-value對,就根據value創建一個對象

// 調用createObject()創建對象,并將對象添加到對象池中

objectPool.put(name, createObject(props.getProperty(name)));

}

} catch (Exception ex) {

System.out.println("讀取" + fileName + "異常");

}

}

public Object getObject(String name) {

// 從objectPool中取出指定name對應的對象

return objectPool.get(name);

}

public static void main(String[] args) throws Exception {

ObjectPoolFactory pf = new ObjectPoolFactory();

pf.initPool("obj.txt");

System.out.println(pf.getObject("a")); // ①

System.out.println(pf.getObject("b")); // ②

}

}

上面程序中 createObject() 方法里的兩行粗體字代碼就是根據字符串來創建 Java 對象的關鍵代碼,程序調用 Class 對象的 newInstance() 方法即可創建一個 Java 對象。程序中的 initPool() 方法會讀取屬性文件,對屬性文件中每個 key-value 對創建一個 Java 對象,其中 value 是該 Java 對象的實現類,而 key 是該 Java 對象放入對象池中的名字。為該程序提供如下屬性配置文件。

a=java.util.Date

b=javax.swing.JFrame

編譯、運行上面的 ObjectPoolFactory 程序,執行到 main 方法中的①號代碼處,將看到輸出系統當前時間——這表明對象池中已經有了一個名為a的對象,該對象是一個 java.util.Date 對象。執行到②號代碼處,將看到輸出一個 JFrame 對象。

提示:這種使用配置文件來配置對象,然后由程序根據配置文件來創建對象的方式非常有用,大名鼎鼎的 Spring 框架就采用這種方式大大簡化了 Java EE 應用的開發。當然,Spring 采用的是 XML 配置文件——畢竟屬性文件能配置的信息太有限了,而 XML 配置文件能配置的信息就豐富多。

如果不想利用默認構造器來創建 Java 對象,而想利用指定的構造器來創建 Java 對象,則需要利用 Constructor 對象,每個 Constructor 對應一個構造器。為了利用指定的構造器來創建 Java 對象,需要如下三個步驟。

獲取該類的 Class 對象。

利用 Class 對象的 getConstructor() 方法來獲取指定的構造器。

調用 Constructor 的 newInstance() 方法來創建 Java 對象。

下面程序利用反射來創建一個 JFrame 對象,而且使用指定的構造器。

public class CreateJFrame {

public static void main(String[] args) throws Exception {

// 獲取JFrame對應的Class對象

Class> jframeClazz = Class.forName("javax.swing.JFrame");

// 獲取JFrame中帶一個字符串參數的構造器

Constructor ctor = jframeClazz.getConstructor(String.class);

// 調用Constructor的newInstance方法創建對象

Object obj = ctor.newInstance("測試窗口");

// 輸出JFrame對象

System.out.println(obj);

}

}

上面程序中第一行粗休字代碼用于獲取 JFrame 類的指定構造器,前面已經提到:如果要唯一地確定某類中的構造器,只要指定構造器的形參列表即可。第一行粗體字代碼獲取構造器時傳入了一個 String 類型,即表明想獲取只有一個字符串參數的構造器。

程序中第二行粗體字代碼使用指定構造器的 newInstance() 方法來創建一個 Java 對象,當調用 Constructor 對象的 newInstance() 方法時通常需要傳入參數,因為調用 Constructor 的 newInstance() 方法實際上等于調用它對應的構造器,傳給 newInstance() 方法的參數將作為對應構造器的參數。

對于上面的 CreateFrame.java 中已知 java.swing.JFrame 類的情形,通常沒有必要使用反射來創建該對象,畢竟通過反射創建對象時性能要稍低一些。實際上,只有當程序需要動態創建某個類的對象時才會考慮使用反射,通常在開發通用性比較廣的框架、基礎平臺時可能會大量使用反射。

調用方法

當獲得某個類對應的 Class 對象后,就可以通過該 Class 對象的 getMethods() 方法或者 getMethod()方法來獲取全部方法或指定方法——這兩個方法的返回值是 Method 數組,或者 Method 對象。

每個 Method 對象對應一個方法,獲得 Method 對象后,程序就可通過該 Method 來調用它對應的方法。在 Method 里包含一個 Invoke() 方法,該方法的簽名如下。

Object invoke(Object obj, Object...args):該方法中的 obj 是執行該方法的主調,后面的 args 是執行該方法時傳入該方法的實參。

下面程序對前面的對象池工廠進行加強,允許在配置文件中增加配置對象的成員變量的值,對象池工廠會讀取為該對象配置的成員變量值,并利用該對象對應的 setter 方法設置成員變量的值。

public class ExtendedObjectPoolFactory {

// 定義一個對象池,前面是對象名,后面是實際對象

private Map objectPool = new HashMap<>();

private Properties config = new Properties();

// 從指定屬性文件中初始化Properties對象

public void init(String fileName) {

try (FileInputStream fis = new FileInputStream(fileName)) {

config.load(fis);

} catch (IOException ex) {

System.out.println("讀取" + fileName + "異常");

}

}

// 定義一個創建對象的方法

// 該方法只要傳入一個字符串類名,程序可以根據該類名生成Java對象

private Object createObject(String clazzName) throws Exception {

// 根據字符串來獲取對應的Class對象

Class> clazz = Class.forName(clazzName);

// 使用clazz對應類的默認構造器創建實例

return clazz.getConstructor().newInstance();

}

// 該方法根據指定文件來初始化對象池

// 它會根據配置文件來創建對象

public void initPool() throws Exception {

for (String name : config.stringPropertyNames()) {

// 每取出一個key-value對,如果key中不包含百分號(%)

// 這就表明是根據value來創建一個對象

// 調用createObject創建對象,并將對象添加到對象池中

if (!name.contains("%")) {

objectPool.put(name, createObject(config.getProperty(name)));

}

}

}

// 該方法將會根據屬性文件來調用指定對象的setter方法

public void initProperty() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {

for (String name : config.stringPropertyNames()) {

// 每取出一對key-value對,如果key中包含百分號(%)

// 即可認為該key用于控制調用對象的setter方法設置值

// %前半為對象名字,后半控制setter方法名

if (name.contains("%")) {

// 將配置文件中的key按%分割

String[] objAndProp = name.split("%");

// 取出調用setter方法的參數值

Object target = getObject(objAndProp[0]);

// 獲取setter方法名:set + "首字母大寫" + 剩下部分

String mtdName = "set" + objAndProp[1].substring(0, 1).toUpperCase() + objAndProp[1].substring(1);

// 通過target的getClass()獲取它的實現類所對應的Class對象

Class> targetClass = target.getClass();

// 獲取希望調用的setter方法

Method mtd = targetClass.getMethod(mtdName, String.class);

// 通過Method的invoke方法執行setter方法

// 將config.getProperty(name)的值作為調用setter方法的參數

mtd.invoke(target, config.getProperty(name));

}

}

}

public Object getObject(String name) {

// 從objectPool中取出指定name對應的對象

return objectPool.get(name);

}

public static void main(String[] args) throws Exception {

ExtendedObjectPoolFactory epf = new ExtendedObjectPoolFactory();

epf.init("extObj.txt");

epf.initPool();

epf.initProperty();

System.out.println(epf.getObject("a"));

}

}

上面程序中 initProperty() 方法里的第一行粗體字代碼獲取目標類中包含一個 String 參數的 setter 方法,第二行粗體字代碼通過調用 Method 的 invoke() 方法來執行該 setter 方法,該方法執行完成后,就相當于執行了目標對象的 setter 方法。為上面程序提供如下配置文件。

a=javax.swing.JFrame

b=javax.swing.JLabel

#set the title of a

a%title=Test Title

上面配置文件中的 a%title 行表明希望調用a對象的 setTitle() 方法,調用該方法的參數值為 Test Title。編譯、運行上面的 ExtendedObjectPoolFactory.java 程序,可以看到輸出一個 JFrame 窗口,該窗口的標題為 Test Title。

提示:Spring 框架就是通過這種方式將成員變量值以及依賴對象等都放在配置文件中進行管理的,從而實現了較好的解耦。這也是 Spring 框架的 IOC 的秘密。

當通過 Method 的 invoke() 方法來調用對應的方法時,Java 會要求程序必須有調用該方法的權限。如果程序確實需要調用某個對象的 private 方法,則可以先調用 Method 對象的如下方法。

setAccessible(boolean flag):將 Method 對象的 accessible 設置為指定的布爾值。值為true,指示該 Method 在使用時應該取消 Java 語言的訪問權限檢查:值為false,則指示該 Method 在使用時要實施 Java 語言的訪問權限檢查。

注意:實際上,setAccessible() 方法并不屬于 Method,而是屬于它的父類 AccessibleObject。因此 Method、Constructor、Field 都可調用該方法,從而實現通過反射來調用 private 方法、private 構造器和成員變量,下一節將會讓讀者看到這種示例。也就是說,它們可以通過調用該方法來取消訪問權限檢查,通過反射即可訪問 private 成員。

訪問成員變量值

通過 Class 對象的 getFields() 或 getField() 方法可以獲取該類所包括的全部成員變量或指定成員變量。Field 提供了如下兩組方法來讀取或設置成員變量值。

getXxx(Object obj):獲取 obj 對象的該成員變量的值。此處的 Xxx 對應8種基本類型,如果該成員變量的類型是引用類型,則取消 get 后面的Xxx。

setXxx(Object obj, Xxx val):將 obj 對象的該成員變量設置成值。此處的 Xxx 對應8種基本類型,如果該成員變量的類型是引用類型,則取消 set 后面的Xxx。

使用這兩個方法可以隨意地訪問指定對象的所有成員變量,包括 private 修飾的成員變量。

class Person {

private String name;

private int age;

public String toString() {

return "Person[name:" + name + " , age:" + age + " ]";

}

}

public class FieldTest {

public static void main(String[] args) throws Exception {

// 創建一個Person對象

Person p = new Person();

// 獲取Person類對應的Class對象

Class personClazz = Person.class;

// 獲取Person的名為name的成員變量

// 使用getDeclaredField()方法表明可獲取各種訪問控制符的成員變量

Field nameField = personClazz.getDeclaredField("name");

// 設置通過反射訪問該成員變量時取消訪問權限檢查

nameField.setAccessible(true);

// 調用set()方法為p對象的name成員變量設置值

nameField.set(p, "Yeeku.H.Lee");

// 獲取Person類名為age的成員變量

Field ageField = personClazz.getDeclaredField("age");

// 設置通過反射訪問該成員變量時取消訪問權限檢查

ageField.setAccessible(true);

// 調用setInt()方法為p對象的age成員變量設置值

ageField.setInt(p, 30);

System.out.println(p);

}

}

上面程序中先定義了一個 Person 類,該類里包含兩個 private 成員變量:name 和 age,在通常情況下,這兩個成員變量只能在 Person 類里訪問。但本程序 FieldTest 的 main() 方法中6行粗體字代碼通過反射修改了 Person 對象的 name、age 兩個成員變量的值。

第一行粗體字代碼使用 getDeclaredField() 方法獲取了名為 name 的成員變量,注意此處不是使用 getField()方法,因為 getField() 方法只能獲取 public 訪問控制的成員變量,而 getDeclaredField() 方法則可以獲取所有的成員變量;第二行粗體字代碼則通過反射訪問該成員變量時不受訪問權限的控制;第三行粗體字代碼修改了 Person 對象的 name 成員變量的值。修改 Person 對象的 age 成員變量的值的方式與此完全相同。

編譯、運行上面程序,會看到如下輸出:

Person[name:Yeeku.H.Lee , age:30 ]

操作數組

在 java.lang.reflect 包下還提供了一個 Array 類,Array 對象可以代表所有的數組。程序可以通過使用 Array 來動態地創建數組,操作數組元素等。

Array 提供了如下幾類方法。

static Object newInstance(Class> componentType,int...length):創建一個具有指定的元素類型、指定維度的新數組。

static xxx getXxx(Object array, int index):返回 array 數組中第 index 個元素。其中是各種基本數據類型,如果數組元素是引用類型,則該方法變為 get(Object array, int index)。

static void setXxx(Object array, int index, xxx val):將 array 數組中第 index 個元素的值設為 val。其中 xxx 是各種基本數據類型,如果數組元素是引用類型,則該方法變成 set(Object array, int index, Object val)。

下面程序示范了如何使用 Array 來生成數組,為指定數組元素賦值,并獲取指定數組元素的方式。

public class ArrayTest1 {

public static void main(String args[]) {

try {

// 創建一個元素類型為String ,長度為10的數組

Object arr = Array.newInstance(String.class, 10);

// 依次為arr數組中index為5、6的元素賦值

Array.set(arr, 5, "瘋狂Java講義");

Array.set(arr, 6, "輕量級Java EE企業應用實戰");

// 依次取出arr數組中index為5、6的元素的值

Object book1 = Array.get(arr, 5);

Object book2 = Array.get(arr, 6);

// 輸出arr數組中index為5、6的元素

System.out.println(book1);

System.out.println(book2);

} catch (Throwable e) {

System.err.println(e);

}

}

}

上面程序中三行粗體字代碼分別是通過 Array 創建數組,為數組元素設置值,訪問數組元素的值的示例代碼,程序通過使用 Array 就可以動態地創建并操作數組。

下面程序比上面程序稍微復雜一點,下面程序使用 Array 類創建了一個三維數組。

public class ArrayTest2 {

public static void main(String args[]) {

/*

* 創建一個三維數組。 根據前面介紹數組時講的:三維數組也是一維數組, 是數組元素是二維數組的一維數組,

* 因此可以認為arr是長度為3的一維數組

*/

Object arr = Array.newInstance(String.class, 3, 4, 10);

// 獲取arr數組中index為2的元素,該元素應該是二維數組

Object arrObj = Array.get(arr, 2);

// 使用Array為二維數組的數組元素賦值。二維數組的數組元素是一維數組,

// 所以傳入Array的set()方法的第三個參數是一維數組。

Array.set(arrObj, 2, new String[] { "瘋狂Java講義", "輕量級Java EE企業應用實戰" });

// 獲取arrObj數組中index為3的元素,該元素應該是一維數組。

Object anArr = Array.get(arrObj, 3);

Array.set(anArr, 8, "瘋狂Android講義");

// 將arr強制類型轉換為三維數組

String[][][] cast = (String[][][]) arr;

// 獲取cast三維數組中指定元素的值

System.out.println(cast[2][3][8]);

System.out.println(cast[2][2][0]);

System.out.println(cast[2][2][1]);

}

}

上面程序的第一行粗體字代碼使用 Array 創建了一個三維數組,程序中較難理解的地方是第二段粗體字代碼部分,使用 Array 為 arrObj 的指定元素賦值,相當于為二維數組的元素賦值。由于二維數組的元素是一維數組,所以程序傳入的參數是一個一維數組對象。

運行上面程序,將看到 cast[2][3][8]、cast[2][2][0]、cast[2][2][1] 元素都有值,這些值就是剛才程序通過反射傳入的數組元素值。

以上就是java使用反射創建并操作對象的方法的詳細內容,更多關于JAVA 反射創建并操作對象的資料請關注腳本之家其它相關文章!

總結

以上是生活随笔為你收集整理的java 反射创建对象并赋值_java使用反射创建并操作对象的方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久yy| 免费在线你懂的 | 翔田千里一区二区三区av | 伊人伊色 | 国产女人18水真多18精品一级做 | 亚洲成人av在线播放 | 女儿朋友| 国产五区| 丝袜美腿av| 中文字幕码精品视频网站 | 欧美v在线 | 久国久产久精永久网页 | 一级片免费观看 | 成人综合区一区 | 91天天看 | 欧美性大战久久久久久久蜜桃 | 久久久亚洲一区二区三区 | 97福利社 | 亚洲最大色网站 | 91在线综合 | 精彩久久 | 欧美激情喷水 | 青青草在线观看视频 | 2025韩国大尺度电影 | 91一区视频 | 高清无码视频直接看 | 91重口味 | 日韩毛片大全 | 国产精品欧美精品 | 日韩高清av在线 | 欧美影院在线 | 成人国产精品免费观看动漫 | 狠狠操天天射 | 嫩草视频在线观看视频 | 亚洲情欲网 | 国产一区二区三区三州 | 大香伊人| 在线视频激情小说 | 人人天天夜夜 | 黑人巨大精品一区二区在线 | 免费视频久久 | 亚洲av首页在线 | 国产精品免费av一区二区 | 日韩中文字幕 | 天天躁日日摸久久久精品 | 大又大粗又爽又黄少妇毛片 | 亚洲精品乱码久久久久久蜜桃麻豆 | 猛1被调教成公厕尿便失禁网站 | 免费观看一区二区三区视频 | 亚洲熟伦熟女新五十路熟妇 | 日韩在线观看免费全 | 日韩国产小视频 | 草久免费视频 | 在线中文字幕播放 | 一区二区视 | 91久久精品一区 | 在线a网 | 久久桃花网| 久久美女免费视频 | 人人插人人看 | 超碰久草| 国产a国产片 | 免费av毛片 | 女女互磨互喷水高潮les呻吟 | 色播网址 | 韩国伦理片免费看 | 天干夜天干天天天爽视频 | 亚洲午夜天堂 | 中文永久免费观看 | 96视频在线观看 | 九九色播 | mm1313亚洲国产精品美女 | 男女啊啊啊视频 | 一级二级三级黄色片 | 久久人人爽天天玩人人妻精品 | 高清视频一区二区三区 | 国产嘿咻 | 亚洲午夜无码av毛片久久 | 免费网站污 | 91av视频免费观看 | av怡红院 | 致单身男女免费观看完整版 | 夫妻淫语绿帽对白 | 亚洲第一免费播放区 | 精品国产乱子伦 | 亚洲精品欧美日韩 | 亚洲精品中文字幕乱码无线 | 深夜av在线 | 精品少妇v888av | aa视频网站 | 性欧美一区二区 | 久久精品国产精品 | 中文字字幕在线中文 | 男人视频网 | 人妖天堂狠狠ts人妖天堂狠狠 | 亚洲一区二区国产精品 | 亚洲精品国产一区二区 | 无码精品一区二区免费 | 操操操操网 |