Java บทช่วยสอน Reflection API พร้อมตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

Java Reflection API วิเคราะห์และแก้ไขความสามารถของคลาสในขณะรันไทม์ รวมถึงฟิลด์ เมธอด และคอนสตรัคเตอร์ เอกสารนี้จะอธิบายแพ็กเกจ java.lang.reflect เมธอดหลักของ java.lang.Class และตัวอย่างสี่ตัวอย่างที่อ่านเมตาเดตาของคลาส ตัวแปร เมธอด และคอนสตรัคเตอร์

  • 🔍 ความหมาย: Reflection ตรวจสอบและเปลี่ยนแปลงคลาสและสมาชิกของคลาสเหล่านั้นในระหว่างการทำงาน แม้แต่สมาชิกที่เป็นส่วนตัวก็ตาม
  • 📦 แพ็คเกจ Reflect: คลาส Field, Method, Constructor และ Modifier รวบรวมข้อมูลเชิงประกาศเกี่ยวกับสมาชิก
  • 🏷️ เมธอดของคลาส: เมธอด getName(), getSuperclass(), getInterfaces() และ getModifiers() จะส่งคืนเมตาเดตาหลักของคลาส
  • 🧪 ตัวอย่างการใช้งาน: สี่โปรแกรม เช่นtracเมตาเดต้าของคลาส ตัวแปร เมธอด และคอนสตรัคเตอร์
  • ⚠️ ข้อควรระวัง: ฟังก์ชัน Reflection สามารถเข้าถึงสมาชิกส่วนตัวได้และมีความเร็วช้ากว่า ดังนั้นควรใช้เป็นทางเลือกสุดท้าย

Java บทช่วยสอนการใช้งาน Reflection API

การสะท้อนกลับอยู่ในอะไร Java?

Java Reflection คือกระบวนการวิเคราะห์และแก้ไขความสามารถทั้งหมดของคลาสในขณะรันไทม์ API ของ Reflection ใน... Java ใช้สำหรับจัดการคลาสและสมาชิกของคลาส ซึ่งรวมถึงฟิลด์ เมธอด คอนสตรัคเตอร์ ฯลฯ ในระหว่างการทำงานของโปรแกรม

ข้อดีอย่างหนึ่งของ Reflection API คือ Java ข้อดีคือมันสามารถควบคุมสมาชิกส่วนตัวของคลาสได้ด้วยเช่นกัน

แพ็กเกจ java.lang.reflect มีคลาสมากมายที่ใช้สำหรับการสร้าง Reflection เมธอดของคลาส java.lang.Class ใช้สำหรับรวบรวมข้อมูลเมตาที่สมบูรณ์ของคลาสใดคลาสหนึ่ง

คลาสในแพ็คเกจ java.lang.reflect

ต่อไปนี้เป็นรายการของ ต่างๆ Java ชั้นเรียน ในแพ็กเกจ java.lang.reflect เพื่อใช้งาน reflection:

  • สนาม: คลาสนี้ใช้สำหรับรวบรวมข้อมูลเชิงประกาศ เช่น ชนิดข้อมูล ตัวแก้ไขการเข้าถึง ชื่อ และค่าของตัวแปร
  • วิธีการ: คลาสนี้ใช้สำหรับรวบรวมข้อมูลเชิงประกาศ เช่น ตัวแก้ไขการเข้าถึง ประเภทค่าส่งคืน ชื่อ ประเภทพารามิเตอร์ และประเภทข้อยกเว้นของเมธอด
  • นวกรรมิก: คลาสนี้ใช้สำหรับรวบรวมข้อมูลเชิงประกาศ เช่น ตัวแก้ไขการเข้าถึง ชื่อ และประเภทพารามิเตอร์ของคอนสตรัคเตอร์
  • ตัวดัดแปลง: คลาสนี้ใช้สำหรับรวบรวมข้อมูลเกี่ยวกับตัวแก้ไขการเข้าถึงเฉพาะตัวหนึ่ง

วิธีการที่ใช้ใน java.lang.Class

  • สาธารณะ String getName(): ส่งคืนชื่อของคลาส
  • คลาสสาธารณะ getSuperclass(): ส่งคืนค่าอ้างอิงของคลาสแม่
  • คลาสสาธารณะ[] รับอินเทอร์เฟซ(): ส่งคืนอาร์เรย์ของอินเทอร์เฟซที่คลาสที่ระบุได้นำไปใช้งาน
  • public int getModifiers(): ส่งคืนค่าจำนวนเต็มที่แสดงถึงตัวแก้ไขของคลาสที่ระบุ ซึ่งจำเป็นต้องส่งเป็นพารามิเตอร์ไปยังเมธอด “public static String toString(int i)” ที่ส่งคืนตัวระบุการเข้าถึงสำหรับคลาสที่กำหนด

วิธีรับข้อมูลที่สมบูรณ์เกี่ยวกับชั้นเรียน

เพื่อรับข้อมูลเกี่ยวกับ ตัวแปรนอกเหนือจากเมธอดและคอนสตรัคเตอร์ของคลาสแล้ว เราจำเป็นต้องสร้างอ็อบเจ็กต์ของคลาส ตัวอย่างต่อไปนี้แสดงวิธีการต่างๆ ในการสร้างอ็อบเจ็กต์ของคลาส “Class”:

วิธีการที่ใช้ใน java.lang.Class

public class Guru99ClassObjectCreation {
    public static void main(String[] args) throws ClassNotFoundException {
        // 1 - By using Class.forName() method
        Class c1 = Class.forName("Guru99ClassObjectCreation");
        // 2 - By using getClass() method
        Guru99ClassObjectCreation guru99Obj = new Guru99ClassObjectCreation();
        Class c2 = guru99Obj.getClass();
        // 3 - By using .class
        Class c3 = Guru99ClassObjectCreation.class;
    }
}

ตัวอย่างที่ 1: วิธีการดึงข้อมูลเมตาของคลาส

ตัวอย่างต่อไปนี้แสดงวิธีการดึงข้อมูลเมตา เช่น ชื่อคลาส ชื่อคลาสแม่ อินเทอร์เฟซที่ใช้งาน และตัวแก้ไขการเข้าถึงของคลาส

เราจะได้รับเมตาเดต้าของคลาสที่มีชื่อว่าด้านล่างนี้ Guru99Base.class:

รับข้อมูลเมตาของคลาส

import java.io.Serializable;
public abstract class Guru99Base implements Serializable, Cloneable {
}
  1. ชื่อของชั้นเรียนคือ: Guru99ฐาน
  2. ตัวแก้ไขการเข้าถึงคือ: public และ abstract
  3. มีการใช้งานอินเทอร์เฟซ: Serializable และ Cloneable
  4. เนื่องจากไม่ได้สืบทอดมาจากคลาสใด ๆ โดยตรง ดังนั้นคลาสแม่ของมันจึงเป็น: java.lang.Object

คลาสด้านล่างนี้จะได้รับเมตาเดตาของ Guru99Base.class แล้วพิมพ์ออกมา:

รับข้อมูลเมตาของคลาส

import java.lang.reflect.Modifier;
public class Guru99GetclassMetaData {
    public static void main(String[] args) throws ClassNotFoundException {
        // Create Class object for Guru99Base.class
        Class<Guru99Base> guru99ClassObj = Guru99Base.class;

        // Print name of the class
        System.out.println("Name of the class is : " + guru99ClassObj.getName());

        // Print super class name
        System.out.println("Name of the super class is : " + guru99ClassObj.getSuperclass().getName());

        // Get the list of implemented interfaces using getInterfaces() method
        Class[] guru99InterfaceList = guru99ClassObj.getInterfaces();

        // Print the implemented interfaces using a for-each loop
        System.out.print("Implemented interfaces are : ");
        for (Class guru99class1 : guru99InterfaceList) {
            System.out.print(guru99class1.getName() + " ");
        }
        System.out.println();

        // Get access modifiers using getModifiers() and Modifier.toString()
        int guru99AccessModifier = guru99ClassObj.getModifiers();
        System.out.println("Access modifiers of the class are : " + Modifier.toString(guru99AccessModifier));
    }
}
  1. แสดงชื่อคลาสโดยใช้เมธอด getName()
  2. แสดงชื่อของคลาสแม่โดยใช้เมธอด getSuperclass().getName()
  3. แสดงชื่อของอินเทอร์เฟซที่ถูกใช้งาน
  4. แสดงตัวแก้ไขการเข้าถึงที่คลาสใช้

รับข้อมูลเมตาของคลาส

รับข้อมูลเมตาของคลาส

ตัวอย่างที่ 2: วิธีการดึงข้อมูลเมตาของตัวแปร

ตัวอย่างต่อไปนี้แสดงวิธีการดึงข้อมูลเมตาของตัวแปร

ในที่นี้ เรากำลังสร้างคลาสชื่อ... Guruไฟล์ 99VariableMetaData.class ที่มีตัวแปรบางส่วน:

package guru;
public class Guru99VariableMetaData {
    public static int guru99IntVar1 = 1111;
    static int guru99IntVar2 = 2222;
    static String guru99StringVar1 = "guru99.com";
    static String guru99StringVar2 = "Learning Reflection API";
}

ขั้นตอนในการรับข้อมูลเมตาเกี่ยวกับตัวแปรในคลาสข้างต้น:

  1. สร้างอ็อบเจ็กต์คลาสของคลาสข้างต้น กล่าวคือ Guru99VariableMetaData.class ดังต่อไปนี้:
    Guru99VariableMetaData guru99ClassVar = new Guru99VariableMetaData();
    Class guru99ClassObjVar = guru99ClassVar.getClass();
  2. รับเมตาเดตาในรูปแบบอาร์เรย์ฟิลด์โดยใช้ รับฟิลด์() or getDeclaredFields () วิธีการดังต่อไปนี้:
    Field[] guru99Field1 = guru99ClassObjVar.getFields();
    Field[] guru99Field2 = guru99ClassObjVar.getDeclaredFields();

การขอ รับฟิลด์() เมธอดนี้จะส่งคืนเมตาเดตาของตัวแปรสาธารณะจากคลาสที่ระบุ รวมถึงจากคลาสแม่ของคลาสนั้นด้วย

การขอ getDeclaredFields () เมธอดนี้จะส่งคืนเมตาเดตาของตัวแปรทั้งหมดจากคลาสที่ระบุเท่านั้น

  1. รับชื่อของตัวแปรโดยใช้เมธอด “public String getName()”
  2. รับชนิดข้อมูลของตัวแปรโดยใช้เมธอด “public Class getType()”
  3. ดึงค่าของตัวแปรโดยใช้เมธอด “public xxx get(Field)” โดยที่ xxx อาจเป็นไบต์ ชอร์ต หรือค่าประเภทใดก็ได้ที่เราต้องการดึงมา
  4. รับค่าตัวแก้ไขการเข้าถึงของตัวแปรโดยใช้เมธอด getModifiers() และ Modifier.toString(int i)

ในที่นี้ เรากำลังเขียนคลาสเพื่อดึงข้อมูลเมตาของตัวแปรต่างๆ ที่มีอยู่ในคลาส Guru99VariableMetaData.class:

รับข้อมูลเมตาของตัวแปร

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

public class Guru99VariableMetaDataTest {
    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        // Create Class object for Guru99VariableMetaData.class
        Guru99VariableMetaData guru99ClassVar = new Guru99VariableMetaData();
        Class guru99ClassObjVar = guru99ClassVar.getClass();

        // Get the metadata of all the fields of the class
        Field[] guru99Field1 = guru99ClassObjVar.getDeclaredFields();

        // Print name, data types, access modifiers and values of the variables
        for (Field field : guru99Field1) {
            System.out.println("Variable name : " + field.getName());
            System.out.println("Datatype of the variable : " + field.getType());

            int guru99AccessModifiers = field.getModifiers();
            System.out.println("Access Modifiers of the variable : " + Modifier.toString(guru99AccessModifiers));
            System.out.println("Value of the variable : " + field.get(guru99ClassVar));
            System.out.println();
        }
    }
}
  1. สร้างอ็อบเจ็กต์คลาสสำหรับ Guru99VariableMetaData.class.
  2. ได้รับเมตาเดต้าทั้งหมดของตัวแปรในอาร์เรย์ฟิลด์แล้ว
  3. พิมพ์ชื่อตัวแปรทั้งหมดในคลาส Guru99VariableMetaData.class.
  4. แสดงชนิดข้อมูลของตัวแปรทั้งหมดในคลาส
  5. พิมพ์ตัวแก้ไขการเข้าถึงทั้งหมดของตัวแปรในคลาส
  6. แสดงค่าของตัวแปรทั้งหมดในคลาส

รับข้อมูลเมตาของวิธีการ

รับข้อมูลเมตาของวิธีการ

ตัวอย่างที่ 3: วิธีการดึงข้อมูลเมตาของเมธอด

ตัวอย่างต่อไปนี้แสดงวิธีการดึงข้อมูลเมตาของเมธอด

ในที่นี้ เรากำลังสร้างคลาสชื่อ... Guru99MethodMetaData.class พร้อมด้วยเมธอดบางส่วน:

รับข้อมูลเมตาของวิธีการ

package guru;
import java.sql.SQLException;
public class Guru99MethodMetaData {

    public void guru99Add(int firstElement, int secondElement, String result)
    throws ClassNotFoundException, ClassCastException {
        System.out.println("Demo method for Reflection API");
    }
    public String guru99Search(String searchString)
    throws ArithmeticException, InterruptedException {
        System.out.println("Demo method for Reflection API");
        return null;
    }
    public void guru99Delete(String deleteString)
    throws SQLException {
        System.out.println("Demo method for Reflection API");
    }
}

ขั้นตอนในการดึงข้อมูลเมตาเกี่ยวกับเมธอดในคลาสข้างต้น:

  1. สร้างอ็อบเจ็กต์คลาสของคลาสข้างต้น กล่าวคือ Guru99MethodMetaData.class ดังต่อไปนี้:
    Guru99MethodMetaData guru99ClassVar = new Guru99MethodMetaData();
    Class guru99ClassObjVar = guru99ClassVar.getClass();
  2. ดึงข้อมูลเมธอดในอาร์เรย์ Method โดยใช้เมธอด getMethods() และ getDeclaredMethods() ดังต่อไปนี้:
    Method[] guru99Method1 = guru99ClassObjVar.getMethods();
    Method[] guru99Method2 = guru99ClassObjVar.getDeclaredMethods();

    การขอ รับวิธีการ() เมธอดนี้จะส่งคืนเมตาเดตาของเมธอดสาธารณะจากคลาสที่ระบุ รวมถึงจากคลาสแม่ของมันด้วย getDeclaredMethods () เมธอดนี้จะส่งคืนเมตาเดตาของเมธอดทั้งหมดจากคลาสที่ระบุเท่านั้น

  3. รับชื่อของเมธอดโดยใช้ getName () วิธี
  4. รับประเภทค่าส่งคืนของเมธอดโดยใช้ getReturnType() วิธี
  5. รับตัวแก้ไขการเข้าถึงของเมธอดโดยใช้ รับโมดิฟายเออร์() และ Modifier.toString(int i) วิธีการ
  6. รับประเภทพารามิเตอร์ของเมธอดโดยใช้ getParameterTypes() เมธอดที่ส่งคืนอาร์เรย์ของคลาส
  7. รับข้อยกเว้นที่ถูกโยนโดยใช้ getExceptionTypes() เมธอดที่ส่งคืนอาร์เรย์ของคลาส

ในที่นี้ เรากำลังเขียนคลาสเพื่อดึงข้อมูลเมตาของเมธอดต่างๆ ที่มีอยู่ในคลาส Guru99MethodMetaData.class:

รับข้อมูลเมตาของวิธีการ

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

public class Guru99MethodMetaDataTest {

    public static void main(String[] args) {
        // Create Class object for Guru99MethodMetaData.class
        Class guru99ClassObj = Guru99MethodMetaData.class;

        // Get the metadata of all the methods using getDeclaredMethods()
        Method[] guru99Methods = guru99ClassObj.getDeclaredMethods();

        for (Method method : guru99Methods) {
            System.out.println("Name of the method : " + method.getName());
            System.out.println("Return type of the method : " + method.getReturnType());

            int guru99ModifierList = method.getModifiers();
            System.out.println("Method access modifiers : " + Modifier.toString(guru99ModifierList));

            Class[] guru99ParamList = method.getParameterTypes();
            System.out.print("Method parameter types : ");
            for (Class class1 : guru99ParamList) {
                System.out.print(class1.getName() + " ");
            }
            System.out.println();

            Class[] guru99ExceptionList = method.getExceptionTypes();
            System.out.print("Exception thrown by method : ");
            for (Class class1 : guru99ExceptionList) {
                System.out.print(class1.getName() + " ");
            }
            System.out.println();
        }
    }
}
  1. สร้างอ็อบเจ็กต์คลาสสำหรับ Guru99MethodMetaData.class.
  2. ได้รับเมตาเดต้าทั้งหมดของทุกเมธอดในอาร์เรย์ Method แล้ว
  3. แสดงชื่อเมธอดทั้งหมดที่มีอยู่ในคลาส
  4. แสดงประเภทค่าส่งคืนของเมธอดในคลาส
  5. พิมพ์ตัวแก้ไขการเข้าถึงทั้งหมดของเมธอดในคลาส
  6. แสดงประเภทพารามิเตอร์ของเมธอดต่างๆ
  7. พิมพ์ข้อยกเว้นที่เกิดขึ้นจากเมธอดต่างๆ

รับข้อมูลเมตาของวิธีการ

รับข้อมูลเมตาของวิธีการ

ตัวอย่างที่ 4: วิธีการดึงข้อมูลเมตาของคอนสตรัคเตอร์

ตัวอย่างต่อไปนี้แสดงวิธีการดึงข้อมูลเมตาของคอนสตรัคเตอร์

ในที่นี้ เรากำลังสร้างคลาสชื่อ... Guru99Constructor.class ที่มีคอนสตรัคเตอร์ต่างกัน:

รับข้อมูลเมตาของตัวสร้าง

package guru;

import java.rmi.RemoteException;
import java.sql.SQLException;

public class Guru99Constructor {

    public Guru99Constructor(int no) throws ClassCastException, ArithmeticException { }
    public Guru99Constructor(int no, String name) throws RemoteException, SQLException { }
    public Guru99Constructor(int no, String name, String address) throws InterruptedException { }
}

ในที่นี้ เรากำลังเขียนคลาสเพื่อดึงข้อมูลเมตาของคอนสตรัคเตอร์ที่มีอยู่ในคลาส Guru99Constructor.class:

รับข้อมูลเมตาของตัวสร้าง

package guru;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class Guru99ConstructorMetaDataTest {

    public static void main(String[] args) {
        // Create Class object for Guru99Constructor.class
        Class guru99Class = Guru99Constructor.class;

        // Get all the constructor information in the Constructor array
        Constructor[] guru99ConstructorList = guru99Class.getConstructors();

        for (Constructor constructor : guru99ConstructorList) {
            System.out.println("Constructor name : " + constructor.getName());

            int guru99Modifiers = constructor.getModifiers();
            System.out.println("Constructor modifier : " + Modifier.toString(guru99Modifiers));

            Class[] guru99ParamList = constructor.getParameterTypes();
            System.out.print("Constructor parameter types : ");
            for (Class class1 : guru99ParamList) {
                System.out.print(class1.getName() + " ");
            }
            System.out.println();

            Class[] guru99ExceptionList = constructor.getExceptionTypes();
            System.out.print("Exception thrown by constructors : ");
            for (Class class1 : guru99ExceptionList) {
                System.out.print(class1.getName() + " ");
            }
            System.out.println();
        }
    }
}
  1. สร้างอ็อบเจ็กต์คลาสสำหรับ Guru99Constructor.class.
  2. ได้รับเมตาเดต้าทั้งหมดของคอนสตรัคเตอร์ทั้งหมดไว้ในอาร์เรย์คอนสตรัคเตอร์แล้ว
  3. แสดงชื่อของคอนสตรัคเตอร์ทั้งหมดที่มีอยู่ในคลาส
  4. พิมพ์ตัวแก้ไขการเข้าถึงทั้งหมดของคอนสตรัคเตอร์ในคลาส
  5. แสดงประเภทพารามิเตอร์ของคอนสตรัคเตอร์
  6. พิมพ์ข้อยกเว้นที่เกิดขึ้นจากคอนสตรัคเตอร์

รับข้อมูลเมตาของตัวสร้าง

รับข้อมูลเมตาของตัวสร้าง

คำถามที่พบบ่อย

Reflection ช่วยให้เฟรมเวิร์กและเครื่องมือ AI สามารถตรวจสอบและสร้างอินสแตนซ์ของคลาสได้ในขณะรันไทม์ นอกจากนี้ยังช่วยในเรื่องการฉีดการพึ่งพา (dependency injection), การทำให้เป็นอนุกรม (serialization) และการแมป ORM อีกด้วยpingและการโหลดปลั๊กอินแบบไดนามิกโดยไม่ทราบคลาสที่แน่นอนในระหว่างการคอมไพล์

AI สามารถสร้างโครงสร้างโค้ดการสะท้อน (reflection) ได้อย่างรวดเร็ว แต่คุณควรตรวจสอบอย่างละเอียด การสะท้อนสามารถข้ามการตรวจสอบการเข้าถึงและก่อให้เกิดความเสี่ยงด้านความปลอดภัยและประสิทธิภาพ ดังนั้นโค้ดที่สร้างขึ้นจึงจำเป็นต้องได้รับการทดสอบและตรวจสอบความถูกต้อง

การใช้ Reflection นั้นช้ากว่าการเรียกใช้เมธอดโดยตรง อาจทำลายหลักการ Encapsulation โดยการเข้าถึงสมาชิกส่วนตัว และอาจก่อให้เกิดปัญหาด้านความปลอดภัยและการบำรุงรักษา ควรใช้เฉพาะเมื่อไม่มีวิธีที่ง่ายกว่าเท่านั้น

ใช่แล้ว การใช้ setAccessible(true) ทำให้ Reflection สามารถอ่านและแก้ไขฟิลด์ส่วนตัวและเรียกใช้เมธอดส่วนตัวได้ ซึ่งมีประสิทธิภาพสำหรับการทดสอบและเฟรมเวิร์ก แต่ก็อาจทำลายหลักการห่อหุ้มข้อมูลและสร้างปัญหาด้านความปลอดภัยได้

สรุปโพสต์นี้ด้วย: