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