Java基礎:反射機制重點回顧

語言: CN / TW / HK

theme: smartblue

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第10天,點擊查看活動詳情

一、基本概念

主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力, 並能根據自身行為的狀態和結果,調整或修改應用所描述行為的狀態和相關的語義。Java 中,反射是一種強大的工具。它使您能夠創建靈活的代碼,這些代碼可以在 運行時裝配,無需在組件之間進行源代碼鏈接。反射允許我們在編寫與執行時,使我們的程序代碼能夠接入裝載到 JVM 中的類的內部信息,而不是源代碼中選定的類協作的代碼。這使反射成為構建靈活的應用的主要工具。

  • 通過java中的反射機制可以操作字節碼文件(讀取和修改)
  • ==反射機制相關的類在java.lang.reflect.*;包下==

反射機制相關的重要的類:

    java.lang.Class:代表整個字節碼,代表一個類型,代表整個類。
    java.lang.reflect.Method:代表字節碼中的方法字節碼。代表類中的方法。
    java.lang.reflect.Constructor:代表字節碼中的構造方法字節碼。代表類中的構造方法
    java.lang.reflect.Field:代表字節碼中的屬性字節碼。代表類中的成員變量(靜態變量+實例變量)。

二、在java中獲取Class的三種方式

第一種:Class c = Class.forName("完整類名");

1.靜態方法 2.參數是一個字符串 3.字符串是一個完整的包名 4.完整類名必須有包名,jana.lang也要寫

java Class c1=null; Class c2=null; try { c1=Class.forName("java.lang.String");//c1代表String類型 c2=Class.forName("java.util.Date"); //Date類型 Class c3=Class.forName("java.lang.Integer");//Integer類型 Class c4=Class.forName("java.lang.System");//System類型 } catch (ClassNotFoundException e) { e.printStackTrace(); }

第二種:Class c = 對象.getClass();

```java String s="abc"; Class x=s.getClass();//x代表String.class字節碼文件,x代表String類型 System.out.println(c1==x);//true(==判斷兩個對象的內存地址)

    Date date=new Date();
    Class y=date.getClass();
    System.out.println(c2==y);

```

第三種:Class c = int.class;(Class c = String.class;)

java //第三種方式:java中任何一個類型,包括基本數據類型,都有class屬性 Class z=String.class;//x代表String Class k=Date.class;//k代表Date Class f=int.class;//f代表int類型 Class e=double.class;//e代表double類型 獲取類之後幹什麼呢?

通過Class的newInstance方法,完成對象的創建,newInstance方法會調用User類的無參構造方法,無參構造必須存在!如果沒有這個無參數構造方法會出現"實例化"異常。

示例代碼(1): User類: java public class User { public User() { System.out.println("無參數構造方法"); } } 測試類: ```java import ben.User;

public class ReflectText02 { public static void main(String[] args) { //不使用反射機制 User user = new User(); System.out.println(user);

    //反射機制創建對象
    try {
        //通過反射機制獲取Class,通過Class實例化對象
        Class c = Class.forName("ben.User");//c代表User類型
        //newInstance方法會調用User類的無參構造方法,完成對象的創建

        Object obj = c.newInstance();
        System.out.println(obj);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    }
}

}

``` 運行結果:

java 無參數構造方法 [email protected] 無參數構造方法 [email protected]

反射機制靈活性:可以做到不同對象的實例化,

資源綁定器:

java.util包下提供了一個資源綁定器,便於獲取屬性配置文件的內容,使用此方法時,屬性文件必須在類路徑下並且屬性配置文件必須以.properties結尾。

示例代碼:(2):

```java import java.util.ResourceBundle;

public class ResourceBundleText { public static void main(String[] args) { ResourceBundle bundle=ResourceBundle.getBundle("classinfo2"); String className=bundle.getString("className"); System.out.println(className); } } ``` 屬性配置文件內容: 在這裏插入圖片描述 運行結果:

java ben.User

三、Field類詳解

Field類常用方法:

(1)類<?> getDeclaringClass() 返回表示的類或接口聲明的 Field對象表示的領域 類對象。 (2)int getModifiers() 返回的 Field對象表示的場java語言修飾符為整數。 (3)String getName() 返回的 Field對象表示的字段的名稱。 (4)類<?> getType() 返回一個 類對象標識聲明類型的 Field對象表示的場。 (5)String toString() 返回一個描述這個 Field字符串。

==反射Student類中的Field屬性== 示例代碼(3): Student類: ```java public class Student { //Field:字段 public int id ; private String name; protected int age; boolean sex; public static final double MATH_PI=301415926; }

``` 測試類:

```java import java.lang.reflect.Field; import java.lang.reflect.Modifier;

public class ReflectText05 { public static void main(String[] args) { try { Class studenClass=Class.forName("ben.Student");

        String className=studenClass.getName();
        System.out.println("完整類型:"+className);
        String simpleName=studenClass.getSimpleName();
        System.out.println("簡單類名:"+simpleName);
        System.out.println("==============================");

        //獲取類中的Filed
        Field[] fileds=studenClass.getFields();
        System.out.println(fileds.length);//1

        //取出這個Field
        Field f=fileds[0];
        String fieldName=f.getName();
        System.out.println(fieldName);

        //取出所有的Field
        Field[] fs=studenClass.getDeclaredFields();
        System.out.println(fs.length);//4
        System.out.println("=========================");

        for (Field field: fs){
            //獲取屬性的修飾符列表
            int i=field.getModifiers();
            System.out.println(i);

            String modfiersString= Modifier.toString(i);
            System.out.println(modfiersString);

            //獲取屬性的類型
            Class fieldType=field.getType();
            //String fNum=fieldType.getName();
            String fNum=fieldType.getSimpleName();
            System.out.println(fNum);

            //獲取屬性名字
            System.out.println(field.getName());
           // System.out.println(field);
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

``` 運行結果:

```java 完整類型:ben.Student 簡單類名:Student ============================== 2 id 5 ========================= 1 public int id 2 private String name 4 protected int age 0

boolean sex 25 public static final double MATH_PI ``` 反射機制進行反編譯Student類 !! 示例代碼(4):

```java import ben.Student;

import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Modifier; / 反射機制進行反編譯!! / public class ReflectText06 { public static void main(String[] args) { try { StringBuilder s=new StringBuilder();

        Class studentClass=Class.forName("ben.Student");
       // Class studentClass=Class.forName("java.util.Date");
        s.append(Modifier.toString(studentClass.getModifiers())+"\t"+"class"+"\t"+studentClass.getSimpleName()+"{\n");
        Field[] fields=studentClass.getDeclaredFields();
        for (Field field:fields){
            s.append("\t");
            s.append(Modifier.toString(field.getModifiers()));
            s.append(" ");
            s.append(field.getType().getSimpleName());
            s.append(" ");
            s.append(field.getName());
            s.append(":\n");
        }
            s.append("}");
        System.out.println(s);

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

}

``` 運行結果:

java public class Student{ public int id: private String name: protected int age: boolean sex: public static final double MATH_PI: }

四、通過反射機制訪問java對象的屬性

給屬性複製:set獲取屬性的值:get

示例代碼(5): Student類: ```java public class Student { //Field:字段 public int id ; private String name; protected int age; boolean sex; public static final double MATH_PI=301415926; }

測試類:java import java.lang.reflect.Field;

public class ReflectText07 { public static void main(String[] args) { try { Class studentClass=Class.forName("ben.Student"); Object obj=studentClass.newInstance();//obj就是Student對象。(無參構造) //獲取no屬性(根據屬性的名稱獲取Field) Field noField=studentClass.getDeclaredField("id"); //給obj對象的no屬性賦值 noField.set(obj,2222 );//給no屬性賦值2222 //讀取值 System.out.println( noField.get(obj));

        Field nameFiled=studentClass.getDeclaredField("name");
        //打破封裝,反射機制缺點
        nameFiled.setAccessible(true);
        //賦值
        nameFiled.set(obj,"jack");
        //獲取
        System.out.println(nameFiled.get(obj));

    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
}

}

``` 運行結果:

java 2222 jack

五、通過反射機制調對象的方法

java Object invoke(Object obj, Object... args) 調用底層的方法,這 方法對象表示,對指定對象的指定參數。

示例代碼(6): UserService類

java public class UserService { public boolean login(String name, String password) { if ("admin".equals(name) && "123".equals(password)) { return true; } return false; } public void logout(){ System.out.println("退出系統成功!1"); } } 測試類:

```java import ben.UserService;

import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;

public class ReflectText08 { public static void main(String[] args) { UserService userService=new UserService(); boolean loginSuccess=userService.login("admin","123"); // System.out.println(loginSuccess); System.out.println(loginSuccess?"登陸成功":"登陸失敗");

    try {
        Class userServiceClass =Class.forName("ben.UserService");
        //創建對象
        Object obj=userServiceClass.newInstance();
        //獲取login方法
        Method loginMethod=userServiceClass.getDeclaredMethod("login", String.class, String.class);
        //調用方法 
        Object retValue=loginMethod.invoke(obj,"admin","123");
        System.out.println(retValue);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

}

``` 運行結果:

java 登陸成功 true

反射機制具有通用性,將可變化的內容放到配置文件中,無需改變java代碼,只需修改配置文件

可變長參數

例如: int...args這是可變長參數 語法:類型... 1.可變長參數個數為0-N個 2. 可變長參數在參數列表中必須在最後一個位置上,而且可變長度參數只能有一個 3.可變長度參數可以是一個數組

示例代碼(7):

```java public class ArgsText { public static void main(String[] args) { m(); m(1, 2); m(1, 2, 3);

    m2(1, "abc");
    m2(2, "cbv", "mcm");
    m2(3, "ncb", "mcn", "mnshs");


    m3("ab", "cd", "abc");
    String[] str = {"a", "b", "c", "d"};
    m3(str);
}

public static void m(int... args) {
    System.out.println("可變長參數方法");
}

public static void m2(int a, String... args) {

}

public static void m3(String... args) {
    for (int i = 0; i < args.length; i++) {
        System.out.println(args[i]);
    }
}

}

```