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

Đây là bài viết được dịch bởi AI.

제이온

[Java] Khái niệm và cách sử dụng Reflection

  • Ngôn ngữ viết: Tiếng Hàn Quốc
  • Quốc gia cơ sở: Tất cả các quốc gia country-flag

Chọn ngôn ngữ

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

Văn bản được tóm tắt bởi AI durumis

  • Reflection là một API cho phép truy cập thông tin lớp và thao tác lớp theo ý muốn tại thời điểm chạy.
  • Reflection cho phép tạo thể hiện của lớp, truy cập trường và phương thức bất kể bộ điều khiển truy cập, đặc biệt hữu ích trong việc quản lý các mối quan hệ động trong các giai đoạn phát triển quy mô lớn như khung.
  • Tuy nhiên, nó có thể vi phạm đóng gói và gây ra hiệu suất thấp, vì vậy tốt nhất là chỉ sử dụng nó khi cần thiết.

Phản chiếu là gì?

Phản chiếu là một API cho phép bạn tạo các thể hiện của lớp mong muốn thông qua các đối tượng loại Class được tải trong vùng heap và cho phép bạn truy cập các trường và phương thức của thể hiện, bất kể trình điều khiển truy cập.



Ở đây, các lớp được tải đề cập đến việc trình tải lớp JVM hoàn thành việc tải tệp lớp và sau đó tạo mộtđối tượng loại Classchứa thông tin về lớp đó và lưu trữ nó trong vùng heap của bộ nhớ. Hãy lưu ý rằng đây khác với các đối tượng được tạo bằng từ khóa new. Nếu bạn không hiểu rõ về đối tượng loại Class này, bạn có thể tham khảo tài liệu JDK cho java.lang.class.


Cách sử dụng

Trước khi sử dụng phản chiếu, bạn cần lấy đối tượng loại Class được tải trong vùng heap. Có tổng cộng 3 cách.


  • Lấy bằng cách sử dụng lớp.class
  • Lấy bằng cách sử dụng thể hiện.getClass()
  • Lấy bằng cách sử dụng Class.forName("tên lớp")


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("Mật khẩu là 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("Jayon", 23, "Phát triển Dara");
        Class memberClass2 = member.getClass();
        System.out.println(System.identityHashCode(memberClass2));

        Class memberClass3 = Class.forName("{tên gói}.Member");
        System.out.println(System.identityHashCode(memberClass3));
    }
}

// Kết quả chạy
1740000325
1740000325

Bạn có thể thấy rằng các thể hiện loại Class thu được bằng 3 cách đều giống nhau. Bất kể bạn sử dụng phương pháp nào, giá trị băm đều giống nhau, vì vậy bạn có thể sử dụng chúng một cách linh hoạt tùy theo hoàn cảnh.


Bây giờ, thông qua loại Class thu được, bạn có thể tạo thể hiện của lớp đó và truy cập các trường và phương thức của thể hiện, bất kể trình điều khiển truy cập. Đầu tiên, hãy thử tạo thể hiện của lớp đó.


public class Main {

    public static void main(String[] args) throws Exception {
        // In tất cả các hàm tạo của Member
        Member member = new Member();
        Class memberClass = member.getClass();
        Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);

        // Tạo thể hiện thông qua hàm tạo mặc định của Member
        Constructor constructor = memberClass.getConstructor();
        Member member2 = constructor.newInstance();
        System.out.println("member2 = " + member2);

        // Tạo thể hiện thông qua hàm tạo khác của Member
        Constructor fullConstructor =
            memberClass.getConstructor(String.class, int.class, String.class);
        Member member3 = fullConstructor.newInstance("Jayon", 23, "Phát triển Dara");
        System.out.println("member3 = " + member3);
    }
}

// Kết quả chạy
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}

Bạn có thể sử dụng getConstructor() để lấy hàm tạo và sử dụng newInstance() để động tạo thể hiện Member.

Cuối cùng, hãy thử truy cập các trường và phương thức của thể hiện, bất kể trình điều khiển truy cập.

public class Main {

    public static void main(String[] args) throws Exception {
        Member member = new Member("Jayon", 23, "Phát triển Dara");
        Class memberClass = member.getClass();

        // Truy cập trường
        Field[] fields = memberClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            System.out.println(field.get(member));
        }
        fields[0].set(member, "Jayon2");
        System.out.println(member);

        // Truy cập phương thức
        Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
        speakMethod.invoke(member, "Kiểm tra phản chiếu");

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

// Kết quả chạy
Jayon
23
Phát triển Dara
Member{name='Jayon2', age=23, hobby='Phát triển Dara'}
Kiểm tra phản chiếu

Bạn có thể sử dụng getDeclaredFileds() để lấy tất cả các biến thể hiện của lớp và sử dụng get() để nhận giá trị trường và sử dụng set() để sửa đổi giá trị trường. Lưu ý rằng khi truy cập các trường có trình điều khiển truy cập private, bạn cần truyền true làm đối số cho setAccessible().


Phương thức cũng có thể được lấy bằng getDeclaredMethod(). Khi đó, bạn cần truyền tên phương thức và kiểu dữ liệu của tham số làm đối số. Tương tự, khi truy cập các phương thức có trình điều khiển truy cập private, bạn cần đặt true làm đối số cho setAccessible(). Cuối cùng, bạn có thể sử dụng phương thức invoke() để gọi phương thức thu được bằng API phản chiếu.


Ưu điểm và nhược điểm

  • Ưu điểm
    • Nó có tính linh hoạt, cho phép bạn tạo thể hiện của lớp tại thời điểm chạy và truy cập các trường và phương thức, bất kể trình điều khiển truy cập, để thực hiện các tác vụ cần thiết.
  • Nhược điểm
    • Vi phạm đóng gói.
    • Không thể kiểm tra kiểu tương ứng tại thời điểm biên dịch vì thể hiện được tạo tại thời điểm chạy.
    • Khó xác định luồng hoạt động cụ thể vì thể hiện được tạo tại thời điểm chạy.
    • Hiệu suất chậm hơn so với việc sử dụng phản chiếu để truy cập trường và phương thức. (Không chậm trong mọi trường hợp.)


Lý do sử dụng

API phản chiếu cho phép bạn truy cập thông tin lớp tại thời điểm chạy và thao tác lớp theo ý muốn. Ngay cả các trường và phương thức được khai báo là private cũng có thể được thao tác. Nó có vẻ như một kỹ thuật không nên sử dụng vì nó vi phạm đóng gói, một khái niệm quan trọng trong thiết kế hướng đối tượng.


Trong giai đoạn phát triển cấp độ bảng điều khiển quy mô nhỏ, nhà phát triển có thể xác định đầy đủ các đối tượng và mối quan hệ phụ thuộc được sử dụng trong chương trình tại thời điểm biên dịch. Tuy nhiên, trong giai đoạn phát triển quy mô lớn như khung, rất khó để xác định vô số đối tượng và mối quan hệ phụ thuộc. Trong trường hợp này, phản chiếu cho phép bạn tạo lớp động để thiết lập mối quan hệ phụ thuộc.


Ví dụ, nếu bạn nhìn vào Nhà máy Bean của Spring, bạn sẽ thấy rằng chỉ cần gắn chú thích @Controller, @Service và @Repository, Nhà máy Bean sẽ tự động tạo và quản lý các lớp có chú thích tương ứng. Nhà phát triển không bao giờ cung cấp cho Nhà máy Bean lớp đó, điều này là có thể nhờ vào phản chiếu. Khi tìm kiếm các lớp có chú thích tương ứng tại thời điểm chạy, nó tạo thể hiện của lớp đó thông qua phản chiếu, tiêm các trường cần thiết và lưu trữ nó trong Nhà máy Bean.


Tất nhiên, như đã đề cập ở trên, nó vi phạm đóng gói, vì vậy tốt nhất là chỉ sử dụng nó khi thật sự cần thiết.


Nguồn

제이온
제이온
제이온
제이온
[Effective Java] Mục 2. Sử dụng builder khi constructor có nhiều tham số Khi tạo đối tượng có nhiều tham số, sử dụng pattern builder có thể giúp viết code rõ ràng và dễ đọc hơn. Tạo đối tượng builder với các tham số bắt buộc, sử dụng setter method để thiết lập các tham số tùy chọn và sau đó gọi method build() để hoàn thiện đối

27 tháng 4, 2024

[Hiệu quả Java] Mục 6. Tránh tạo đối tượng không cần thiết Hướng dẫn về cách giảm thiểu việc tạo đối tượng không cần thiết trong Java. Đối với các đối tượng bất biến như String, Boolean, nên sử dụng literal, và đối với biểu thức chính quy, tốt nhất nên cache instance Pattern. Ngoài ra, việc auto-boxing có thể dẫn

28 tháng 4, 2024

[Effective Java] Mục 4. Sử dụng constructor private để ngăn chặn việc khởi tạo instance Đối với các lớp tiện ích chỉ chứa các phương thức và trường tĩnh, nên đặt quyền truy cập của constructor thành private để ngăn chặn việc khởi tạo instance. Điều này giúp ngăn chặn người dùng nhầm tưởng rằng constructor được tạo tự động và làm cho việc kế

28 tháng 4, 2024

[Không chuyên ngành, sống sót với tư cách nhà phát triển] 14. Tóm tắt nội dung phỏng vấn kỹ thuật thường gặp của nhà phát triển mới vào nghề Hướng dẫn chuẩn bị phỏng vấn kỹ thuật dành cho nhà phát triển mới vào nghề. Vùng bộ nhớ chính, cấu trúc dữ liệu, RDBMS và NoSQL, lập trình hướng thủ tục và hướng đối tượng, ghi đè và quá tải, thuật toán thay thế trang, tiến trình và luồng, OSI 7 lớp, TCP
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3 tháng 4, 2024

Mô hình hóa dữ liệu khái niệm Mô hình hóa dữ liệu khái niệm là quá trình tách biệt các thực thể và thể hiện mối quan hệ giữa các thực thể bằng ERD. Thực thể là đơn vị thông tin độc lập, thuộc tính là dữ liệu mà thực thể sở hữu. Định danh là để xác định duy nhất thực thể, quan hệ là để
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

8 tháng 4, 2024

[Javascript] Cấu trúc của Object (V8) Object trong JavaScript được tối ưu hóa như một cấu trúc theo trạng thái trong V8 Engine, hoạt động ở chế độ Fast (nhanh) và chế độ Dictionary (từ điển) là một bản đồ băm. Chế độ Fast là chế độ nhanh nhưng khóa và giá trị hầu như cố định, khi thêm khóa mớ
곽경직
곽경직
곽경직
곽경직
곽경직

18 tháng 3, 2024

Phân loại dữ liệu là gì? Loại, ưu điểm và nhược điểm Phân loại dữ liệu là một quy trình thiết yếu để giúp máy tính hiểu dữ liệu, giống như việc gắn nhãn 'chó' và 'mèo' cho các bức ảnh chó và mèo tương ứng, gắn thẻ cho dữ liệu để cho phép học máy. Có nhiều phương thức phân loại khác nhau như hình chữ nhật, đ
세상 모든 정보
세상 모든 정보
세상 모든 정보
세상 모든 정보

29 tháng 3, 2024

Quản lý kênh trên Slack, công cụ cộng tác Bài viết giới thiệu các mẹo quản lý kênh Slack. Tùy thuộc vào quy mô và văn hóa của công ty, bạn có thể quản lý hiệu quả các kênh trò chuyện chung, thông báo, kênh công khai/riêng tư theo bộ phận, kênh theo dự án, v.v. Và đặt tên kênh phản ánh rõ ràng tên
여행가고싶은블로거지만여행에대해다루진않을수있어요
여행가고싶은블로거지만여행에대해다루진않을수있어요
Hình ảnh minh họa về việc sắp xếp kênh Slack
여행가고싶은블로거지만여행에대해다루진않을수있어요
여행가고싶은블로거지만여행에대해다루진않을수있어요

8 tháng 2, 2024

Hoàn thành AI Full Stack bằng mã nguồn mở Các mô hình LLM (mô hình ngôn ngữ lớn) mã nguồn mở mới đang xuất hiện trong hệ sinh thái AI. Mistral, Llama, phi-2, v.v., là những mô hình có hiệu suất mạnh mẽ và giấy phép mở được công khai, và nhiều công cụ khác đang được phát triển để sử dụng chúng. La
RevFactory
RevFactory
RevFactory
RevFactory

5 tháng 2, 2024