摘要:在的反射包中提供了三個(gè)類以及來(lái)分別描述屬性方法和構(gòu)造器。獲取構(gòu)造器獲取方法可以看到我們可以通過(guò)一個(gè)類的對(duì)象很輕松的獲取他的屬性構(gòu)造器以及方法信息。返冋一個(gè)用于描述構(gòu)造器名的字符串。
想要獲取更多文章可以訪問(wèn)我的博客?-?代碼無(wú)止境。
上周上班的時(shí)候解決一個(gè)需求,需要將一批數(shù)據(jù)導(dǎo)出到Excel。本來(lái)公司的中間件組已經(jīng)封裝好了使用POI生成Excel的工具方法,但是無(wú)奈產(chǎn)品的需求里面有個(gè)合并單元格的要求,工具類中找了半天也沒(méi)發(fā)現(xiàn)適用的方法,就只能自己擼起袖子干了。導(dǎo)出Excel的工具方法會(huì)少不了使用反射,但是反射這東西對(duì)于我這種寫(xiě)業(yè)務(wù)代碼的人來(lái)說(shuō)接觸比較少,所以就惡補(bǔ)了一下,寫(xiě)下這篇文章記錄一下。
什么是反射萬(wàn)物究其根,研究一樣新東西,首先我們需要了解它是什么,干什么用的。在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意一個(gè)方法和屬性;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為Java語(yǔ)言的反射機(jī)制。那么我們又能利用反射做什么呢?
在運(yùn)行時(shí)分析類。
在運(yùn)行時(shí)查看對(duì)象,我們還可以利用反射編寫(xiě)一個(gè)toString方法供所有類使用。
利用Method對(duì)象,在運(yùn)行時(shí)任意調(diào)用一個(gè)對(duì)象的方法。
那么本篇文章將圍繞者上面三個(gè)點(diǎn)來(lái)了解一下Java的反射機(jī)制。在開(kāi)始之前,我們先來(lái)介紹一下一個(gè)類,這個(gè)類是我們?cè)谑褂梅瓷涞倪^(guò)程中必不可少會(huì)使用到的一個(gè)類。
Class類在運(yùn)行時(shí),Java運(yùn)行時(shí)系統(tǒng)會(huì)為每一個(gè)對(duì)象都維護(hù)一個(gè)標(biāo)識(shí)這個(gè)對(duì)象類型的信息,而保存這些信息的類型就是Class類。我們可以通過(guò)對(duì)象的getClass()方法來(lái)獲取該對(duì)象對(duì)于的Class對(duì)象,就像下面這樣。
User user = new User(); Class c = user.getClass();
這個(gè)世界上的任何東西都有它存在的意義,那么我們可以用Class對(duì)象來(lái)干什么呢?我們最常使用Class來(lái)判斷一個(gè)對(duì)象是不是屬于某個(gè)類型,就像下面這樣:
User user = new User(); if (user.getClass() == User.class) { System.out.println("user is User"); }
當(dāng)然我們也經(jīng)常會(huì)使用Class類的getName()方法來(lái)獲取某個(gè)類的名稱。有寫(xiě)時(shí)候,我們還會(huì)利用它的newInstance()方法來(lái)獲取某個(gè)類型的實(shí)例(當(dāng)這類沒(méi)有提供共有的構(gòu)造方法時(shí))。
利用反射分析類分析一個(gè)類,無(wú)外乎就是查看這個(gè)類中的屬性、方法以及其構(gòu)造方法了。在Java的反射包中提供了三個(gè)類Field、Method以及Constructor來(lái)分別描述屬性、方法和構(gòu)造器。
下面我們就分別來(lái)看下,我們是如何通過(guò)反射機(jī)制來(lái)獲取一個(gè)類的這些信息的。
1.獲取屬性
User user = new User(); Class cl = user.getClass(); Field[] fields1 = cl.getFields(); Field[] fields2 = cl.getDeclaredFields();
可以看到我們可以利用getFields()和getDeclaredFields()兩個(gè)方法來(lái)獲取類中的屬性列表,那么這兩個(gè)方法有什么區(qū)別呢?區(qū)別就是前者只會(huì)返回類的共有成員信息,而后者這會(huì)返回類中所有的成員信息包括公有的、私有的、受保護(hù)的,但是不包括父類的成員信息。
2.獲取構(gòu)造器
Constructor[] constructors1 = cl.getConstructors(); Constructor[] constructors2 = cl.getDeclaredConstructors();
3.獲取方法
Method[] methods1 = cl.getMethods(); Method[] methods2 = cl.getDeclaredMethods();
可以看到我們可以通過(guò)一個(gè)類的Class對(duì)象很輕松的獲取他的屬性、構(gòu)造器以及方法信息。但是在Field、Constructor以及Method中又分別提供了哪些api呢?下面我們就一起來(lái)看下。
1.getName()方法,用來(lái)獲取對(duì)應(yīng)的名稱。同時(shí)存在于Field、Constructor以及Method類中。
2.getModifiers()方法來(lái)獲取前面的修飾符(public等),但是getModifiers()返回的是一個(gè)int值,我們可以通過(guò)Modifier.toString(int i)將其轉(zhuǎn)換成對(duì)應(yīng)的字符串。也同樣同時(shí)存在于Field、Constructor以及Method類中。
3.getParameterTypes()方法,用來(lái)獲取方法的參數(shù)類型數(shù)組。存在于Constructor以及Method類中
4.getReturnType()方法,用來(lái)獲取方法的返回類型。只存在于Method類中
有了這些api,我們就擁有了在運(yùn)行時(shí)分析一個(gè)類的能力,我們可以通過(guò)一個(gè)簡(jiǎn)單的小例子來(lái)實(shí)踐一下,我們可以編寫(xiě)一個(gè)方法來(lái)輸出一個(gè)類的完整信息,具體的實(shí)現(xiàn)會(huì)在文末給出,大家可以先自己嘗試一下。
利用反射查看對(duì)象有些時(shí)候呢,我們可能也需要反射去獲取對(duì)象中屬性的值,比如說(shuō)在導(dǎo)出Excel的時(shí)候,我們只知道列所對(duì)應(yīng)屬性的字段名稱,然后我們需要通過(guò)反射獲取它的值,然后把它寫(xiě)到Excel中。那么這節(jié)內(nèi)容就一起來(lái)看下如何利用Java的反射機(jī)制來(lái)分析對(duì)象。
User user = new User(1,"itweknow"); Class cl = user.getClass(); Field userName = cl.getDeclaredField("userName"); Object value = userName.get(user);
就像上面的代碼一樣,我們可以使用Field類中提供的get(Object obj)方法來(lái)獲取屬性的值,對(duì)于基礎(chǔ)類型還提供了特定的get方法,比如getDouble()。但是如果上面的userName是個(gè)私有屬性的話,get()方法肯定會(huì)拋出IllegalAccessException的異常。這是時(shí)候我們需要使用setAccessible()方法覆蓋安全管理器的訪問(wèn)控制。
User user = new User(1,"itweknow"); Class cl = user.getClass(); Field userName = cl.getDeclaredField("userName"); userName.setAccessible(true); Object value = userName.get(user);
setAccessible()方法在Field、Method、Constructor類中都有提供。與get()方法呼應(yīng),Field還提供了set()方法用來(lái)給屬性設(shè)置值。
利用反射調(diào)用任何方法在Method類中提供了invoke()方法來(lái)調(diào)用,當(dāng)前Method對(duì)象所包裝的方法。invoke()方法的定義如下:
Object invoke(Object obj, Object... args)
第一個(gè)參數(shù)是調(diào)用這個(gè)方法的對(duì)象,第二個(gè)參數(shù)是該方法的參數(shù),是一個(gè)數(shù)組的形式。下面我們就來(lái)看下如何利用反射來(lái)調(diào)用User類中的sayHello()方法吧。
Method sayHelloMethod = cl.getDeclaredMethod("sayHello", String.class); sayHelloMethod.setAccessible(true); sayHelloMethod.invoke(user, "Reflect");
看上面的代碼我們通過(guò)getDeclaredMethod()方法來(lái)獲取了一個(gè)名為sayHello的私有方法(PS:如果是公有方法的話直接使用getMethod()方法就可以了),同樣對(duì)于私有方法,我們需要修改它的訪問(wèn)控制才能順利調(diào)用。
API整理上面的章節(jié)中提到了不少Java反射機(jī)制中提供的Api,下面是我整理的一些常用的反射Api,大家可以參考一下。
1.Class類
Api | 描述 |
---|---|
forName() | 返回指定類名的Class對(duì)象 |
newInstance() | 返回一個(gè)這個(gè)類的新實(shí)例 |
getFields() | 返回這個(gè)類所有的公有屬性 |
getDeclaredField() | 返回這個(gè)類所有的屬性(包含公有、私有、受保護(hù)) |
getMethods() | 返回這個(gè)類下所有的共有方法 |
getDeclaredMethods() | 返回這個(gè)類所有的方法(包含公有、私有、受保護(hù)) |
getConstructors() | 返回這個(gè)類所有公有的構(gòu)造器 |
getDeclaredConstructors() | 返回這個(gè)類所有的構(gòu)造器(包含公有、私有、受保護(hù)) |
getField() & getDeclaredField() | 返回這個(gè)類中指定名稱的屬性 |
getMethod() & getDeclaredMethod() | 返回指定名稱和參數(shù)的方法 |
cl.getConstructor() & cl.getDeclaredConstructor() | 獲取指定參數(shù)的構(gòu)造器 |
2.Field類
Api | 描述 |
---|---|
getModifiers() | 返回一個(gè)用于描述屬性的修飾符的整型數(shù)值。使用 Modifier類中的toString()方法將其轉(zhuǎn)為字符串。 |
getName() | 返冋一個(gè)用于描述屬性名的字符串。 |
3.Method類
Api | 描述 |
---|---|
getModifiers() | 返回一個(gè)用于描述方法的修飾符的整型數(shù)值。使用 Modifier類中的toString()方法將其轉(zhuǎn)為字符串。 |
getName() | 返冋一個(gè)用于描述方法名的字符串。 |
getParameterTypes() | 返回一個(gè)用于描述參數(shù)類型的Class對(duì)象數(shù)組。 |
getReturnType() | 返回一個(gè)用于描述返H類型的Class對(duì)象。 |
invoke() | 調(diào)用這個(gè)對(duì)象所描述的方法, 傳遞給定參數(shù),并返回方法的返回值。 |
4.Constructor類
Api | 描述 |
---|---|
getModifiers() | 返回一個(gè)用于描述構(gòu)造器的修飾符的整型數(shù)值。使用 Modifier類中的toString()方法將其轉(zhuǎn)為字符串。 |
getName() | 返冋一個(gè)用于描述構(gòu)造器名的字符串。 |
getParameterTypes() | 返回一個(gè)用于描述參數(shù)類型的Class對(duì)象數(shù)組。 |
5.AccessibleObject類
Api | 描述 |
---|---|
setAccessible(boolean flag) | 為反射對(duì)象設(shè)置可訪問(wèn)標(biāo)志。flag 為 true 表明屏蔽 Java 語(yǔ)言的訪問(wèn)檢查,使得對(duì)象的私有屬性也可以被査詢和設(shè)置。 |
isAccessible() | 返回反射對(duì)象的可訪問(wèn)標(biāo)志的值。 |
這篇文章主要和大家一起了解了一下Java的反射機(jī)制,以及在反射包下Field、Method、Constructor三個(gè)類所提供的api。在利用反射分析類小節(jié)中,我提到了使用反射打印類的完整信息,具體的實(shí)現(xiàn)代碼點(diǎn)擊這里獲取。希望這篇文章能夠?qū)Υ蠹矣兴鶐椭?。最后,如果你喜歡這篇文章的話歡迎在Github源碼項(xiàng)目點(diǎn)個(gè)Star。
PS:學(xué)習(xí)不止,碼不停蹄!如果您喜歡我的文章,就關(guān)注我吧!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75633.html
Java學(xué)習(xí)打卡:第十八天 內(nèi)容導(dǎo)航 Java學(xué)習(xí)打卡:第十八天內(nèi)容管理基礎(chǔ)問(wèn)題(一定不要忘記)Java對(duì)象清除機(jī)制(垃圾處理機(jī)制)什么樣的對(duì)象是垃圾呢?那一個(gè)對(duì)象成為垃圾有哪幾種情況?一個(gè)良好習(xí)慣 枚舉類型嵌套枚舉類型實(shí)例----交通信號(hào)燈枚舉類型的方法帶參數(shù)的枚舉類型的枚舉常量? 博主的話 Java養(yǎng)成計(jì)劃(打卡第18天) JAVA SE(夯實(shí)基...
摘要:本文是作者自己對(duì)中線程的狀態(tài)線程間協(xié)作相關(guān)使用的理解與總結(jié),不對(duì)之處,望指出,共勉。當(dāng)中的的數(shù)目而不是已占用的位置數(shù)大于集合番一文通版集合番一文通版垃圾回收機(jī)制講得很透徹,深入淺出。 一小時(shí)搞明白自定義注解 Annotation(注解)就是 Java 提供了一種元程序中的元素關(guān)聯(lián)任何信息和著任何元數(shù)據(jù)(metadata)的途徑和方法。Annotion(注解) 是一個(gè)接口,程序可以通過(guò)...
摘要:公司始于名為的平臺(tái)即服務(wù)供應(yīng)商??缍鄠€(gè)機(jī)器之間協(xié)調(diào)這些容器需要額外的工具,這稱之為容器編排。的核心優(yōu)勢(shì)是為應(yīng)用程序開(kāi)發(fā)人員提供了用于編排無(wú)狀態(tài)容器的強(qiáng)大工具。有無(wú)數(shù)的文章都在討論和比較Docker、Kubernetes 以及Mesos。如果你是初學(xué)者,那么你可能會(huì)認(rèn)為這三個(gè)開(kāi)源項(xiàng)目正為了稱霸容器界而殊死搏斗。雖然這三種技術(shù)都使得使用容器部署、管理和伸縮應(yīng)用成為可能,但實(shí)際上它們各自解決了不同...
摘要:最大傳輸距離是米,最大傳輸速度為,支持與頻段??梢詫?shí)現(xiàn)一對(duì)一,以及一對(duì)多。簡(jiǎn)單而安全的連接設(shè)備采用簡(jiǎn)化了在設(shè)備之間創(chuàng)建安全連接的過(guò)程。用戶可以按下任一設(shè)備上的按鈕,也可以輸入碼即設(shè)備顯示的碼,輕松創(chuàng)建安全連接。 ...
摘要:月底了,又到了我們總結(jié)這一個(gè)月技術(shù)干貨的時(shí)候了,又到了我們給粉絲免費(fèi)送書(shū)的日子了。 月底了,又到了我們總結(jié)這一個(gè)月 Java 技術(shù)干貨的時(shí)候了,又到了我們給粉絲免費(fèi)送書(shū)的日子了。 7 月份干貨總結(jié) Oracle 發(fā)布了一個(gè)全棧虛擬機(jī) GraalVM 一文帶你深入拆解 Java 虛擬機(jī) 圖文帶你了解 8 大排序算法 Spring Boot 2.x 新特性總結(jié)及遷移指南 Spring B...
閱讀 1338·2021-09-04 16:40
閱讀 3464·2021-07-28 00:13
閱讀 2889·2019-08-30 11:19
閱讀 2623·2019-08-29 12:29
閱讀 3176·2019-08-29 12:24
閱讀 1131·2019-08-26 13:28
閱讀 2404·2019-08-26 12:01
閱讀 3455·2019-08-26 11:35