Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

นี่คือโพสต์ที่แปลด้วย AI

제이온

[Java] แนวคิด Reflection และวิธีการใช้งาน

เลือกภาษา

  • ไทย
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

สรุปโดย AI ของ durumis

  • Reflection เป็น API ที่ช่วยให้เข้าถึงข้อมูลเกี่ยวกับคลาสในขณะที่โปรแกรมกำลังทำงานและสามารถจัดการกับคลาสนั้นได้ตามต้องการ
  • Reflection ช่วยให้สามารถสร้างอินสแตนซ์ของคลาสและเข้าถึงฟิลด์และเมธอดโดยไม่คำนึงถึงตัวควบคุมการเข้าถึง ซึ่งมีประโยชน์อย่างยิ่งในการจัดการการพึ่งพาแบบไดนามิกในขั้นตอนการพัฒนาขนาดใหญ่ เช่น ในกรอบงาน
  • อย่างไรก็ตาม ควรใช้ Reflection เฉพาะในกรณีที่จำเป็นเท่านั้น เนื่องจากอาจส่งผลต่อการปิดบังข้อมูลและทำให้ประสิทธิภาพลดลง

การสะท้อนคืออะไร?

การสะท้อนคือ API ที่ช่วยให้คุณสามารถสร้างอินสแตนซ์ของคลาสที่ต้องการได้โดยใช้วัตถุประเภทคลาสที่โหลดในพื้นที่ฮีป และช่วยให้คุณสามารถเข้าถึงฟิลด์และเมธอดของอินสแตนซ์ได้โดยไม่คำนึงถึงตัวควบคุมการเข้าถึง



ที่นี่ คลาสที่โหลดหมายถึง JVM คลาสโหลดเดอร์ได้ทำการโหลดไฟล์คลาสแล้ว และสร้างวัตถุประเภทคลาสที่เก็บข้อมูลของคลาสนั้นไว้ในพื้นที่ฮีป โปรดทราบว่าสิ่งนี้แตกต่างจากวัตถุที่สร้างขึ้นโดยใช้คีย์เวิร์ด new หากคุณไม่เข้าใจวัตถุประเภทคลาส คุณสามารถตรวจสอบเอกสาร JDK สำหรับวัตถุ java.lang.class ได้


วิธีการใช้งาน

ก่อนที่จะใช้การสะท้อน คุณต้องรับวัตถุประเภทคลาสที่โหลดในพื้นที่ฮีป มี 3 วิธี


  • รับจากคลาส.class
  • รับจากอินสแตนซ์.getClass()
  • รับจาก Class.forName("ชื่อคลาส")


public class Member {

    private String name;

    protected int age;

    public String hobby;

    public Member() {
    }

    public Member(String name, int age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
    }

    public void speak(String message) {
        System.out.println(message);
    }

    private void secret() {
        System.out.println("รหัสผ่านคือ 1234");
    }

    @Override
    public String toString() {
        return "Member{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", hobby='" + hobby + '\'' +
            '}';
    }
}

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {
        Class memberClass = Member.class;
        System.out.println(System.identityHashCode(memberClass));

        Member member = new Member("เจย์ออน", 23, "พัฒนา DARA");
        Class memberClass2 = member.getClass();
        System.out.println(System.identityHashCode(memberClass2));

        Class memberClass3 = Class.forName("{ชื่อแพ็คเกจ}.Member");
        System.out.println(System.identityHashCode(memberClass3));
    }
}

// ผลลัพธ์การดำเนินการ
1740000325
1740000325

คุณสามารถเห็นได้ว่าอินสแตนซ์ประเภทคลาสที่ได้รับจาก 3 วิธีนั้นเหมือนกัน ไม่ว่าคุณจะใช้วิธีใด ค่าแฮชจะเหมือนกัน ดังนั้นคุณสามารถเลือกใช้ตามสถานการณ์ได้


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


public class Main {

    public static void main(String[] args) throws Exception {
        // พิมพ์คอนสตรัคเตอร์ทั้งหมดของ Member
        Member member = new Member();
        Class memberClass = member.getClass();
        Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);

        // สร้างอินสแตนซ์โดยใช้คอนสตรัคเตอร์เริ่มต้นของ Member
        Constructor constructor = memberClass.getConstructor();
        Member member2 = constructor.newInstance();
        System.out.println("member2 = " + member2);

        // สร้างอินสแตนซ์โดยใช้คอนสตรัคเตอร์อื่นของ Member
        Constructor fullConstructor =
            memberClass.getConstructor(String.class, int.class, String.class);
        Member member3 = fullConstructor.newInstance("เจย์ออน", 23, "พัฒนา DARA");
        System.out.println("member3 = " + member3);
    }
}

// ผลลัพธ์การดำเนินการ
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}

คุณสามารถรับคอนสตรัคเตอร์ได้โดยใช้ getConstructor() และสร้างอินสแตนซ์ของ Member ได้โดยใช้ newInstance()

สุดท้าย ลองเข้าถึงฟิลด์และเมธอดของอินสแตนซ์โดยไม่คำนึงถึงตัวควบคุมการเข้าถึง

public class Main {

    public static void main(String[] args) throws Exception {
        Member member = new Member("เจย์ออน", 23, "พัฒนา DARA");
        Class memberClass = member.getClass();

        // เข้าถึงฟิลด์
        Field[] fields = memberClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            System.out.println(field.get(member));
        }
        fields[0].set(member, "เจย์ออน2");
        System.out.println(member);

        // เข้าถึงเมธอด
        Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
        speakMethod.invoke(member, "ทดสอบการสะท้อน");

        Method secretMethod = memberClass.getDeclaredMethod("secret");
        secretMethod.setAccessible(true);
        secretMethod.invoke(member);
    }
}

// ผลลัพธ์การดำเนินการ
เจย์ออน
23
พัฒนา DARA
Member{name='เจย์ออน2', age=23, hobby='พัฒนา DARA'}
ทดสอบการสะท้อน

คุณสามารถรับตัวแปรอินสแตนซ์ทั้งหมดของคลาสได้โดยใช้ getDeclaredFileds() และสามารถรับค่าฟิลด์ได้โดยใช้ get() และสามารถแก้ไขค่าฟิลด์ได้โดยใช้ set() โปรดทราบว่าเมื่อเข้าถึงฟิลด์ที่มีตัวควบคุมการเข้าถึง private คุณต้องส่ง true เป็นอาร์กิวเมนต์ไปยัง setAccessible()


คุณยังสามารถรับเมธอดได้โดยใช้ getDeclaredMethod() ด้วย ในกรณีนี้ คุณต้องส่งชื่อเมธอดและประเภทของพารามิเตอร์เป็นอาร์กิวเมนต์ เช่นเดียวกัน คุณต้องตั้งค่าอาร์กิวเมนต์ของ setAccessible() เป็น true เมื่อเข้าถึงเมธอดที่มีตัวควบคุมการเข้าถึง private สุดท้าย คุณสามารถเรียกใช้เมธอดที่ได้รับจาก API การสะท้อนโดยใช้เมธอด invoke()


ข้อดีข้อเสีย

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


เหตุผลในการใช้งาน

คุณสามารถเข้าถึงข้อมูลคลาสและปรับแต่งคลาสได้ตามต้องการในขณะรันไทม์ผ่าน API การสะท้อน แม้แต่ฟิลด์หรือเมธอดที่ประกาศโดยใช้ตัวควบคุมการเข้าถึง private ก็สามารถปรับแต่งได้ ดูเหมือนว่าจะเป็นเทคนิคที่ไม่ควรใช้เนื่องจากละเมิดการห่อหุ้มซึ่งเป็นสิ่งสำคัญในแบบจำลองการออกแบบเชิงวัตถุ


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


เช่น ใน Spring Bean Factory คุณสามารถเห็นได้ว่า Bean Factory จะสร้างและจัดการคลาสที่มีการแนบ @Controller, @Service, @Repository เป็นต้น แม้ว่านักพัฒนาจะไม่ได้แจ้งคลาสนั้นไปยัง Bean Factory แต่สิ่งนี้เป็นไปได้เนื่องจากการสะท้อน ในขณะรันไทม์ หากพบคลาสที่มีการแนบการอธิบายประกอบนั้น การสะท้อนจะใช้เพื่อสร้างอินสแตนซ์ของคลาสนั้น ใส่ฟิลด์ที่จำเป็น และเก็บไว้ใน Bean Factory


แน่นอน เนื่องจากละเมิดการห่อหุ้ม จึงควรใช้การสะท้อนเฉพาะในกรณีที่จำเป็นเท่านั้น


แหล่งที่มา

제이온
제이온
제이온
제이온
[Effective Java] รายการที่ 2. พิจารณาตัวสร้างหากมีพารามิเตอร์มากมาย เมื่อสร้างวัตถุที่มีพารามิเตอร์มากมาย การใช้รูปแบบตัวสร้างจะช่วยให้คุณเขียนโค้ดได้ชัดเจนและอ่านง่ายขึ้น สร้างวัตถุตัวสร้างด้วยพารามิเตอร์ที่จำเป็น และตั้งค่าพารามิเตอร์ทางเลือกด้วยเมธอด setter จากนั้นเรียกใช้เมธอด build() เพื่อทำให้วัตถุเสร็จสมบูรณ์ รูปแบ

27 เมษายน 2567

[Effective Java] รายการ 4. ใช้ตัวสร้างส่วนตัวเพื่อป้องกันการสร้างอินสแตนซ์ สำหรับคลาสยูทิลิตี้ที่มีเพียงเมธอดคงที่และฟิลด์ ควรตั้งค่าตัวสร้างให้เป็นส่วนตัวเพื่อป้องกันการสร้างอินสแตนซ์ วิธีนี้จะช่วยป้องกันผู้ใช้จากการเข้าใจผิดว่าตัวสร้างถูกสร้างขึ้นโดยอัตโนมัติ และทำให้ไม่สามารถสืบทอดได้ ทำให้ความตั้งใจของคลาสชัดเจนขึ้น

28 เมษายน 2567

[Effective Java] รายการ 6. หลีกเลี่ยงการสร้างอ็อบเจ็กต์ที่ไม่จำเป็น คู่มือเกี่ยวกับวิธีลดการสร้างอ็อบเจ็กต์ที่ไม่จำเป็นใน Java อ็อบเจ็กต์แบบไม่เปลี่ยนแปลง เช่น String, Boolean ควรใช้ลิเทอรัล และควรแคชอินสแตนซ์ Pattern สำหรับนิพจน์ทั่วไป นอกจากนี้ การออโต้บอกซ์อาจทำให้ประสิทธิภาพลดลง ดังนั้นจึงควรใช้ประเภทพื้นฐาน รายละเอีย

28 เมษายน 2567

[Javascript] โครงสร้างของวัตถุ (V8) วัตถุของ JavaScript ในเครื่องยนต์ V8 ถูกแปลงเป็น Fast mode ที่ปรับให้เหมาะสมเหมือนโครงสร้างข้อมูลตามสถานะและ Dictionary mode ที่ทำงานเป็นแฮชแมป Fast mode เร็วเนื่องจากคีย์และค่าอยู่ในรูปแบบคงที่เกือบทั้งหมด แต่เมื่อมีการเพิ่มคีย์ใหม่หรือดำเนินการลบองค์ประ
곽경직
곽경직
곽경직
곽경직
곽경직

18 มีนาคม 2567

JWT (JSON Web Token) คืออะไร? JSON Web Token (JWT) เป็นมาตรฐานเปิดสำหรับการส่งข้อมูลอย่างปลอดภัย โดยใช้โทเค็นที่ลงนามเพื่อรักษาความสมบูรณ์และความปลอดภัยของข้อมูล ส่วนหัวประกอบด้วยประเภทโทเค็นและอัลกอริทึมการลงนาม และเพย์โหลดประกอบด้วยข้อมูลผู้ใช้ที่ผู้พัฒนาต้องการ รวมอยู่ด้วย JWT ที่ล
Seize the day
Seize the day
Seize the day
Seize the day
Seize the day

4 มีนาคม 2567

[การสอบช่างฝีมือระดับสูงสาขาโลหะวิทยา] 39 ครั้ง การแก้ปัญหา บล็อกโพสต์นี้ครอบคลุมเนื้อหาพื้นฐานเกี่ยวกับสมบัติเชิงกลของวัสดุ การอบชุบความร้อน วิธีการทดสอบ และการตรวจสอบแบบไม่ทำลาย บทความนี้ได้อธิบายแนวคิดและคำศัพท์ต่างๆ เช่น ความต้านทานแรงดึง ความแข็ง การชุบแข็งด้วยคาร์บอน การทดสอบการปล่อยคลื่นเสียง เป็นต้น
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi
blog.naver.com/gksmftordldi

24 เมษายน 2567

วิธีที่ Rust ป้องกันบั๊กแบบพร้อมกัน Rust เป็นภาษาที่ทรงพลังในการแก้ปัญหาความท้าทายของการเขียนโปรแกรมแบบพร้อมกัน ระบบประเภทและแบบจำลองการเป็นเจ้าของทำให้การส่งผ่านและการแชร์ข้อมูลระหว่างเธรดปลอดภัย Mutex, Channel, Atomic และรูปแบบความแปรปรวนภายในอื่น ๆ ช่วยให้คุณกำหนดและใช้ตัวแปรที่แชร์ได้อย
곽경직
곽경직
곽경직
곽경직
곽경직

28 มีนาคม 2567

[ไม่มีพื้นฐานทางวิศวกรรมคอมพิวเตอร์ การอยู่รอดในฐานะนักพัฒนา] 14. สรุปเนื้อหาการสัมภาษณ์ทางเทคนิคที่นักพัฒนาหน้าใหม่ถามบ่อย คู่มือเตรียมตัวสัมภาษณ์งานเทคนิคสำหรับนักพัฒนาหน้าใหม่ บทความนี้จะอธิบายแนวคิดที่มักปรากฏใน การสัมภาษณ์งาน เช่น พื้นที่หน่วยความจำหลัก โครงสร้างข้อมูล RDBMS และ NoSQL การเขียนโปรแกรมเชิงโครงสร้างและเชิงวัตถุ การโอเวอร์ไรด์และการโอเวอร์โหลด อัลกอริทึมการเป
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 เมษายน 2567

[นอกสายงาน วิศวกร สู้ชีวิต] 17. พอร์ตโฟลิโอของวิศวกรมือใหม่ ไปถึงไหน? พอร์ตโฟลิโอของวิศวกรมือใหม่ควรเน้นไปที่ทักษะการพัฒนา ซอฟต์แวร์ การติดตั้ง Infra ทั้งหมดนั้นไม่จำเป็นเท่ากับการสร้างฟังก์ชัน CRUD พื้นฐาน และการสะสมประสบการณ์การเชื่อมต่อ API ภายนอก สามารถลองใช้ API เช่น การเข้าสู่ระบบของ Naver, API แผนที่ Naver, API ของ
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 เมษายน 2567