1. 程式人生 > >Java基礎之反射(非常重要)

Java基礎之反射(非常重要)

點選上方“Java團長”,選擇“置頂公眾號”

技術文章第一時間送達!

反射是框架設計的靈魂

(使用的前提條件:必須先得到代表的位元組碼的Class,Class類用於表示.class檔案(位元組碼))

一、反射的概述

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼檔案對應的Class型別的物件.

以上的總結就是什麼是反射

反射就是把java類中的各種成分對映成一個個的Java物件

例如:一個類有:成員變數、方法、構造方法、包等等資訊,利用反射技術可以對一個類進行解剖,把個個組成部分對映成一個個物件。

     (其實:一個類中這些成員方法、構造方法、在加入類中都有一個類來描述)

如圖是類的正常載入過程:反射的原理在與class物件。

熟悉一下載入的時候:Class物件的由來是將class檔案讀入記憶體,併為之建立一個Class物件。


其中這個Class物件很特殊。我們先了解一下這個Class類

二、檢視Class類在java中的api詳解(1.7的API

如何閱讀java中的api詳見java基礎之——String字串處理


Class 類的例項表示正在執行的 Java 應用程式中的類和介面。也就是jvm中有N多的例項每個類都有該Class物件。(包括基本資料型別)

Class 沒有公共構造方法。Class 物件是在載入類時由 Java 虛擬機器以及通過呼叫類載入器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理建立,JVM已經幫我們建立好了。

沒有公共的構造方法,方法共有64個太多了。下面用到哪個就詳解哪個吧


三、反射的使用(這裡使用Student類做演示)

先寫一個Student類。

1、獲取Class物件的三種方式

1.1 Object ——> getClass();
1.2 任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性
1.3 通過Class類的靜態方法:forName(String  className)(常用)

其中1.1是因為Object類中的getClass方法、因為所有類都繼承Object類。從而呼叫Object類來獲取

<span style="font-size:18px;">package fanshe;  
/**
* 獲取Class物件的三種方式
* 1 Object ——> getClass();
* 2 任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性
* 3 通過Class類的靜態方法:forName(String  className)(常用)
*
*/
 
public class Fanshe {  
   public static void main(String[] args) {  
       //第一種方式獲取Class物件    
       Student stu1 = new Student();//這一new 產生一個Student物件,一個Class物件。  
       Class stuClass = stu1.getClass();//獲取Class物件  
       System.out.println(stuClass.getName());  
         
       //第二種方式獲取Class物件  
       Class stuClass2 = Student.class;  
       System.out.println(stuClass == stuClass2);//判斷第一種方式獲取的Class物件和第二種方式獲取的是否是同一個  
         
       //第三種方式獲取Class物件  
       try {  
           Class stuClass3 = Class.forName("fanshe.Student");//注意此字串必須是真實路徑,就是帶包名的類路徑,包名.類名  
           System.out.println(stuClass3 == stuClass2);//判斷三種方式是否獲取的是同一個Class物件  
       } catch (ClassNotFoundException e) {  
           e.printStackTrace();  
       }  
         
   }  
}</span>

注意:在執行期間,一個類,只有一個Class物件產生。

三種方式常用第三種,第一種物件都有了還要反射干什麼。第二種需要匯入類的包,依賴太強,不導包就拋編譯錯誤。一般都第三種,一個字串可以傳入也可寫在配置檔案中等多種方法。

2、通過反射獲取構造方法並使用:

student類:

package fanshe;  
 
public class Student {  
     
   //---------------構造方法-------------------  
   //(預設的構造方法)  
   Student(String str){  
       System.out.println("(預設)的構造方法 s = " + str);  
   }  
     
   //無參構造方法  
   public Student(){  
       System.out.println("呼叫了公有、無參構造方法執行了。。。");  
   }  
     
   //有一個引數的構造方法  
   public Student(char name){  
       System.out.println("姓名:" + name);  
   }  
     
   //有多個引數的構造方法  
   public Student(String name ,int age){  
       System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,以後解決。  
   }  
     
   //受保護的構造方法  
   protected Student(boolean n){  
       System.out.println("受保護的構造方法 n = " + n);  
   }  
     
   //私有構造方法  
   private Student(int age){  
       System.out.println("私有的構造方法   年齡:"+ age);  
   }  
 
}

共有6個構造方法;

測試類:

package fanshe;  
 
import java.lang.reflect.Constructor;  
 
 
/*
* 通過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員;
*  
* 1.獲取構造方法:
*      1).批量的方法:
*          public Constructor[] getConstructors():所有"公有的"構造方法
           public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
     
*      2).獲取單個的方法,並呼叫:
*          public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
*          public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有;
*      
*          呼叫構造方法:
*          Constructor-->newInstance(Object... initargs)
*/
 
public class Constructors {  
 
   public static void main(String[] args) throws Exception {  
       //1.載入Class物件  
       Class clazz = Class.forName("fanshe.Student");  
         
         
       //2.獲取所有公有構造方法  
       System.out.println("**********************所有公有構造方法*********************************");  
       Constructor[] conArray = clazz.getConstructors();  
       for(Constructor c : conArray){  
           System.out.println(c);  
       }  
         
         
       System.out.println("************所有的構造方法(包括:私有、受保護、預設、公有)***************");  
       conArray = clazz.getDeclaredConstructors();  
       for(Constructor c : conArray){  
           System.out.println(c);  
       }  
         
       System.out.println("*****************獲取公有、無參的構造方法*******************************");  
       Constructor con = clazz.getConstructor(null);  
       //1>、因為是無參的構造方法所以型別是一個null,不寫也可以:這裡需要的是一個引數的型別,切記是型別  
       //2>、返回的是描述這個無參建構函式的類物件。  
     
       System.out.println("con = " + con);  
       //呼叫構造方法  
       Object obj = con.newInstance();  
   //  System.out.println("obj = " + obj);  
   //  Student stu = (Student)obj;  
         
       System.out.println("******************獲取私有構造方法,並呼叫*******************************");  
       con = clazz.getDeclaredConstructor(char.class);  
       System.out.println(con);  
       //呼叫構造方法  
       con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)  
       obj = con.newInstance('男');  
   }  
     
}

後臺輸出:

**********************所有公有構造方法*********************************  
public fanshe.Student(java.lang.String,int)  
public fanshe.Student(char)  
public fanshe.Student()  
************所有的構造方法(包括:私有、受保護、預設、公有)***************  
private fanshe.Student(int)  
protected fanshe.Student(boolean)  
public fanshe.Student(java.lang.String,int)  
public fanshe.Student(char)  
public fanshe.Student()  
fanshe.Student(java.lang.String)  
*****************獲取公有、無參的構造方法*******************************  
con = public fanshe.Student()  
呼叫了公有、無參構造方法執行了。。。  
******************獲取私有構造方法,並呼叫*******************************  
public fanshe.Student(char)  
姓名:男

呼叫方法:

1.獲取構造方法:

 1).批量的方法:
public Constructor[] getConstructors():所有"公有的"構造方法
           public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
     
 2).獲取單個的方法,並呼叫:
public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有;

 呼叫構造方法:

Constructor-->newInstance(Object... initargs)

2、newInstance是 Constructor類的方法(管理建構函式的類)

api的解釋為:

newInstance(Object... initargs)
          使用此 Constructor 物件表示的構造方法來建立該構造方法的宣告類的新例項,並用指定的初始化引數初始化該例項。

它的返回值是T型別,所以newInstance是建立了一個構造方法的宣告類的新例項物件。併為之呼叫

3、獲取成員變數並呼叫

student類:

<span style="font-size:14px;">package fanshe.field;  
 
public class Student {  
   public Student(){  
         
   }  
   //**********欄位*************//  
   public String name;  
   protected int age;  
   char sex;  
   private String phoneNum;  
     
   @Override  
   public String toString()
{  
       return "Student [name=" + name + ", age=" + age + ", sex=" + sex  
               + ", phoneNum=" + phoneNum + "]";  
   }  
     
     
}</span>

測試類:

<span style="font-size:14px;">package fanshe.field;  
import java.lang.reflect.Field;  
/*
* 獲取成員變數並呼叫:
*  
* 1.批量的
*      1).Field[] getFields():獲取所有的"公有欄位"
*      2).Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有;
* 2.獲取單個的:
*      1).public Field getField(String fieldName):獲取某個"公有的"欄位;
*      2).public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
*  
*   設定欄位的值:
*      Field --> public void set(Object obj,Object value):
*                  引數說明:
*                  1.obj:要設定的欄位所在的物件;
*                  2.value:要為欄位設定的值;
*  
*/
 
public class Fields {  
 
       public static void main(String[] args) throws Exception {  
           //1.獲取Class物件  
           Class stuClass = Class.forName("fanshe.field.Student");  
           //2.獲取欄位  
           System.out.println("************獲取所有公有的欄位********************");  
           Field[] fieldArray = stuClass.getFields();  
           for(Field f : fieldArray){  
               System.out.println(f);  
           }  
           System.out.println("************獲取所有的欄位(包括私有、受保護、預設的)********************");  
           fieldArray = stuClass.getDeclaredFields();  
           for(Field f : fieldArray){  
               System.out.println(f);  
           }  
           System.out.println("*************獲取公有欄位**並呼叫***********************************");  
           Field f = stuClass.getField("name");  
           System.out.println(f);  
           //獲取一個物件  
           Object obj = stuClass.getConstructor().newInstance();//產生Student物件--》Student stu = new Student();  
           //為欄位設定值  
           f.set(obj, "劉德華");//為Student物件中的name屬性賦值--》stu.name = "劉德華"  
           //驗證  
           Student stu = (Student)obj;  
           System.out.println("驗證姓名:" + stu.name);  
             
             
           System.out.println("**************獲取私有欄位****並呼叫********************************");  
           f = stuClass.getDeclaredField("phoneNum");  
           System.out.println(f);  
           f.setAccessible(true);//暴力反射,解除私有限定  
           f.set(obj, "18888889999");  
           System.

相關推薦

Java基礎反射非常重要

package fanshe; import java.lang.reflect.Constructor; /* * 通過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員; * * 1.獲取構造方法: * 1).批量的方法: * public Constr

Java基礎反射非常重要

點選上方“Java團長”,選擇“置頂公眾號”技術文章第一時間送達!反射是框架設計的靈魂(使用的前

Java基礎反射應用如何獲取物件的構造方法、屬性以及、基本方法

反射實戰:新建Student類,利用反射原理輸出Student的構造方法,屬性,普通方法,引數列表等等資訊。 反射資料:查詢java_API之:java.lang.reflect包下。 Student類: package com.briup.ch24; public class St

Java基礎反射例項例項化Account與修改屬性

要求:    設計Account類,並且新增屬性id、name、balance,新增get和set方法與存取錢的方法。    設計ReflectAccountTest類,例項化Account物件,存如100元,與取1000元的結果顯示。 &nb

Java基礎Freemarker1模板加載及清空機制

ron date java 自帶 pda 直接 onf 刷新方法 希望 一 freemarker加載模版機制 freemarker中的配置項template_update_delay表明模版的緩存時間,單位是s,超過緩存時間則從磁盤加載最新的模版,具體細節如下: 1)fre

java基礎--註解

       最近學習spring5的時候,發現好像多了一些新的註解,於是乎想好好看看這些註解到底是怎麼實現的,但是奈何自己連基礎的元註解都還是一知半解,所以還是萬丈高樓平地起,一切以基礎為重。下面就來說說jdk自帶的元註解,與新手朋友們分享也為自己填一個坑。 1.什麼是元

JAVA基礎檔案File

File類 構造: public class File extends Object implements Serializable, Comparable File類就是檔案和目錄路徑名的抽象表示形式。 通過將給定路徑名字串轉換為抽象路徑名來建立一個新 File 例項,也就

Java基礎引用String,char[],Integer總結於牛客網的專項練習題

1、String的引用:下列程式碼執行後的結果為:public class Test { public static void main(String[] args) { StringBuffe

Java基礎異常Exception

異常,是Java中非常常用的功能,它可以簡化程式碼,並且增強程式碼的安全性。本文將介紹一些異常高階知識,也是學習Java一來的一次總結。包括以下內內容: 異常的基礎知識 異常特點 異常誤用 如何正確地使用異常 異常的實現原理 關於異常 異常機制,是

Java基礎部分回顧為自己

.cn logs -1 繼續 分享 9.png 沒有 理解 開始 最近,學到集合框架。感覺有些蒙圈兒。知道這一塊很重要很重要,不敢疏忽。自學遇到的攔路虎,想著是不是前面的基礎知道還沒有夯實,對一些概念沒有真正的理解到位呢?!所以,停下來。開始找一些視頻,做一下回顧。 再次鞏

Java基礎反射

實例 編譯 ring 反序列化 ons 信息 method api 反射 Java反射是指運行時獲取類信息,進而在運行時動態構造對象、調用對象方法及修改對象屬性的機制。百度百科的定義:“JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和

Java學習書籍推薦

個人 分布式 方法 都是 操作 測試 對象 web編程 數據庫 一、基礎類 1、《Thinking in java》(閱讀2遍),入門第一位是建立正確的概念 2、《Core Java》這本書更貼近實踐,更多API的介紹,同樣,更新也更頻繁。(可以選重點章節讀一下) 二、進階

java基礎73 待續網頁知識

bsp 說明 http col tro font -s .cn java基礎 1、待續 待續 原創作者:DSHORE 作者主頁:http://www.cnblogs.com/dshore123/ 原文出自:https://www.cnbl

面向對象反射定制

租房子 click span 領域 面向 屬性和方法 lsd 正在 ttr 什麽是反射? 反射的蓋面是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力(自省), 這一概念的提出很快引發了計算機科學領域關於應用反射的研究。它首

java基礎學習總結二十三:什麼要使用AOP

從最基礎的原始程式碼-->使用設計模式(裝飾器模式與代理)-->使用AOP三個層次來講解一下為什麼我們要使用AOP。 原始程式碼的寫法 既然要通過程式碼來演示,那必須要有例子,這裡我的例子為: 有一個介面Dao有insert、delete、update三個方法,在insert

java基礎學習總結二十:多執行緒上下文切換

什麼是上下文切換        即使是單核CPU也支援多執行緒執行程式碼,CPU通過給每個執行緒分配CPU時間片來實現這個機制。時間片是CPU分配給各個執行緒的時間,因為時間片非常短,所以CPU通過不停地切換執行緒執行,讓我們感覺多個執行緒時同時執行的,時

java基礎學習總結十九:Unsafe與CAS

Unsafe         簡單講一下這個類。Java無法直接訪問底層作業系統,而是通過本地(native)方法來訪問。不過儘管如此,JVM還是開了一個後門,JDK中有一個類Unsafe,它提供了硬體級別的原子操作。     &n

java基礎學習總結十八:切勿用普通for迴圈遍歷LinkedList

ArrayList與LinkedList的普通for迴圈遍歷 對於大部分Java程式設計師朋友們來說,可能平時使用得最多的List就是ArrayList,對於ArrayList的遍歷,一般用如下寫法: public static void main(String[] args) {

java基礎學習總結十七Java Socket

一、 什麼是Socket          Socket的概念很簡單,它是網路上執行的兩個程式間雙向通訊的一端,既可以接收請求,也可以傳送請求,利用它可以較為方便地編寫網路上資料的傳遞。 所以簡而言之,Socket就是程序通訊的端點

java基礎學習總結十六:程式碼優化

程式碼優化的目標是: 1、減小程式碼的體積 2、提高程式碼執行的效率 程式碼優化細節 (1)儘量指定類、方法的final修飾符     帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.Strin