欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java高級語法學習之反射詳解

 更新時間:2022年01月28日 10:29:59   作者:張雷鋒  
java的泛型和反射機制一直很難理解和應用,下面這篇文章主要給大家介紹了關于Java高級語法學習之反射的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

一、什么是反射

java.lang包提供java語言程序設計的基礎類,在lang包下存在一個子包:reflect,與反射相關的APIs均在此處;

官方對reflect包的介紹如下:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

java.lang.reflect官方介紹

簡單來說,反射機制就像類對照平靜的湖面,湖面映射出類的字段、方法、構造函數(shù)等信息;反射機制不僅可以看到類信息,還能針對字段、方法等做出相應的操作。

二、準備測試:實體類的創(chuàng)建

為方便解釋說明,首先創(chuàng)建一個實體類,用于測試使用

package cn.byuan.entity;

/**
 * 學生實體類
 *
 * @author byuan
 * @date 2022-01-25
 */
public class Student {

    /**
     * 學生學號, 公共變量, 默認值: defaultStudentNo
     * */
    public String studentNo = "defaultStudentNo";

    /**
     * 學生姓名, 公共變量, 默認值: defaultStudentName
     * */
    public String studentName = "defaultStudentName";

    /**
     * 學生性別, 私有變量, 默認值: defaultStudentSex
     * */
    private String studentSex = "defaultStudentSex";

    /**
     * 學生年齡, 私有變量, 默認值: 0
     * */
    private Integer studentAge = 0;

    /**
     * 公有無參構造方法
     * */
    public Student() {

    }

    /**
     * 公有滿參構造方法
     * */
    public Student(String studentNo, String studentName, String studentSex, Integer studentAge) {
        this.studentNo = studentNo;
        this.studentName = studentName;
        this.studentSex = studentSex;
        this.studentAge = studentAge;
    }

    /**
     * 私有構造方法
     * */
    private Student(String studentSex, Integer studentAge) {
        this.studentSex = studentSex;
        this.studentAge = studentAge;
    }

    /**
     * get/set 方法
     * */
    public String getStudentNo() {
        return studentNo;
    }

    public Student setStudentNo(String studentNo) {
        this.studentNo = studentNo;
        return this;
    }

    public String getStudentName() {
        return studentName;
    }

    public Student setStudentName(String studentName) {
        this.studentName = studentName;
        return this;
    }

    public String getStudentSex() {
        return studentSex;
    }

    public Student setStudentSex(String studentSex) {
        this.studentSex = studentSex;
        return this;
    }

    public Integer getStudentAge() {
        return studentAge;
    }

    public Student setStudentAge(Integer studentAge) {
        this.studentAge = studentAge;
        return this;
    }

    @Override
    public String toString() {
        return "Student{" +
                "studentNo = " + this.studentNo + ", " +
                "studentName = " + this.studentName + ", " +
                "studentSex = " + this.studentSex + ", " +
                "studentAge = " + this.studentAge +"}";
    }

    /**
     * 學生類說話方法
     * */
    private String speak(String message) {
        return this.studentName + " : " + message;
    }

}

三、反射中的幾個重要類及方法

在了解反射前,先來梳理下一個類(Class)本身中包含了哪些內容。

  • 字段,字段又由修飾符、字段類型、字段名稱、對應值等部分組成
  • 構造方法,構造方法可簡單分為無參與有參兩大類
  • 非構造方法,又稱普通方法,方法由修飾符、返回值類型、方法名、形參表、方法體等部分構成

本文所論述的反射中幾個重要類及其對應方法正基于以上內容

(一)反射中的重要類之Class

Class類代表了類本身,類本身包含字段,構造方法,非構造方法等內容,因此使用反射的第一步就是獲取對象所對應的Class類。

僅就使用反射而言,我們需著重了解Class類的獲取方式,下面給出實例

1. Class類測試實例

package cn.byuan.example;
import cn.byuan.entity.Student;
/**
 * 獲取 Class 的幾種方式
 *
 * @author byuan
 * @date 2022-01-25
 */
public class GetClassExample {
    public static void main(String[] args) throws ClassNotFoundException {
        // 獲取 class 方式一: 通過類的全路徑字符串獲取 Class 對象
        Class getClassExample1 = Class.forName("cn.byuan.entity.Student");
        // 獲取 class 方式二: 通過類名直接獲取
        Class getClassExample2 = Student.class;
        // 獲取 class 方式三: 通過已創(chuàng)建的對象獲取對應 Class
        Student student1 = new Student();
        Class getClassExample3 = student1.getClass();
    }
}

(二)反射中的重要類之Field

Field類是對類中屬性的描述,借助Class與Field的配合,我們可以了解類中有哪些字段,并做出相應處理;

1. Field類的獲取與常用方法

Class類為我們提供了兩個方法用以獲取Field類:

  • getDeclaredFields():獲取所有聲明的字段(包括公有字段和私有字段)
  • getFields():僅可獲取公有字段

Field類代表了類中的屬性字段,常用類中屬性字段可籠統(tǒng)分為兩種,公有字段(public)與私有字段(private);

每個字段又具有四個屬性:修飾符,字段類型,字段名稱,對應值;Field也自然提供了對應方法對這四種屬性進行獲?。?/p>

  • getModifiers():獲取字段修飾符相加值,想要獲取明確標識需要通過Modifier常量的toString方法對相加值進行解碼
  • getType():獲取字段類型
  • getName():獲取字段名稱
  • get(Object):獲取字段對應值

下面給出實例

2. Field類測試實例

package cn.byuan.example;

import cn.byuan.entity.Student;

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

/**
 * 獲取類字段的幾種方式
 *
 * @author byuan
 * @date 2021-01-25
 */
public class GetFieldExample {
    public static void main(String[] args) throws IllegalAccessException {
        Class studentClass = Student.class;
        // 獲取類字段的兩個方法: getDeclaredFields, getFields
        // 1. getDeclaredFields: 獲取所有聲明的字段(包括公有字段和私有字段)
        Field[] declaredFieldArray = studentClass.getDeclaredFields();
        printFieldInformation(declaredFieldArray);
        // 2. getFields: 僅可獲取公有字段
        Field[] fieldArray = studentClass.getFields();
        printFieldInformation(fieldArray);
        // 獲取字段對應值
        Student student = new Student()
                .setStudentSex("女")
                .setStudentAge(18);
        printFieldValue(student);
    }

    /**
     * 打印類字段信息
     *
     * @param fieldArray 類字段對象列表
     * */
    public static void printFieldInformation(Field[] fieldArray) {
        for (Field fieldPart : fieldArray) {
            System.out.println("直接打印類字段對象: " + fieldPart);
            // 獲取字段修飾符
            String fieldModifier = Modifier.toString(fieldPart.getModifiers());
            // 獲取字段類型
            String fieldType = fieldPart.getType().getName();
            // 獲取字段名稱
            String fieldName = fieldPart.getName();
            System.out.println(fieldModifier + " " + fieldType + " " + fieldName);
        }
        System.out.println();
    }

    /**
     * 打印類字段屬性
     *
     * @param t 泛型對象
     * */
    private static <T> void printFieldValue(T t) throws IllegalAccessException {
        Field[] fieldValueArray = t
                .getClass()
                .getDeclaredFields();
        for (Field fieldValuePart : fieldValueArray) {
            // 對于有可能存在的 private 字段取消語言訪問檢查
            fieldValuePart.setAccessible(true);
            // 字段名稱
            String filedName = fieldValuePart.getName();
            // 字段對應值
            String fieldValue = fieldValuePart.get(t).toString();
            System.out.println(filedName + " = " + fieldValue);
        }
    }
}

運行截圖

(三)反射中的重要類之Constructor

Constructor代表了某個類的構造方法,是用來管理所有的構造函數(shù)的類

1. Constructor類的獲取與常用方法

Class類為我們提供了兩個方法用以獲取Constructor類:

  1. getDeclaredConstructors():獲取所有構造方法
  2. getConstructors():僅可獲取公有構造方法

對于構造器,可簡單將其分為兩大類,無參構造器與帶參構造器,構造器也是方法的一種,因此對于任意一構造器都由修飾符,方法名,形參表,方法體四部分組成;Constructor自然也為其組成部分提供了對應方法:

  1. 與字段類似,Constructors同樣提供了getModifiers()方法:獲取構造器修飾符相加值,想要獲取明確標識需要通過Modifier常量的toString方法進行解碼
  2. getName():獲取構造器名稱
  3. getParameterTypes():獲取構造器參數(shù)列表

下面給出實例

2. Constructor類測試實例

package cn.byuan.example;
import cn.byuan.entity.Student;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

/**
 * 獲取構造方法的幾種方式
 *
 * @author byuan
 * @date 2022-01-25
 */
public class GetConstructorsExample {
    public static void main(String[] args) {
        Class studentClass = Student.class;
        // 獲取類構造器的兩個方法: getDeclaredConstructors, getConstructors
        // 1. getDeclaredConstructors: 獲取所有構造方法
        Constructor[] declaredConstructorArray = studentClass.getDeclaredConstructors();
        printConstructorInformation(declaredConstructorArray);
        // 2. getConstructors, 僅可獲取公有構造方法
        Constructor[] constructorArray = studentClass.getConstructors();
        printConstructorInformation(constructorArray);
    }

    /**
     * 打印構造器信息
     *
     * @param constructorArray 構造器對象列表
     * */
    public static void printConstructorInformation(Constructor[] constructorArray) {
        for (Constructor constructorPart : constructorArray) {
            System.out.println("直接打印構造器對象: " + constructorPart);
            // 獲取構造器修飾符
            String constructorModifier = Modifier.toString(constructorPart.getModifiers());
            // 獲取構造器名稱
            String constructorName = constructorPart.getName();
            // 獲取構造器參數(shù)列表
            Class[] constructorParameterArray = constructorPart.getParameterTypes();
            // 打印構造器參數(shù)列表
            System.out.print(constructorModifier + " " + constructorName + "(");
            for (Class constructorParameterPart : constructorParameterArray) {
                System.out.print(constructorParameterPart.getName() + " ");
            }
            System.out.println(")");
        }
        System.out.println();
    }
}

運行截圖

3. 利用Constructor類實例化對象

一般而言,我們關心的不只是獲取到對象構造器的具體信息,更重要的是如何利用反射實例化對象,針對對象實例化,Constructor提供了兩種類型的方法:

  1. getConstructor(Class<?>... parameterTypes):獲取指定形參表的構造方法,可借助其獲取無參/指定參數(shù)的構造方法;
  2. newInstance(Object ... initargs):通過形參表傳遞實例化對象參數(shù),與getConstructor配合使用;

注意:Class也存在newInstance()方法,但僅能用來調用類的無參構造器

4. Constructor實例化對象測試實例

package cn.byuan.example;
import cn.byuan.entity.Student;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 構造器調用實例
 *
 * @author byuan
 * @date 2022-01-26
 */
public class ConstructorsInvokeExample {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class studentClass = Student.class;
        // Class 類的 newInstance 方法
        studentClass.newInstance();
        // 1. 調用公有無參構造器
        Object object1 = studentClass
                .getConstructor()
                .newInstance();
        System.out.println(object1.getClass());
        // 2. 調用公有滿參構造器
        Constructor studentConstructorFull = studentClass
                .getConstructor(String.class, String.class, String.class, Integer.class);
        Object object2 = studentConstructorFull
                .newInstance("2022001", "趙一", "男", 18);
        System.out.println(object2);
        // 3. 調用私有構造器
        Constructor studentConstructorPrivate = studentClass
                .getDeclaredConstructor(String.class, Integer.class);
        // 私有構造器需將 accessible 設置為 true, 取消語言訪問檢查
        studentConstructorPrivate.setAccessible(true);
        Object object3 = studentConstructorPrivate
                .newInstance("女", 19);
        System.out.println(object3);
    }
}

運行截圖

(四)反射中的重要類之Method

Method類描述了類的方法信息

1. Method類的獲取與常用方法

Class類為我們提供了兩個方法用以獲取Method類:

  1. getDeclaredMethods():獲取所有非構造方法
  2. getMethods():僅可獲取公有非構造方法

對于任意方法都可分為修飾符,方法名,形參表,方法體四部分;Method為其組成部分提供了對應方法:

  1. getModifiers():獲取方法修飾符相加值,想要獲取明確標識需要通過Modifier常量的toString方法進行解碼
  2. getName():獲取方法名稱
  3. getParameterTypes():獲取方法形參表

2. Method類測試實例

package cn.byuan.example;
import cn.byuan.entity.Student;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 獲取非構造方法的幾種方式
 *
 * @author byuan
 * @date 2022-01-26
 */
public class GetMethodExample {
    public static void main(String[] args) {
        Class studentClass = Student.class;
        // 獲取非構造方法的兩個方法: getDeclaredMethods, getMethods
        // 1. getDeclaredMethods: 獲取所有非構造方法
        Method[] declaredMethodArray = studentClass.getDeclaredMethods();
        printMethodInformation(declaredMethodArray);
        // 2. getMethods, 僅可獲取公有非構造方法
        Method[] methodArray = studentClass.getMethods();
        printMethodInformation(methodArray);
    }

    /**
     * 打印非構造器方法信息
     *
     * @param methodArray 構造器對象列表
     * */
    public static void printMethodInformation(Method[] methodArray) {
        for (Method methodPart : methodArray) {
            System.out.println("直接打印非構造方法對象: " + methodArray);
            // 獲取非構造器方法修飾符
            String methodModifier = Modifier.toString(methodPart.getModifiers());
            // 獲取非構造器方法名稱
            String methodName = methodPart.getName();
            String methodReturnType = methodPart.getReturnType().getName();
            // 獲取非構造方法參數(shù)列表
            Class[] constructorParameterArray = methodPart.getParameterTypes();
            // 打印非構造方法參數(shù)列表
            System.out.print(methodModifier + " " + methodReturnType + " " + methodName + "(");
            for (Class methodParameterPart : constructorParameterArray) {
                System.out.print(methodParameterPart.getName() + " ");
            }
            System.out.println(")");
        }
        System.out.println();
    }
}

運行截圖

3. 利用Method調用非構造方法

與利用Constructor實例化對象相似,Method同樣需要兩個方法用以調用非構造方法

  1. getDeclaredMethod(方法名, 形參表數(shù)組): 獲取所有構造方法
  2. invoke(對象實例, 參數(shù)數(shù)組):方法調用

4. Method調用非構造方法測試實例

package cn.byuan.example;
import cn.byuan.entity.Student;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 非構造器方法調用實例
 *
 * @author byuan
 * @date 2022-01-26
 */
public class MethodInvokeExample {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        Class studentClass = Student.class;
        // 對于私有的非構造方法, 需要使用 getDeclaredMethod 進行獲取
        // getDeclaredMethod(方法名, 形參表數(shù)組)
        Method studentSpeakMethod = studentClass.getDeclaredMethod("speak", new Class[]{String.class});
        // 取消語言訪問檢查
        studentSpeakMethod.setAccessible(true);
        // invoke(對象實例, 參數(shù)數(shù)組)
        Object object = studentSpeakMethod.invoke(studentClass.newInstance(), "Hello, world");
        System.out.println(object);
    }
}

運行截圖

四、綜合實戰(zhàn):利用反射機制編寫對象拷貝工具類

在實際項目中,我們經(jīng)常會遇到POJO與VO等類型對象進行相互轉換的情況,如果直接進行轉換則會使用大量的樣板代碼,為消除這樣的代碼,我們可以寫一個簡單的對象拷貝工具類進行解決;

(一)業(yè)務分析

通過反射獲取源對象Field數(shù)組,并利用Field類提供的set/get方法實現(xiàn)同名屬性的拷貝;

(二)實體類準備

創(chuàng)建Student類

package cn.byuan.entity;

/**
 * 學生實體類
 *
 * @author byuan
 * @date 2022-01-25
 */
public class Student {

    /**
     * 學生學號, 公共變量, 默認值: defaultStudentNo
     * */
    public String studentNo = "defaultStudentNo";

    /**
     * 學生姓名, 公共變量, 默認值: defaultStudentName
     * */
    public String studentName = "defaultStudentName";

    /**
     * 學生性別, 私有變量, 默認值: defaultStudentSex
     * */
    private String studentSex = "defaultStudentSex";

    /**
     * 學生年齡, 私有變量, 默認值: 0
     * */
    private Integer studentAge = 0;

    /**
     * 公有無參構造方法
     * */
    public Student() {

    }

    /**
     * 公有滿參構造方法
     * */
    public Student(String studentNo, String studentName, String studentSex, Integer studentAge) {
        this.studentNo = studentNo;
        this.studentName = studentName;
        this.studentSex = studentSex;
        this.studentAge = studentAge;
    }

    /**
     * 私有構造方法
     * */
    private Student(String studentSex, Integer studentAge) {
        this.studentSex = studentSex;
        this.studentAge = studentAge;
    }

    public String getStudentNo() {
        return studentNo;
    }

    public Student setStudentNo(String studentNo) {
        this.studentNo = studentNo;
        return this;
    }

    public String getStudentName() {
        return studentName;
    }

    public Student setStudentName(String studentName) {
        this.studentName = studentName;
        return this;
    }

    public String getStudentSex() {
        return studentSex;
    }

    public Student setStudentSex(String studentSex) {
        this.studentSex = studentSex;
        return this;
    }

    public Integer getStudentAge() {
        return studentAge;
    }

    public Student setStudentAge(Integer studentAge) {
        this.studentAge = studentAge;
        return this;
    }

    @Override
    public String toString() {
        return "Student{" +
                "studentNo = " + this.studentNo + ", " +
                "studentName = " + this.studentName + ", " +
                "studentSex = " + this.studentSex + ", " +
                "studentAge = " + this.studentAge +"}";
    }

    /**
     * 學生類說話方法
     * */
    private String speak(String message) {
        return this.studentName + " : " + message;
    }
}

創(chuàng)建StudentOut類

package cn.byuan.api.out;

import cn.byuan.entity.Student;

/**
 * 學生類出參
 *
 * @author byuan
 * @date 2022-01-26
 */
public class StudentOut {
    /**
     * 學生學號, 公共變量
     * */
    private String studentNo;

    /**
     * 學生姓名, 公共變量
     * */
    private String studentName;

    /**
     * 學生性別, 私有變量
     * */
    private String studentSex;

    /**
     * 學生年齡, 私有變量
     * */
    private Integer studentAge;

    public String getStudentNo() {
        return studentNo;
    }

    public StudentOut setStudentNo(String studentNo) {
        this.studentNo = studentNo;
        return this;
    }

    public String getStudentName() {
        return studentName;
    }

    public StudentOut setStudentName(String studentName) {
        this.studentName = studentName;
        return this;
    }

    public String getStudentSex() {
        return studentSex;
    }

    public StudentOut setStudentSex(String studentSex) {
        this.studentSex = studentSex;
        return this;
    }

    public Integer getStudentAge() {
        return studentAge;
    }

    public StudentOut setStudentAge(Integer studentAge) {
        this.studentAge = studentAge;
        return this;
    }

    @Override
    public String toString() {
        return "StudentOut{" +
                "studentNo = " + this.studentNo + ", " +
                "studentName = " + this.studentName + ", " +
                "studentSex = " + this.studentSex + ", " +
                "studentAge = " + this.studentAge +"}";
    }
}

(三)工具類編寫

package cn.byuan.util;
import cn.byuan.api.out.StudentOut;
import cn.byuan.entity.Student;
import java.lang.reflect.Field;

/**
 * 對象屬性拷貝工具類
 *
 * @author byuan
 * @date 2022-01-26
 */
public class BeanUtil {
    /**
     * 對象拷貝工具
     *
     * @param sourceObject 源對象
     * @param destClass 目的對象對應 Class
     *
     * @return 拷貝完畢后對象
     * */
    public static <T> T copyObject(Object sourceObject, Class<T> destClass) {
        if (sourceObject == null) {
            return null;
        }

        try {

            T destObject = destClass.newInstance();

            copyField(sourceObject, destObject);

            return destObject;

        } catch (InstantiationException e) {
            e.printStackTrace();
            
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 對象屬性拷貝工具
     *
     * @param sourceObject 源對象
     * @param destObject 目的對象
     * */
    private static void copyField(Object sourceObject, Object destObject) {
        if (sourceObject == null || destObject == null) {
            return;
        }

        // 獲取源對象所有字段
        Field[] sourceFieldArray = sourceObject.getClass().getDeclaredFields();
        for (Field sourceFieldPart : sourceFieldArray) {
            // 取消語言訪問檢查
            sourceFieldPart.setAccessible(true);
            String sourceFieldName = sourceFieldPart.getName();
            try {
                // 根據(jù)屬性名稱獲取目標對象對應類字段
                Field destField = destObject
                        .getClass()
                        .getDeclaredField(sourceFieldName);
                destField.setAccessible(true);
                destField.set(destObject, sourceFieldPart.get(sourceObject));
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) {
        Student student = new Student("2022001", "趙一", "男", 18);
        StudentOut studentOut = copyObject(student, StudentOut.class);
        System.out.println(studentOut);
    }
}

運行截圖

 總結

到此這篇關于Java高級語法學習之反射的文章就介紹到這了,更多相關Java高級語法反射內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論