1. 程式人生 > 實用技巧 >java反射初學習

java反射初學習

java反射初學習

“程式執行時,允許改變程式結構或變數型別,這種語

言稱為動態語言”,如Python,Ruby是動態語言;顯然

C++,Java,C#不是動態語言,但是JAVA有著一個非常

突出的動態相關機制:Reflection。

JAVA反射機制是在執行狀態中,對於任意一個類,都能

夠知道這個類的所有屬性和方法;對於任意一個物件,

都能夠呼叫它的任意一個方法和屬性;這種動態獲取的

資訊以及動態呼叫物件的方法的功能稱為java語言的反

射機制,很多優秀的開源框架都是通過反射完成的。

Java反射機制,可以實現以下功能:

①在執行時判斷任意一個物件所屬的類;

②在執行時構造任意一個類的物件;

③在執行時判斷任意一個類所具有的成員變數和方法;

④在執行時呼叫任意一個物件的方法;

⑤生成動態代理;

可變引數

/**

\* 入門級示例:通過物件獲取 包名.類名 

\* @author Administrator 

*/ 

public class Simple { 

public static void main(String[] args) { 

Simple s=new Simple(); 

System.out.println(s.2.getName()); 

} 

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

當我們能夠確定一系列引數的型別,型別必須是統一

的, 但是我們確定不了引數的個數的時候,我們可以使

用可變引數。可變代表個數可變[0,+),如果一個方法

中帶有可變引數,這個可變引數只能在引數列表最後。

獲取源頭Class(重點)

所有類的物件其實都是Class**的例項。**這個 Class 例項

可以理解為類的模子,就是包含了類的結構資訊,類似

於圖紙。我們日常生活中,需要創造一個產品,如想山

寨一個iphone手機,怎麼辦?有三種方式可以實現:

⑴買個iphone手機,拆的七零八落的,開始山寨;

⑵到iphone工廠參觀,拿到iphone磨具,開始山寨;

⑶跑到美國盜取iphone的圖紙,開始山寨,最後一種最

暴力,最爽。

同理,獲取類的Class物件也有三種方式

⑴Class.forName(”包名.類名”) //一般儘量採用該形式

(2)類.class

(3)物件.getClass()

類載入器(瞭解)

類的生命週期

在一個類編譯完成之後,下一步就需要開始使用類,如

果要使用一個類,肯定離不開JVM。在程式執行中JVM通

過裝載,連結,初始化這3個步驟完成。

從類的生命週期而言,一個類包括如下階段:

載入、驗證、準備、初始化和解除安裝這5個階段的順序是確

定的,類的載入過程必須按照這種順序進行

類的裝載是通過 類載入器 完成的,載入器將 .class 文

件的二進位制檔案裝入JVM的方法區,並且在堆區建立描

述這個類的 java.lang.Class 物件。用來封裝資料。

但是同一個類只會被類裝載器裝載一次。

連結就是把二進位制資料組裝為可以執行的狀態。連結分

為校驗,準備,解析這3個階段

類載入器

顧名思義,類載入器(class loader)用來載入 Java 類到

Java 虛擬機器中。一般來說,Java 虛擬機器使用 Java 類的

方式如下:Java 源程式(.java 檔案)在經過 Java 編譯

器編譯之後就被轉換成 Java 位元組程式碼(.class 檔案)。

類載入器負責讀取 Java 位元組程式碼,並轉換成

java.lang.Class 類的一個例項。每個這樣的例項用

來表示一個 Java 類。通過此例項的 newInstance()

方法就可以創建出該類的一個物件。實際的情況可能更

加複雜,比如 Java 位元組程式碼可能是通過工具動態生成

的,也可能是通過網路下載的。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-f173Onk3-1603201534777)(C:\Users\lwf\AppData\Roaming\Typora\typora-user-images\image-20201020214106170.png)]

在java中有三種類類載入器:

⑴ Bootstrap ClassLoader 此載入器採用c++編寫,一般開

發中很少見。⑵ Extension ClassLoader 用來進行擴充套件類的載入,一般

對應的是jre\lib\ext目錄中的類

⑶ AppClassLoader 載入classpath指定的類,是最常用的

載入器。同時也是java中預設的載入器。 瞭解即可。

public static void main(String[] args) throws 

Exception { 

System.out.println("類載入器 

"+ClassLoader.class.getClassLoader().getClass( 

).getName()); 

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

反射的運用

package com.lwf;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author lwf
 * @title: RefTest
 * @projectName Learn
 * @description: 反射
 * @date 2020/10/2019:51
 */
public class RefTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, CloneNotSupportedException, IOException, NoSuchFieldException {
        //new物件
        Student student0=new Student();
        student0.setName("lwf");
        student0.setAge(18);
        student0.setClassName("class 1");
        System.out.println(student0);
        Class  c=Class.forName("com.lwf.Student");
        Constructor[] constructors = c.getDeclaredConstructors();
        for(Constructor c1 : constructors){
            System.out.println(c1);
        }
        Field[] declaredFields = c.getDeclaredFields();
        System.out.println("屬性");
        for(Field field:declaredFields){
            System.out.println(field.getName()+","+field.getType());
        }
        //修改訪問許可權,將私有屬性直接修改值
        Field field = c.getDeclaredField("name");
        field.setAccessible(true);
        field.set(student0, "羅衛飛");
        System.out.println(student0);
        //呼叫方法
        Method method=c.getMethod("getName");
        System.out.println(method.invoke(student0));


        //反射獲取物件
        Student student1= (Student)c.getConstructor(String.class,Integer.class,String.class).newInstance("lwf",18,"一班");
        Student student= (Student)c.getConstructor().newInstance();
        System.out.println(student);
        System.out.println(student1);



        //克隆物件 繼承Coneable介面
        Student student2=(Student)student1.clone();
        System.out.println(student2);

        //序列化獲取物件
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("1.txt"));
        outputStream.writeObject(student);
        ObjectInputStream obj=new ObjectInputStream(new FileInputStream("1.txt"));
        Student object =(Student) obj.readObject();
        System.out.println(object);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  1. 構造器 :

    //反射獲取物件
               Student student1= (Student)c.getConstructor(String.class,Integer.class,String.class).newInstance("lwf",18,"一班");
               Student student= (Student)c.getConstructor().newInstance();
     
    
    • 1
    • 2
    • 3
    • 4
  2. 獲取屬性並賦值

     //修改訪問許可權,將私有屬性直接修改值
            Field field = c.getDeclaredField("name");//從所有屬性中找;getField從public修飾屬性中找屬性
            field.setAccessible(true);
            field.set(student0, "羅衛飛");
            System.out.println(student0);
    
    • 1
    • 2
    • 3
    • 4
    • 5
  3. 獲取方法並執行 Method物件呼叫invoke(例項,方法引數列表)

    //呼叫方法
            Method method=c.getMethod("getName");
            System.out.println(method.invoke(student0));
    
    • 1
    • 2
    • 3

聯絡:物件的建立

//new物件
        Student student0=new Student();


//反射獲取物件
        Student student1= (Student)c.getConstructor(String.class,Integer.class,String.class).newInstance("lwf",18,"一班");
        Student student= (Student)c.getConstructor().newInstance();
        System.out.println(student);
        System.out.println(student1);
        
   //克隆物件 繼承Coneable介面
    Student student2=(Student)student1.clone();
    System.out.println(student2);

    //序列化獲取物件
    ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("1.txt"));
    outputStream.writeObject(student);
    ObjectInputStream obj=new ObjectInputStream(new FileInputStream("1.txt"));
    Student object =(Student) obj.readObject();