天天看點

Java反射機制筆記Java反射機制筆記反射是架構設計的靈魂

Java反射機制筆記

反射是架構設計的靈魂

Java的反射(reflection)機制是指在程式的運作狀态中,可以構造任意一個類的對象,可以了解任意一個對象所屬的類,可以了解任意一個類的成員變量和方法,可以調用任意一個對象的屬性和方法。這種動态擷取程式資訊以及動态調用對象的功能稱為Java語言的反射機制。反射被視為動态語言的關鍵。(百度百科)

一、反射機制可以幹啥

  1. 在運作過程中,能夠動态的擷取一個類的屬性(Field)和方法(Method)
  2. 動态的調用任意一個對象的屬性和方法;
  3. 架構設計的核心,通過修改配置檔案動态加載類,調用類的方法和屬性;

二、反射機制依賴Class類

Java反射機制依賴java.lang.Class這個類,它是Java反射機制的起源。當一個類被加載以後,Java虛拟機就會自動産生一個Class對象。通過這個Class對象我們就能獲得加載到虛拟機當中這個Class對象對應的方法、成員以及構造方法的聲明和定義等資訊。

三、Java擷取Class對象的三種方法:

無論何時,隻要你想在運作時使用類型資訊,就必須先得到那個

Class

對象的引用。

Class.forName()

就是實作這個功能的一個便捷途徑,因為使用該方法你不需要先持有這個類型 的對象。但是,如果你已經擁有了目标類的對象,那就可以通過調用

getClass()

方法來擷取

Class

引用了,這個方法來自根類

Object

,它将傳回表示該對象實際類型的

Class

對象的引用。《On Java 8》

方法一:Class類的靜态方法

forName()

  • 方法的參數是一個完整類名字元串
  • 完整的類名還包括包名(連java.lang都不能省略)

方法二:Object類的

getClass(

)方法

Map<Integer,String> map = new HashMap<>();
Class c2 = map.getClass();
Class c3 = new String("abc").getClass();
System.out.println(c1==c3);// true
           

方法三:java語言中任意一種類型(包括基本資料類型)都有

.class

屬性

Class c4 = String.class;
Class c5 = int.class;
           

四、反射機制常用類:

Java反射機制筆記Java反射機制筆記反射是架構設計的靈魂

五、通過反射機制執行個體化對象

在某些場景下我們可以通過修改配置檔案就可以改變程式的執行個體對象,而不是通過修改代碼

package com.kongxiao.javase.reflect;

import java.io.FileReader;
import java.util.Properties;

public class ReflectTest02 {
    public static void main(String[] args) throws Exception {
        // 傳統執行個體化(隻能建立指定類型的對象)
        User user = new User();
        System.out.println(user);

        // 通過反射機制執行個體化對象
        // 靈活性測試:
        // 建立一個讀取配置檔案的流
        FileReader reader = new FileReader("G:\\JavaXB\\ReFlect\\src\\com\\kongxiao\\javase\\reflect\\classinfo.properties");
        // 使用Properties建立一個Map對象
        Properties map = new Properties();
        // 加載配置檔案到Map中
        map.load(reader);
        // 擷取類名
        String className = map.getProperty("ClassName");
        reader.close();

        // 建立一個Class對象
        Class c = Class.forName(className);
        // 通過反射機制執行個體化對象
        // 調用無參構造
        @Deprecated(since="9")
        Object o = c.newInstance();
        System.out.println(o);

    }
}

           

classinfo.properties:

ClassName = com.kongxiao.javase.reflect.User

輸出:

User{name=‘null’, age=0, no=0}

User{name=‘null’, age=0, no=0}

六、反射屬性(Field)

測試類:

public class Student {
    /**
     * 四個Field分别使用不同的通路修飾符
     */
    public int no;
    private String name;
    protected int age;
    boolean sex;
}

           

實作類:

package com.kongxiao.javase.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class ReflectField {
    public static void main(String[] args) throws ClassNotFoundException {
        Class studentClass = Class.forName("com.kongxiao.javase.reflect.Student");
        // 擷取所有的Field(public)
        Field [] fields = studentClass.getFields();
        // 擷取所有的字段(所有修飾符)
        Field [] filds2 = studentClass.getDeclaredFields();

        System.out.println(Arrays.toString(fields));
        System.out.println(Arrays.toString(filds2));

        // 單個擷取(toString)
        for(Field field:filds2){
            // 擷取修飾符
            // java.lang.reflect.Modifier有一個專門針對修飾符而寫的類
            // 特定的修飾符有特定的編号,并且有一個靜态的toString()方法
            int mod = field.getModifiers();
            System.out.print(Modifier.toString(mod)+" ");

            // 擷取類型
            // 傳回Class類型我想應該是應該區分基本資料類型和引用型資料類型
            Class typeClass  = field.getType();
            //System.out.println(typeClass.getName());
            System.out.print(typeClass.getSimpleName()+" ");

            //擷取字段
            System.out.println(field.getName());
        }

    }
}

           

輸出結果:

[public int com.kongxiao.javase.reflect.Student.no]
[public int com.kongxiao.javase.reflect.Student.no,
 private java.lang.String com.kongxiao.javase.reflect.Student.name,
 protected int com.kongxiao.javase.reflect.Student.age, 
 boolean com.kongxiao.javase.reflect.Student.sex]
 ==================================================
public int no
private String name
protected int age
boolean sex
           

反射機制調用屬性:

package com.kongxiao.javase.reflect;

import java.lang.reflect.Field;
import java.util.Arrays;

public class ReflectFieldTest {
    public static void main(String[] args) throws Exception {
        // 傳統指派
        // 三要素:對象-屬性-值
        Student student = new Student();
        student.age = 12;

        // 使用反射機制先去通路一個對象屬性
        Class studentClass = Class.forName("com.kongxiao.javase.reflect.Student");
        @Deprecated(since="9")
        Object obj = studentClass.newInstance();
        // 擷取屬性清單
        Field [] fields = studentClass.getDeclaredFields();
        System.out.println(Arrays.toString(fields));

        // 設定指定屬性值
        // 三要素:
        // 對象:obj
        // 屬性: Field
        // 值: value
        int value = 12;
        Field field = studentClass.getDeclaredField("age");
        field.set(obj,value);
        // 用屬性去掉對象中對應的值
        System.out.println(field.get(obj));
        
        // 通路私有屬性
        Field field1 = studentClass.getDeclaredField("name");
        // 打破封裝
        field1.setAccessible(true);
        field1.set(obj,"SUN");
        System.out.println(field1.get(obj));
    }
}

           

七、反射方法(Method)

測試類:

public class UserService {
    /**
     * 登入方法
     * @param name 使用者名
     * @param passWord 密碼
     * @return 登入成功/失敗
     */
    public boolean login(String name ,String passWord){
        return "admin".equals(name)&&"123".equals(passWord);
    }

    /**
     * 登出
     */
    public void logout(){
        System.out.println("登出成功!");
    }
}

           

實作類:

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReflectMethod {
    public static void main(String[] args) throws ClassNotFoundException {
        Class userClass = Class.forName("com.kongxiao.javase.reflect.UserService");
        // 擷取所有Method(包括私有的)
        Method [] methods = userClass.getDeclaredMethods();

        // 擷取各個元素
        for(Method m :methods){
            //擷取修飾符清單
            System.out.print(Modifier.toString(m.getModifiers())+" ");
            // 擷取傳回值類型
            System.out.print(m.getReturnType().getSimpleName()+" ");
            // 擷取方法名
            System.out.print(m.getName()+" ");
            // 擷取參數清單
            Class [] parameterTypes = m.getParameterTypes();
            System.out.print("( ");
            for(int i = 0 ; i<parameterTypes.length;i++){
                if (i==parameterTypes.length-1){
                    System.out.print(parameterTypes[i].getSimpleName()+" a");
                }else{
                    System.out.print(parameterTypes[i].getSimpleName()+" a,");
                }
            }
            System.out.println(" )");
        }
    }
}

           

輸出:

public void logout (  )
public boolean login ( String a,String a )
           

反射機制調用方法:

package com.kongxiao.javase.reflect;

import java.lang.reflect.Method;
import java.util.Arrays;


public class ReflectMethodTest {
    public static void main(String[] args) throws Exception {
        // 傳統調用方法
        // 三要素: 對象-方法名-參數清單-傳回值
        UserService userService = new UserService();
        boolean status1 = userService.login("SUN","123456");
        System.out.println(status1?"登入成功!":"登陸失敗!");

        //使用反射機制
        Class userServiceClass = Class.forName("com.kongxiao.javase.reflect.UserService");
        // 建立對象
        @Deprecated(since="9")
        Object obj = userServiceClass.newInstance();
        // 檢視有哪些函數
        Method [] methods = userServiceClass.getDeclaredMethods();
        System.out.println(Arrays.toString(methods));
        //因為方法可能存在是以單靠方法名不能獲得方法
        // getMethod(String name, Class<?>... parameterTypes) Class 對象個數可變
        Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);
        // 調用方法
        // 三要素 :對象-方法名-參數清單-傳回值
        //傳回值:
        Object reValue = null;
        reValue  = loginMethod.invoke(obj,"admin","123456");
        System.out.println((boolean)reValue?"登入成功!":"登陸失敗!");
    }
}

           

輸出:

D:\Java\jdk-12.0.2\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\lib\idea_rt.jar=57995:C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.2\bin" -Dfile.encoding=UTF-8 -classpath G:\JavaXB\out\production\ReFlect com.kongxiao.javase.reflect.ReflectMethodTest
    
登陸失敗!
[public boolean com.kongxiao.javase.reflect.UserService.login(java.lang.String,java.lang.String), 
 public void com.kongxiao.javase.reflect.UserService.logout()]
登陸失敗!
           

通過以上例子我們不難發現:反射機制讓代碼更具有通用性,可變化的内容都寫到配置檔案中,可以通過修改配置檔案(類似XML)這種靈活的方式來加載類、調用類方法,以及使用類屬性。