欧美成人高清,97精品国产福利一区二区三区,аⅴ资源天堂资源库在线,色999日韩自偷自拍美女

到底什么是反射?反射究竟能用來干什么?(到底什么是反射-反射究竟能用來干什么呢)

到底什么是反射?反射究竟能用來干什么?(到底什么是反射-反射究竟能用來干什么呢)

反射,顧名思義,它是一種逆向的操作。就好像人在照鏡子的時候,正是由于光的反射,才能看到鏡子中的自己。而在Java中,反射功能就好比是一面鏡子,通過它,我們可以在程序運行過程中看到Class以及對象的相關信息。

在以往的經驗中,當我們需要完成某些操作,往往是在編譯之前完成,比如根據創建對象、讀取屬性、設置屬性;我們把這些程序編寫完之后編譯器會將之編譯為class文件,然后直接在虛擬機中運行就可以了,大部分情況確實是這樣,這也是為什么Java是"靜態語言"。

但是我們卻可以通過反射來完成在動態語言中才能做到的一些操作,比如首先第一步,通過反射獲取某個.class文件的結構信息。

示例如下:

/** * 蝙蝠俠 */public class Batman { public Batman(String name,int age,String power){ this.name = name; this.age = age; this.power = power; } //蝙蝠俠的名字 private String name; //蝙蝠俠的年齡 private int age; //蝙蝠俠的超能力 private String power; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPower() { return power; } public void setPower(String power) { this.power = power; } /** 跟小貓談戀愛 */ private void beInLove(){ System.out.println("蝙蝠俠正在跟小貓談戀愛"); } /** 教訓小丑 */ public void work(){ System.out.println("蝙蝠俠正在教訓小丑"); } private void workWithGordon(String name){ System.out.printf("蝙蝠俠正在和%s一起教訓小丑",name); }}復制代碼

//測試類public class ReflectTest { public static void main(String[] args) { Class cls = Batman.class; //1.獲取class中的所有屬性,包括全局屬性和局部屬性 Field[] fields = cls.getDeclaredFields(); System.out.println("屬性:"); for (Field f : fields) { System.out.println(f); } System.out.println("方法:"); //獲取class中的所有方法 Method[] mets = cls.getDeclaredMethods(); for (Method met : mets) { System.out.println(met); } System.out.println("構造器:"); //獲取class中的所有構造器 Constructor[] cons = cls.getDeclaredConstructors(); for (Constructor c : cons) { System.out.println(c); } }}復制代碼

運行結果:
屬性:
private java.lang.String day2.demo2.Batman.name private int day2.demo2.Batman.age private java.lang.String day2.demo2.Batman.power
方法:
public int day2.demo2.Batman.getAge() public void day2.demo2.Batman.setAge(int) public java.lang.String day2.demo2.Batman.getPower() public void day2.demo2.Batman.setPower(java.lang.String) public java.lang.String day2.demo2.Batman.getName() public void day2.demo2.Batman.setName(java.lang.String)
構造器:
public day2.demo2.Batman(java.lang.String,int,java.lang.String)

java程序在運行時,虛擬機在加載類時,會為這個類創建一個Class對象,用來表示這個類的信息??梢酝ㄟ^類名.class、Class.forName("類名")、Object.getClass等方式獲取到一個Class對象,這個對象記錄了類的信息,通過它可以逆向獲取類的結構。

在示例中,通過Class對象中方法的調用,獲取了Batman類中的所有屬性、方法、構造器,但是反射的功能遠不止于此,比如通過上述三個方法獲取到的Field、Method、Constructor數組對象完成進一步的操作:

public class ReflectTest { public static void main(String[] args) { Class cls = Batman.class; Field[] fields = cls.getDeclaredFields(); System.out.println("屬性:"); System.out.println("訪問修飾符:" Modifier.toString(fields[0].getModifiers())); System.out.println("是否靜態的:" Modifier.isStatic(fields[0].getModifiers())); System.out.println("是否為public:" Modifier.isPublic(fields[0].getModifiers())); System.out.println("是否常量:" Modifier.isFinal(fields[0].getModifiers())); System.out.println("方法:"); Method[] mets = cls.getDeclaredMethods(); System.out.println("是否為本地方法:" Modifier.isNative(mets[0].getModifiers())); System.out.println("是否為抽象方法:" Modifier.isAbstract(mets[0].getModifiers())); System.out.println("是否為接口:" Modifier.isInterface(mets[0].getModifiers())); System.out.println("是否線程同步:" Modifier.isSynchronized(mets[0].getModifiers())); System.out.println("構造器:"); Constructor[] cons = cls.getDeclaredConstructors(); System.out.println("是否公有:" Modifier.isPublic(cons[0].getModifiers())); /** * ... * */ }}復制代碼

以上這些都是直接對Class類的操作,其實java反射也同樣支持對運行中的對象的操作,甚至可以修改對象中屬性的值。

示例代碼:

public class ReflectTest { public static void main(String[] args) throws IllegalAccessException { Batman batman = new Batman("布魯斯韋恩",27,"有錢"); Class cls = batman.getClass(); Field[] fields = cls.getDeclaredFields(); /**獲取第一個屬性name的值,由于是private屬性, 所以會報IllegalAccessException異常,很顯然是與權限有關*/ try { var name = fields[0].get(batman); System.out.println(name); }catch (IllegalAccessException e){ //這里通過一個方法設置可訪問對象的可訪問標志 fields[0].setAccessible(true); var name = fields[0].get(batman); System.out.println(name); } //但是這里設置的只是數組中第一個屬性的訪問權限,下面這句話依然會報錯 try { var name = fields[1].get(batman); System.out.println(name); }catch (IllegalAccessException e){ //所以通過下面的方法對整個數組對象的訪問權限進行設置 AccessibleObject.setAccessible(fields,true); var age = fields[1].get(batman); var power = fields[2].get(batman); System.out.println(age); System.out.println(power); } //修改fields[2]的值 fields[2].set(batman,"哥譚首富"); System.out.println("超能力:" batman.getPower()); }}復制代碼

運行結果:
布魯斯韋恩
27
有錢
超能力:哥譚首富

通過調用對象的getClass()方法獲取這個類唯一的Class對象,再通過獲取到field對象的get(obj)方法獲取到這個field的值(當然如果屬性是私有的,還需要使用setAccessible方法設置訪問標志),并且不僅可以獲取,還能通過其set(obj,val)方法重新設置這個屬性的值。而這一切都是在程序運行期間完成的,成功的通過反射修改了對象中的屬性。

至此,已經實現了通過反射來查看類的信息、對象的屬性以及設置對象的屬性。那么如何通過反射來調用方法以及構造器呢?

示例代碼:

public class ReflectTest { public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, InstantiationException { Class cls = Batman.class; //通過反射調用構造器創建蝙蝠俠對象 Batman batman = (Batman) cls.getDeclaredConstructor(String.class,int.class,String.class).newInstance("蝙蝠俠", 27, "有錢"); Method method = cls.getDeclaredMethod("beInLove"); //因為beInLove()方法是私有的,所以需要設置以下權限 method.setAccessible(true); method.invoke(batman); Method work = cls.getDeclaredMethod("work"); //work方法不是private的,不需要設置權限 work.invoke(batman); //調用帶參數的方法 Method workWithGordon = cls.getDeclaredMethod("workWithGordon", String.class); //私有方法依然要設置權限 workWithGordon.setAccessible(true); workWithGordon.invoke(batman,"Gordon"); }}復制代碼

至此,就完成了方法及構造方法的調用。需要注意的是,若調用了一個帶返回值的方法,如果返回值類型是基本類型,invoke方法會返回其包裝類型,如int返回Integer、double返回Double。

另外,java.lang.reflect包中還提供了一個很好用的類Array,ArrayList中的數組擴容就使用到了這個類。

示例代碼:

public class ReflectTest { public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, InstantiationException { //假如我想創建一個數組 String[] strs = {"bruce","jack","jerry"}; strs = (String[]) copyOf(strs,10); } //現在我想寫一個方法來為泛型數組擴容 public static Object[] CopyOf(Object[] obj,int nlength){ var newArray = new Object[nlength]; System.arraycopy(obj,0,newArray,0,Math.min(obj.length,nlength)); return newArray; }}復制代碼

運行結果:Exception in thread "main" java.lang.ClassCastException

這段代碼看起來好像沒有問題,通過Object超類接收任意類型的數組。但是有一個細節問題,當創建一個數組然后將其轉為Object[],再把它從Object[]轉回來是沒有問題的,但是如果直接創建一個Object[]轉成目標類型的數組是會出錯的。所以上述代碼無法完成泛型數組的擴容。

現在對代碼做一些改進,示例代碼:

public class ReflectTest { public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, InstantiationException { //假如我想創建一個數組 String[] strs = {"bruce","jack","jerry"}; strs = (String[]) CopyOf(strs,10); System.out.println(strs.length); } //現在我想寫一個方法來為泛型數組擴容 public static Object CopyOf(Object obj,int nlength){ Class cls = obj.getClass(); if(!cls.isArray()) return null; //獲取數組的類型 Class type = cls.getComponentType(); //獲取數組的長度 int length = Array.getLength(obj); //通過Array.newInstance創建一個泛型數組,類型通過參數指定 Object newArray = Array.newInstance(type,nlength); System.arraycopy(obj,0,newArray,0,Math.min(length,nlength)); return newArray; }}復制代碼

運行結果:10

這次程序成功運行,并且成功為數組擴容。最主要的原因是代碼中的關鍵方法,Array類的靜態方法newInstance,這個方法能夠返回一個有給定類型,給定大小的新數組,而不是一個簡單的Object[]。

總結:反射機制可以在運行時查看、操作字段和方法。但是不應該濫用反射,因為反射在編譯階段無法查找出錯誤,如果存在問題,往往到了運行時才會發現。JVM無法對反射的相關代碼做優化,所以效率相對低。并且反射可能導致程序不安全。

作者:現在沒有牛仔了
鏈接:https://juejin.cn/post/7228967103349080120

版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至89291810@qq.com舉報,一經查實,本站將立刻刪除。
(0)
上一篇 2024年4月24日 下午2:05
下一篇 2024年4月24日 下午2:11

相關推薦

  • 孩子網癮如何教育

    孩子網癮如何教育 隨著互聯網的普及,越來越多的人開始沉迷于網絡世界中。其中,孩子網癮的問題也越來越普遍。孩子網癮不僅會對身心健康造成負面影響,還會對他們的學習和成長產生負面影響。因…

    教育百科 2024年8月15日
  • 藝考升有什么用 藝考升怎么報名

    藝考升有什么用? 藝考升是指通過藝考考試進入大學的學生,需要通過專業考試來證明自己的專業能力和素質。對于想要進入藝術領域的學生來說,藝考升是一個重要的選擇。 藝考升的好處在于,可以…

    教育百科 2024年4月27日
  • 不上學愿意干活文案

    不上學,你愿意干活嗎? 近年來,隨著經濟的發展和社會進步,越來越多的年輕人開始意識到,只有通過自己的努力和奮斗,才能實現自己的人生價值和夢想。然而,對于有些年輕人來說,上學可能是他…

    教育百科 2025年7月13日
  • 濰坊學院2025分數線

    濰坊學院2025分數線 隨著高考的結束,許多學生和家長都在關注著濰坊學院的分數線。作為一所知名的高等教育機構,濰坊學院在各個領域都有著卓越的成績。因此,濰坊學院的分數線也是備受關注…

    教育百科 2024年11月26日
  • 休學沒到時間可以復學嗎(不到休學時間可以復學嗎)

    不到休學時間可以復學嗎? 休學是指學生暫停學業一段時間,用于休息、治療或參加社會實踐等活動。在許多國家和地區,學生休學的時間長度和方式都有所不同。通常情況下,休學時間的長度和學生的…

    教育百科 2024年6月29日
  • 網癮表現大全圖

    網癮表現大全圖 網癮是一種嚴重的社會問題,指人們沉迷于網絡活動,影響正常的生活和工作。網癮的癥狀和行為有很多種,下面將詳細介紹一些常見的表現。 1. 社交焦慮 網癮者常常因為網絡上…

    教育百科 2025年3月8日
  • 農村初中生嚴重的輟學問題(農村初中生輟學原因)

    農村初中生輟學原因 在中國農村地區,初中生輟學現象是一種常見的問題。盡管中國政府一直在采取措施來減少輟學率,但輟學問題仍然存在。在這篇文章中,我們將探討一些可能導致農村初中生輟學的…

    教育百科 2024年8月29日
  • 休學后能干什么職業(休學后能干什么)

    休學后能干什么 休學是一種重要的決策,可以幫助人們更好地管理時間和恢復身心健康。當人們決定休學時,他們可能感到困惑和不安,因為他們不知道休學后能做些什么。但是,一旦休學開始,就可以…

    教育百科 2024年5月9日
  • 不上學的兒童

    不上學的兒童 在中國,有許多兒童不上學。這些兒童可能因為他們的家庭情況, 或者因為他們自己的原因而不愿意上學。然而, 這種情況正在發生變化,隨著教育的普及和人們對教育的重視,越來越…

    教育百科 2025年4月21日
  • 弟弟厭學哥哥受影響

    弟弟厭學哥哥受影響,這是一個普遍的現象。在當今這個信息爆炸的時代,人們的生活變得越來越快節奏,壓力也越來越大。在這樣的環境下,許多人開始表現出各種情緒和行為問題,包括厭學。 對于我…

    教育百科 2025年3月1日

發表回復

您的郵箱地址不會被公開。 必填項已用 * 標注

主站蜘蛛池模板: 平定县| 革吉县| 江孜县| 调兵山市| 赤壁市| 乌兰察布市| 南溪县| 苏尼特右旗| 岱山县| 丽江市| 高青县| 阳信县| 河曲县| 兴隆县| 巴东县| 漳浦县| 姜堰市| 永德县| 建湖县| 永康市| 郸城县| 治县。| 高尔夫| 灵武市| 南投县| 宝应县| 夏河县| 鹰潭市| 铁力市| 牙克石市| 山丹县| 金坛市| 长乐市| 皋兰县| 射阳县| 阿拉善盟| 繁峙县| 安多县| 龙州县| 嘉禾县| 佳木斯市|