摘要:中的反射反射能夠分析類(lèi)所擁有的能力的程序稱(chēng)為反射。獲取類(lèi)的名稱(chēng)獲取類(lèi)的修飾符獲取類(lèi)所在的包獲取父類(lèi)的屬性獲取類(lèi)的構(gòu)造器等等獲得的構(gòu)造器的使用獲取構(gòu)造器有兩種方法。
Java中的反射
反射:能夠分析類(lèi)所擁有的能力的程序稱(chēng)為反射。
反射的作用當(dāng)我們?cè)谑褂靡粋€(gè)已有的類(lèi)的時(shí)候,在主代碼的main()方法中使用別的已有的類(lèi)的時(shí)候,如果被使用的類(lèi)發(fā)生了改變,那么導(dǎo)致我們的main()方法中也要修改大量的代碼,以適應(yīng)被使用的類(lèi)的修改。這個(gè)時(shí)候,如果在main()方法使用了反射(reflect),那么就可以通過(guò)被使用的類(lèi)的名字來(lái)獲取這個(gè)被使用的類(lèi)的所有情況(方法、Field等),這樣就不必修改我們的主程序了。只需在被使用類(lèi)的配置文件中寫(xiě)上被使用類(lèi)的名字,在mian()方法中通過(guò)讀取這個(gè)配置文件獲得這個(gè)被使用類(lèi)的名字即可通過(guò)反射的方法使用這個(gè)類(lèi)。即使修改了要使用的類(lèi)的名字或者實(shí)現(xiàn),所有的修改也只體現(xiàn)在這個(gè)類(lèi)的配置文件中,將需要修改的地方減至最少,提升了類(lèi)的可擴(kuò)展性。
反射作用使用示例:
被使用類(lèi)與使用類(lèi):
import java.io.*; interface eatable { public void eat(); } class person implements eatable { public void eat() { System.out.println("person EAT"); } } class animal implements eatable { public void eat() { System.out.println("animal EAT"); } } public class ClassTest { public static void main(String[] args)throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("file.txt")) )); Class className = Class.forName(br.readLine()); //使用了anima類(lèi) eatable ea= (eatable)className.newInstance(); ea.eat(); } }
被使用類(lèi)的配置文件:file.txt
animal
各種框架里面大量使用了反射,但是只對(duì)用戶暴露了類(lèi)名與該類(lèi)的配置文件,防止被修改。
Java類(lèi)的class屬性程序運(yùn)行的時(shí)候,每一個(gè)類(lèi)(如Person類(lèi))在加載的時(shí)候,JVM都會(huì)為這個(gè)類(lèi)創(chuàng)建一個(gè)static的class成員屬性,這個(gè)class屬性里面記載的都是這個(gè)程序里面所有Person類(lèi)對(duì)象的信息。
同時(shí)我們可以通過(guò)Person類(lèi)的class屬性獲得這個(gè)Person類(lèi)的所有情況,如:Person類(lèi)里面的所有方法對(duì)象,Person類(lèi)里面的所有屬性,Person類(lèi)里面的所有構(gòu)造方法對(duì)象。
這個(gè)class屬性的類(lèi)型就是Class.
獲取類(lèi)的Class對(duì)象。
Java中的所有類(lèi)型包括基本類(lèi)型(int, long, float等等),即使是數(shù)組都有與之關(guān)聯(lián)的Class類(lèi)的對(duì)象。
如果你在編譯期知道一個(gè)類(lèi)的名字的話,那么你可以使用如下的方式獲取一個(gè)類(lèi)的Class對(duì)象:
Class myObjectClass = MyObject.class;
如果你在編譯期不知道類(lèi)的名字,但是你可以在運(yùn)行期獲得到類(lèi)名的字符串,那么你則可以這么做來(lái)獲取Class對(duì)象:
String className = ... ;//在運(yùn)行期獲取的類(lèi)名字符串
Class class = Class.forName(className);
在使用Class.forName()方法時(shí),你必須提供一個(gè)類(lèi)的全名,這個(gè)全名包括類(lèi)所在的包的名字。例如MyObject類(lèi)位于com.jenkov.myapp包,那么他的全名就是com.jenkov.myapp.MyObject。
類(lèi)的class屬性的作用用于動(dòng)態(tài)獲取類(lèi)中的成員:
1. 可以獲取這個(gè)類(lèi)的所有方法對(duì)象(注意:Java中一切都是對(duì)象,包括方法,一個(gè)類(lèi)中的成員,即使連方法也是對(duì)象。) 可以通過(guò)這個(gè)方法對(duì)象來(lái)使這個(gè)方法被執(zhí)行,將一個(gè)類(lèi)對(duì)象作為方法對(duì)象的參數(shù)傳入即可。
2. 也可以獲取這個(gè)類(lèi)的所有成員。
3. 獲取類(lèi)的名稱(chēng)
4. 獲取類(lèi)的修飾符
5. 獲取類(lèi)所在的包
6. 獲取父類(lèi)的class屬性
7. 獲取類(lèi)的構(gòu)造器
等等
獲取構(gòu)造器有兩種方法。
獲取構(gòu)造器的參數(shù)
使用構(gòu)造器來(lái)創(chuàng)建類(lèi)對(duì)象
訪問(wèn)類(lèi)的私有變量即私有方法訪問(wèn)私有變量
要想獲取私有變量你可以調(diào)用Class.getDeclaredField(String name)方法或者Class.getDeclaredFields()方法。Class.getField(String name)和Class.getFields()只會(huì)返回公有的變量,無(wú)法獲取私有變量。下面例子定義了一個(gè)包含私有變量的類(lèi),在它下面是如何通過(guò)反射獲取私有變量的例子:
public class PrivateObject { private String privateString = null; public PrivateObject(String privateString) { this.privateString = privateString; } } PrivateObject privateObject = new PrivateObject("The Private Value"); Field privateStringField = PrivateObject.class. getDeclaredField("privateString"); privateStringField.setAccessible(true); String fieldValue = (String) privateStringField.get(privateObject); System.out.println("fieldValue = " + fieldValue);
這個(gè)例子會(huì)輸出”fieldValue = The Private Value”,The Private Value是PrivateObject實(shí)例的privateString私有變量的值,注意調(diào)用 PrivateObject.class.getDeclaredField(“privateString”)方法會(huì)返回一個(gè)私有變量,這個(gè)方法返回的變量是定義在PrivateObject類(lèi)中的而不是在它的父類(lèi)中定義的變量。 注意privateStringField.setAccessible(true)這行代碼,通過(guò)調(diào)用setAccessible()方法會(huì)關(guān)閉指定類(lèi)Field實(shí)例的反射訪問(wèn)檢查,這行代碼執(zhí)行之后不論是私有的、受保護(hù)的以及包訪問(wèn)的作用域,你都可以在任何地方訪問(wèn),即使你不在他的訪問(wèn)權(quán)限作用域之內(nèi)。但是你如果你用一般代碼來(lái)訪問(wèn)這些不在你權(quán)限作用域之內(nèi)的代碼依然是不可以的,在編譯的時(shí)候就會(huì)報(bào)錯(cuò)。
訪問(wèn)私有方法
訪問(wèn)一個(gè)私有方法你需要調(diào)用 Class.getDeclaredMethod(String name, Class[] parameterTypes)或者Class.getDeclaredMethods() 方法。 Class.getMethod(String name, Class[] parameterTypes)和Class.getMethods()方法,只會(huì)返回公有的方法,無(wú)法獲取私有方法。下面例子定義了一個(gè)包含私有方法的類(lèi),在它下面是如何通過(guò)反射獲取私有方法的例子:
public class PrivateObject { private String privateString = null; public PrivateObject(String privateString) { this.privateString = privateString; } private String getPrivateString(){ return this.privateString; } } PrivateObject privateObject = new PrivateObject("The Private Value"); Method privateStringMethod = PrivateObject.class. getDeclaredMethod("getPrivateString", null); privateStringMethod.setAccessible(true); String returnValue = (String) privateStringMethod.invoke(privateObject, null); System.out.println("returnValue = " + returnValue);
這個(gè)例子會(huì)輸出”returnValue = The Private Value”,The Private Value是PrivateObject實(shí)例的getPrivateString()方法的返回值。
PrivateObject.class.getDeclaredMethod(“privateString”)方法會(huì)返回一個(gè)私有方法,這個(gè)方法是定義在PrivateObject類(lèi)中的而不是在它的父類(lèi)中定義的。
同樣的,注意Method.setAcessible(true)這行代碼,通過(guò)調(diào)用setAccessible()方法會(huì)關(guān)閉指定類(lèi)的Method實(shí)例的反射訪問(wèn)檢查,這行代碼執(zhí)行之后不論是私有的、受保護(hù)的以及包訪問(wèn)的作用域,你都可以在任何地方訪問(wèn),即使你不在他的訪問(wèn)權(quán)限作用域之內(nèi)。但是你如果你用一般代碼來(lái)訪問(wèn)這些不在你權(quán)限作用域之內(nèi)的代碼依然是不可以的,在編譯的時(shí)候就會(huì)報(bào)錯(cuò)。
例如:在重寫(xiě)一個(gè)方法的時(shí)候,在方法上面加上@Override,在編譯階段就保證編譯成功。這就是注解(Anotation)的作用,這是和注釋不一樣的。
Anotation是一個(gè)接口,Override之類(lèi)的都是它的實(shí)現(xiàn)類(lèi)。
獲取注解對(duì)象只有一種方法:反射。
使用反射技術(shù)創(chuàng)建數(shù)組
int[] intArray = (int[]) Array.newInstance(int.class, 3);
這個(gè)例子創(chuàng)建一個(gè)int類(lèi)型的數(shù)組。Array.newInstance()方法的第一個(gè)參數(shù)表示了我們要?jiǎng)?chuàng)建一個(gè)什么類(lèi)型的數(shù)組。第二個(gè)參數(shù)表示了這個(gè)數(shù)組的空間是多大。
使用反射技術(shù)訪問(wèn)數(shù)組內(nèi)的內(nèi)容
具體可以使用Array.get(…)和Array.set(…)方法來(lái)訪問(wèn)數(shù)組內(nèi)的內(nèi)容。下面是一個(gè)例子:
int[] intArray = (int[]) Array.newInstance(int.class, 3);
Array.set(intArray, 0, 123);
Array.set(intArray, 1, 456);
Array.set(intArray, 2, 789);
System.out.println("intArray[0] = " + Array.get(intArray, 0));
System.out.println("intArray[1] = " + Array.get(intArray, 1));
System.out.println("intArray[2] = " + Array.get(intArray, 2));
獲取數(shù)組對(duì)象的class屬性
如果不通過(guò)反射的話你可以這樣來(lái)獲取數(shù)組的Class對(duì)象:
>
Class stringArrayClass = String[].class;
如果使用Class.forName()方法來(lái)獲取數(shù)組的Class對(duì)象則不是那么簡(jiǎn)單。比如你可以像這樣來(lái)獲得一個(gè)原生數(shù)據(jù)類(lèi)型(primitive)int數(shù)組的Class對(duì)象:
>
Class intArray = Class.forName("[I");
在JVM中字母I代表int類(lèi)型,左邊的‘[’代表我想要的是一個(gè)int類(lèi)型的數(shù)組,這個(gè)規(guī)則同樣適用于其他的原生數(shù)據(jù)類(lèi)型。
對(duì)于普通對(duì)象類(lèi)型的數(shù)組有一點(diǎn)細(xì)微的不同:
Class stringArrayClass = Class.forName("[Ljava.lang.String;");
注意‘[L’的右邊是類(lèi)名,類(lèi)名的右邊是一個(gè)‘;’符號(hào)。這個(gè)的含義是一個(gè)指定類(lèi)型的數(shù)組。
獲取普通原生數(shù)據(jù)類(lèi)型的class屬性
需要注意的是,你不能通過(guò)Class.forName()方法獲取一個(gè)原生數(shù)據(jù)類(lèi)型的Class對(duì)象。下面這兩個(gè)例子都會(huì)報(bào)ClassNotFoundException:
Class intClass1 = Class.forName("I");
Class intClass2 = Class.forName("int");
通常會(huì)用下面這個(gè)方法來(lái)獲取普通對(duì)象以及原生對(duì)象的Class對(duì)象:
public Class getClass(String className){
if("int" .equals(className)) return int.class;
if("long".equals(className)) return long.class;
...
return Class.forName(className);
}
一旦你獲取了類(lèi)型的Class對(duì)象,你就有辦法輕松的獲取到它的數(shù)組的Class對(duì)象,你可以通過(guò)指定的類(lèi)型創(chuàng)建一個(gè)空的數(shù)組,然后通過(guò)這個(gè)空的數(shù)組來(lái)獲取數(shù)組的Class對(duì)象。這樣做有點(diǎn)討巧,不過(guò)很有效。如下例:
Class theClass = getClass(theClassName); Class stringArrayClass = Array.newInstance(theClass, 0).getClass();
這是一個(gè)特別的方式來(lái)獲取指定類(lèi)型的指定數(shù)組的Class對(duì)象。無(wú)需使用類(lèi)名或其他方式來(lái)獲取這個(gè)Class對(duì)象。
為了確保Class對(duì)象是不是代表一個(gè)數(shù)組,你可以使用Class.isArray()方法來(lái)進(jìn)行校驗(yàn):
Class stringArrayClass = Array.newInstance(String.class, 0).getClass(); System.out.println("is array: " + stringArrayClass.isArray());
獲取數(shù)組的成員的class屬性
一旦你獲取了一個(gè)數(shù)組的class屬性,你就可以通過(guò)class.getComponentType()方法獲取這個(gè)數(shù)組的成員類(lèi)型。
成員類(lèi)型就是數(shù)組存儲(chǔ)的數(shù)據(jù)類(lèi)型。例如,數(shù)組int[]的成員類(lèi)型就是一個(gè)Class對(duì)象int.class。String[]的成員類(lèi)型就是java.lang.String類(lèi)的Class對(duì)象。
下面是一個(gè)訪問(wèn)數(shù)組成員的class屬性的例子:
String[] strings = new String[3];
Class stringArrayClass = strings.getClass();
Class stringArrayComponentType = stringArrayClass.getComponentType();
System.out.println(stringArrayComponentType);
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/64187.html
摘要:反射機(jī)制一結(jié)合官方通過(guò)編寫(xiě)的反射教程,復(fù)習(xí)一下反射的知識(shí)。反射的概念反射是一種在運(yùn)行時(shí)獲取以及修改應(yīng)用行為的一種工具。因?yàn)榉瓷湫枰獎(jiǎng)討B(tài)的解析類(lèi)的信息,相比于非反射使用的方式要慢。反射需要獲取一定的運(yùn)行時(shí)權(quán)限,在特定的安全環(huán)境下不一定存在。 Java反射機(jī)制(一) 結(jié)合Oracle官方通過(guò)JDK8編寫(xiě)的反射教程,復(fù)習(xí)一下反射的知識(shí)。結(jié)尾篇補(bǔ)一個(gè)小例子。 主要內(nèi)容 這次博客的主要內(nèi)容就是簡(jiǎn)...
摘要:反射非常強(qiáng)大和有用。另外,反射可以用在映射結(jié)果集的列名到對(duì)象的方法。本教程將深入介紹反射。本教程還將清除一些關(guān)于范型信息在運(yùn)行時(shí)可用性的認(rèn)知混淆。類(lèi)對(duì)象使用反射時(shí),起點(diǎn)通常是需要使用反射檢視的類(lèi)的對(duì)象。 Java反射可以在運(yùn)行時(shí)檢視類(lèi)、接口、屬性和方法,而無(wú)需在編譯時(shí)知道類(lèi)名、方法名等等。它也同樣使用反射支持實(shí)例化新的對(duì)象、調(diào)用方法和get/set屬性值。 Java反射非常強(qiáng)大和有用...
摘要:通過(guò)反射獲取帶參無(wú)返回值成員方法并使用設(shè)置安全檢查,訪問(wèn)私有構(gòu)造函數(shù)必須創(chuàng)建實(shí)例這種不行,注意和方法需要傳遞參數(shù)測(cè)試復(fù)制這個(gè)功能獲取私有方法,同樣注意和的區(qū)別賦予訪問(wèn)權(quán)限調(diào)用方法。 反射 目錄介紹 1.反射概述 1.1 反射概述 1.2 獲取class文件對(duì)象的三種方式 1.3 反射常用的方法介紹 1.4 反射的定義 1.5 反射的組成 1.6 反射的作用有哪些 2.反射的...
摘要:反射使用類(lèi)對(duì)象提供的基本元數(shù)據(jù),能從類(lèi)對(duì)象中找出方法或字段的名稱(chēng),然后獲取表示方法或字段的對(duì)象。常見(jiàn)的反射手段有反射和反射。以之前的反射為例其中指定了方法的返回類(lèi)型,其實(shí)不止如此。 Java反射機(jī)制主要提供了以下功能: 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類(lèi) 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類(lèi)的對(duì)象 在運(yùn)行時(shí)判斷任意一個(gè)類(lèi)所具有的成員變量和方法 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法 生成動(dòng)態(tài)代理 很多框架...
近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問(wèn)題,因?yàn)閷?shí)體類(lèi)中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對(duì)象賦值的過(guò)程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對(duì)象屬性賦值,借此機(jī)會(huì)也了解了反射的一些具體用法和使用場(chǎng)景,分以下兩點(diǎn)對(duì)反射進(jìn)行分析: 反射的優(yōu)勢(shì)和劣勢(shì) 反射的應(yīng)用場(chǎng)景 反射的優(yōu)勢(shì)和劣勢(shì) ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說(shuō)方法的調(diào)用是 Java 正確的打開(kāi)方式...
摘要:一反射機(jī)制概念程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類(lèi)型,這種語(yǔ)言稱(chēng)為動(dòng)態(tài)語(yǔ)言,如,是動(dòng)態(tài)語(yǔ)言顯然,,不是動(dòng)態(tài)語(yǔ)言,但是有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制。相關(guān)的為二獲取源頭重點(diǎn)打開(kāi)權(quán)限所有類(lèi)的對(duì)象其實(shí)都是的實(shí)例。 一、Java反射機(jī)制概念 程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類(lèi)型,這種語(yǔ)言稱(chēng)為動(dòng)態(tài)語(yǔ)言,如Python, Ruby是動(dòng)態(tài)語(yǔ)言;顯然C++,Java,C#不是動(dòng)態(tài)語(yǔ)言,但是JAVA有...
閱讀 2965·2021-11-17 09:33
閱讀 3753·2021-11-16 11:42
閱讀 3564·2021-10-26 09:50
閱讀 1489·2021-09-22 15:49
閱讀 3106·2021-08-10 09:44
閱讀 3785·2019-08-29 18:36
閱讀 4056·2019-08-29 16:43
閱讀 2330·2019-08-29 14:10