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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

《重学Java系列》之 反射(上)

發布時間:2024/1/18 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《重学Java系列》之 反射(上) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

不詩意的女程序媛不是好廚師~
轉載請注明出處,From李詩雨—https://blog.csdn.net/cjm2484836553/article/details/103350829】


《重學Java系列》之 反射(上)

  • 1.反射是什么?
  • 2.了解Class類
      • (1). Class類是什么?
      • (2). 獲取Class對象的3種方式
      • (3). Class類的常用方法
  • 3.反射的基本使用
      • (1).Constructor的基本使用
      • (2).Field的基本使用
      • (3).Method的基本使用
      • 小結與回顧

今天我們來學習學習反射,如果單純講反射的使用的話,其實一點也不復雜,我們只需要對照相應的API進行調用就可以了。但是要想對反射有較深層的認識和感悟,那就需要我們多看源碼。從真實的實戰中,我們才能體會其精髓。

所以,對于反射的學習我將分為上、中、下 3篇來總結。上篇講思維導圖中的前三點:反射是什么,Class類 和 反射的基本使用。中篇從動態代理的源碼中去體會反射,下篇從Retrofit源碼中再去體會反射。如此步步深入才能學到點東西。

今天講的是反射基礎,但是不要小瞧基礎哦,沒有基礎什么都白搭。話不多說,就讓我們開始吧~ ?

1.反射是什么?

說到反射,可能大家即陌生又熟悉。為什么這么說呢?
其實,反射在我們自己平時的開發過程中用到的并不多,因此它是陌生的。但是,在我們使用到的很多框架代碼中,一旦你要去閱讀他們的源碼,就會經常發現反射的身影,所以說它又是十分熟悉的。

那到底什么是反射呢?

反射就是在運行時才知道要操作的類是什么,并且可以在運行時獲取類的完整構造,并調用對應的方法。

這么官方的解釋是不是聽著還有點不太明白?沒事,我再來換種方法跟大家說。

咱們先不說反射,咱們來先說 【正】

大家回憶一下,【正】常的 我們怎么來實例化一個對象?
是不是通過 new,直接new一個對象出來,然后我就可訪問類的成員、調用類的方法了。

//實例化對象的標準用法,也就是所謂的【正】Person person=new Person("夏天",18);person.say("我是男神~");

【反】 射 就不一樣了,它是一開始并不知道我要初始化的類是什么?既然都不知道類是什么,那當然不能用 new 關鍵字來 正面的 直接的創建對象了。那我們該怎么辦呢?這種情況下我們就可以使用 JDK 提供的反射 API 進行反射調用。

//反射的使用 【反】Class personClass = Person.class;//要先獲取對應的Class對象Person reflePerson=(Person)personClass.newInstance();//通過class得到類的實例reflePerson.say("哈哈哈哈哈哈"); //然后才可以對對象進行其他操作

這個時候你是不是會有疑問:
我們平時寫代碼都知道是什么類啊,直接new個對象出來就好了。什么時候才會出現不知道new的是什么類呢?

你還別說, 反射在我們平時自己代碼中還真的基本用不到,它是在我們寫框架代碼的時候才會用到。如果是框架的開發人員,或者是在我們閱讀源碼的時候那反射就用的多了。

大家在用Retrofit網絡請求的框架的時候,有沒有想過:這個框架它在創建的時候,它是怎么知道將來我們的調用者會創建什么樣的類呢?他顯然是不知道的。那它怎么來new出我們調用者所需要的對象呢?這里我們就需要用到反射了。

所以反射的定義我這么這個時候再看一下,是不是就明白了許多呢:
反射是在運行時才知道要操作的類是什么,并且在運行時來獲取類的完整構造,并調用對應的方法

Reflection(反射) 是Java被視為動態語言的關鍵,反射機制允許程序在執行期借助于Reflection API取得任何類的內部信息,并能直接操作任意對象的內部屬性及方法

我們來歸納一下Java反射機制主要提供的功能

  • 運行時構造任意一個類的對象
  • 運行時獲取任意一個類所具有的成員變量和方法
  • 運行時調用任意一個對象的方法(屬性)

雖然我說的比較多,但相信經過這樣的反復說說說之后,你看一遍就可以懂了。

大家都知道Java 是一門面向對象的語言。在面向對象的世界里,萬事萬物皆對象。
我就又要問問大家了:既然萬事萬物皆對象,那我們寫的每一個類(比如說Person類),是不是應該也是對象呀。那它又是誰的對象呢?
答案是:它是Class類的對象。

好下面我們就來說說Class類。

2.了解Class類

(1). Class類是什么?

上面我們說了,我們寫的每一個類都可以看成一個對象,是java.lang.Class 類的對象。

那么Class到底是什么呢?
Class它是一個類它封裝了當前的類里面所包括的所有信息

一個類有哪些信息呢?
一個類中有屬性,方法,構造器等。
比如說有一個Person類,一個Fruit類,一個Animal類,這些都是不同的類,現在我們需要一個類,用來描述這些類,這就是Class。所以Class是用來描述類的類。

你可以這樣理解:Class類是一個對象照鏡子的結果,對象可以看到自己有哪些屬性,方法,構造器,實現了哪些接口等等。

對于每個類而言,JRE 都為其保留一個不變的 Class 類型的對象。一個 Class 對象包含了特定某個類的有關信息。

而且大家需要知道:一個類(而不是一個對象)在 JVM 中只會有一個Class實例。
我們可以new出這個類的很多個對象,但是這個類在JDK中只會有一個Class對象。
比如說:一個Person類,它可以new出很多個對象。

Person p1=new Person(); Person p2=new Person(); Person p3=new Person();

但是Person類對應的Class類的實例只有唯一一個。

(2). 獲取Class對象的3種方式

那么,我們要怎么樣才能獲取到Class對象呢?
這里有3種方式:

  • 方式1:通過類名獲取 --> 類名.class
  • 方式2:通過對象獲取 --> 對象名.getClass()
  • 方式3:通過全類名獲取 --> Class.forName(全類名,即包名+類名)
    以Person類為例:
//獲取對應的Class對象(有3種方式)Class personClass = Person.class;//方式1:通過類名獲取 --> 類名.classClass personClass2 = person.getClass();//方式2:通過對象獲取 --> 對象名.getClass()Class personClass3=Class.forName("reflect.Person"); //方式3:通過全類名獲取 --> Class.forName(全類名) 可能會出現“ClassNotFoundException”,必須對其進行捕獲或聲明以便拋出

(3). Class類的常用方法

3.反射的基本使用

上面我們已經知道了如何拿到class對象。
但是純粹的拿到class對象,其實是沒有什么實際含義的,我們真正的目的是為了能夠設置它的屬性,調用它的方法。

那我們如何去獲取和修改它的屬性、調用它的方法呢?
其實像構造器,屬性,方法這些信息在Java中都有對應的類來表示。

下面就讓我們分別來看看該怎么用:

首先我們定義一個Person類:

/*** @author shiyu* @create 2019-12-02 9:50*/ public class Person {//私有字段private String name;private int age;//公有字段public String sex;//無參構造方法public Person() {}//有參構造方法public Person(String name, int age) {this.name = name;this.age = age;}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 void say(String message){System.out.println(message);}//普通私有方法private void secret(){System.out.println("我是Person的私有方法");} }

讓我們來提取一下Person類的信息:

(1).Constructor的基本使用


使用要點

  • getConstructors() :可以獲取該類的所有構造器
  • getConstructor() :可以獲取某一個指定參數的構造器,需要參數列表。
    而且需要注意 傳的參數列表必須嚴格的一樣,否則會報NoSuchMethodException。
    比如 【clazz0.getConstructor(String.class, int.class);】//如果不傳int.class,而傳Integer.class是不行的.
  • 得到構造器后,再調用構造器的 newInstance() 方法可以創建對象

直接上代碼來演示使用:

//------------------------Constructor的基本使用-----------------------String className0 = "reflect.Person";Class<Person> clazz0 = (Class<Person>) Class.forName(className0);//getConstructors()---獲取全部Constructor對象Constructor<Person>[] constructors = (Constructor<Person>[]) clazz0.getConstructors();for(Constructor<Person> constructor: constructors){System.out.println("getConstructors()獲取到的構造器:"+constructor);}System.out.println();//getConstructor()----獲取某一個Constructor 對象,需要參數列表// //注意此處傳的參數列表必須嚴格的一樣,否則會報有可能NoSuchMethodExceptionConstructor<Person> constructor = clazz0.getConstructor(String.class, int.class);//如果傳Integer.class是不行的.System.out.println("getConstructor()獲取到的構造器:"+constructor);//調用構造器的 newInstance() 方法創建對象Person malegod=constructor.newInstance("夏夏夏",26);malegod.say("我負責指導詩雨學習!");System.out.println();

我們來看下打印結果:

(2).Field的基本使用


使用要點:

  • getDeclaredFields():可以獲取 自己的 所有字段( 包括私有的),但不能獲取父類字段
  • getDeclaredField(name)—獲取指定字段
  • 如果獲取的字段是私有的,不管是讀還是寫,都要先 field.setAccessible(true);才可以。否則會報:IllegalAccessException。

老規矩直接上代碼:

//-------------Field的基本使用--------------------Person goddess=new Person("賈玲",18);//先new個女神String className = "reflect.Person";Class clazz = Class.forName(className);//getDeclaredFields()---獲取 自己的 公有和私有的所有字段,但不能獲取父類字段Field[] fields = clazz.getDeclaredFields();for(Field field: fields){System.out.println("getDeclaredFields()獲取的字段:"+ field.getName());}System.out.println();//getDeclaredField()---獲取指定字段,傳入字段的名稱Field field=clazz.getDeclaredField("name");Field field2 = clazz.getDeclaredField("sex");//獲取的字段是私有的,不管是讀還是寫都要先設置 field.setAccessible(true);field.setAccessible(true);System.out.println("getDeclaredField()獲取的字段:"+field.getName());//field.getName()是讀操作,所以在此之前要設置field.setAccessible(true)System.out.println("getDeclaredField()獲取的字段:"+field2.getName());//"獲取指定字段的值"Object val = field.get(goddess);Object val2 = field2.get(goddess);System.out.println(field.getName()+"="+val);System.out.println(field2.getName()+"="+val2);//修改指定字段的為指定的值field.set(goddess,"郭德綱"); //相當于是寫操作System.out.println(field.getName()+"="+goddess.getName());//這個時候再打印,女神的名字就變成了郭德綱了

看一下打印結果:

(3).Method的基本使用


使用要點:

  • getMethods():可以獲取clazz對應類的所有公有方法,包括從父類繼承來的方法,私有方法不能得到。
  • getDeclaredMethods():只獲取當前類的所有方法,包括私有方法
  • getDeclaredMethod():獲取指定的方法,需要參數名稱和參數列表,無參則不需要寫。
    也要注意 傳入的參數類型要嚴格一致。
  • 私有方法的執行,必須在調用invoke之前加上一句method.setAccessible(true)

上代碼:

//-------------Method的基本使用--------------------Person goddess=new Person("賈玲",18);//有一個女神String className = "reflect.Person";Class clazz = Class.forName(className);//getMethods()---獲取clazz對應類所有公有方法,包括從父類繼承來的方法Method[] methods= clazz.getMethods();for(Method method:methods){System.out.println("getMethods()獲取的方法: "+method.getName()+"()");}System.out.println("");//getDeclaredMethods()---只獲取當前類的所有方法,包括私有方法methods = clazz.getDeclaredMethods();for(Method method:methods){System.out.println(" getDeclaredMethods()獲取的方法:"+method.getName()+"()");}System.out.println("");//getDeclaredMethod()---獲取指定的方法,需要參數名稱和參數列表,無參則不需要寫//注意 是 參數寫成int.classMethod method = clazz.getDeclaredMethod("setAge", int.class);//獲取的是方法public void setAge(int age) { }System.out.println("getDeclaredMethod()獲取的指定方法:"+method);System.out.println("");//第一個參數表示執行哪個對象的方法,剩下的參數是執行方法時需要傳入的參數"method.invoke(goddess,25);System.out.println("此時女神的年齡是:"+goddess.getAge());System.out.println();/*私有方法的執行,必須在調用invoke之前加上一句method.setAccessible(true);*/method = clazz.getDeclaredMethod("secret");System.out.println(method);method.setAccessible(true);//在訪問私有域時同樣method.invoke(goddess);//執行私有方法

打印結果大家可以對照Person類的思維導圖看:

小結與回顧

通過上面的學習我們知道了

獲取class對象有3種方式:

  • 1:通過類名獲取 --> 類名.class
Class personClass = Person.class;
  • 2.通過對象獲取 --> 對象名.getClass()
Class personClass2 = person.getClass()
  • 3.通過全類名獲取 --> Class.forName(全類名)
Class personClass3=Class.forName("reflect.Person");

那么請問大家 獲取一個類的實例對象方法 有幾種呢?
其實是有3種的:

  • 直接new出來
Person person=new Person("夏天",18);
  • 2.獲取class對象后,調用newInstance()方法
Class personClass = Person.class;//要先獲取對應的Class對象Person reflePerson=(Person)personClass.newInstance();//通過class得到類的實例

3.通過反射拿到這個類的構造器之后,再通過構造器的newInstance獲得。

Constructor<Person> constructor = clazz0.getConstructor(String.class, int.class);Person malegod=constructor.newInstance("夏夏夏",26);

今天的內容其實很簡單,相信大家看了一遍之后就懂了會了,有了這些基礎之后,下次我們再看源碼就會順利很多了~

積累點滴,做好自己~

總結

以上是生活随笔為你收集整理的《重学Java系列》之 反射(上)的全部內容,希望文章能夠幫你解決所遇到的問題。

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