sách gpt4 ăn đã đi

Một cuộc thảo luận ngắn gọn về công nghệ phản chiếu Java

In lại Tác giả: qq735679552 Thời gian cập nhật: 27-09-2022 22:32:09 35 4
mua khóa gpt4 giày nike

CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.

Bài viết trên blog CFSDN này nói sơ qua về công nghệ phản chiếu Java, được tác giả sưu tầm và biên soạn. Nếu các bạn quan tâm tới bài viết này thì nhớ like nhé.

Một cuộc thảo luận ngắn gọn về công nghệ phản chiếu Java

1. Phản ánh là gì?

Phản chiếu là một trong những tính năng của Java, cho phép một chương trình Java đang chạy có được thông tin riêng của nó và thao tác các thuộc tính bên trong của một lớp hoặc đối tượng.

Lời giải thích chính thức của Oracle về sự phản ánh là:

Reflection cho phép mã Java khám phá thông tin về các trường, phương thức và hàm tạo của các lớp được tải và sử dụng các trường, phương thức và hàm tạo được phản ánh để vận hành trên các đối tác cơ bản của chúng, trong phạm vi giới hạn bảo mật. API hỗ trợ các ứng dụng cần truy cập vào các thành viên công khai của đối tượng mục tiêu (dựa trên lớp thời gian chạy của đối tượng) hoặc các thành viên được khai báo bởi một lớp nhất định. Nó cũng cho phép các chương trình ngăn chặn quyền kiểm soát truy cập phản chiếu mặc định.

Nói tóm lại, thông qua sự phản ánh, chúng ta có thể thu được thông tin về từng loại và thành viên của một chương trình hoặc tập hợp trong thời gian chạy. Các loại đối tượng chung trong chương trình được xác định tại thời điểm biên dịch, nhưng cơ chế phản ánh Java có thể tạo động các đối tượng và gọi các thuộc tính của chúng không xác định được tại thời điểm biên dịch. Vì vậy, chúng ta có thể tạo các đối tượng trực tiếp thông qua cơ chế phản chiếu, ngay cả khi loại đối tượng này không xác định được tại thời điểm biên dịch.

2. Công dụng chính của sự phản ánh

Nhiều người nghĩ rằng sự phản chiếu không được sử dụng rộng rãi trong các ứng dụng phát triển Java thực tế, nhưng thực tế không phải vậy. Khi chúng ta sử dụng IDE (như Eclipse, IDEA), khi chúng ta vào một đối tượng hoặc lớp và muốn gọi các thuộc tính hoặc phương thức của nó, ngay khi chúng ta nhấn dấu chấm, trình biên dịch sẽ tự động liệt kê các thuộc tính hoặc phương thức của nó. được sử dụng.

Công dụng quan trọng nhất của sự phản ánh là phát triển các khuôn khổ chung khác nhau. Nhiều khung công tác (chẳng hạn như Spring) được định cấu hình (chẳng hạn như định cấu hình các Bean thông qua các tệp XML). Để đảm bảo tính linh hoạt của khung, chúng có thể cần tải các đối tượng hoặc lớp khác nhau và gọi các phương thức khác nhau tùy theo tệp cấu hình. trường hợp, bạn phải sử dụng Để phản ánh, các đối tượng cần tải sẽ được tải động khi chạy.

Ví dụ: khi phát triển bằng framework Struts 2, chúng ta thường cấu hình Action trong struts.xml, chẳng hạn như:

  1. <hoạt động tên="đăng nhập"
  2. lớp="org.xxx.SimpleLoginAction"
  3. phương pháp="thực hiện">
  4. /cửa hàng/cửa hàng- chỉ số .jsp
  5. tên ="lỗi">đăng nhập.jsp
  6. hoạt động>

Tệp cấu hình và Hành động thiết lập mối quan hệ ánh xạ. Khi lớp Xem đưa ra một yêu cầu, yêu cầu đó sẽ bị chặn bởi StrutsPrepareAndExecuteFilter, sau đó StrutsPrepareAndExecuteFilter sẽ tự động tạo một phiên bản Hành động. Ví dụ: nếu chúng ta yêu cầu login.action thì StrutsPrepareAndExecuteFilter sẽ phân tích tệp struts.xml, truy xuất hành động có tên đăng nhập trong hành động, tạo một cá thể SimpleLoginAction dựa trên thuộc tính lớp và sử dụng phương thức gọi để gọi phương thức thực thi. Quá trình này không thể tách rời khỏi sự phản ánh.

Đối với các nhà phát triển khung, sự phản chiếu tuy nhỏ nhưng rất quan trọng. Đối với các nhà phát triển bình thường, nếu không đi sâu vào phát triển framework, họ sẽ ít sử dụng sự phản ánh hơn. Tuy nhiên, việc hiểu được cơ chế cơ bản của framework sẽ giúp làm phong phú thêm ý tưởng lập trình của họ và cũng rất có lợi.

3. Sử dụng cơ bản sự phản ánh

3.1. Lấy đối tượng lớp thông qua sự phản chiếu

Có ba cách để có được đối tượng thông qua sự phản ánh.

3.1.1 Nhận được bởi Class.forName().

  1. công cộng tĩnh Lớp học forName(Chuỗi className)
  2. ném ClassNotFoundException {
  3. Lớp học người gọi = Reflection.getCallerClass();
  4. trở lại forName0(lớpTên, ĐÚNG VẬY, ClassLoader.getClassLoader(người gọi), người gọi);
  5. }

Ví dụ: phương pháp này thường được sử dụng trong quá trình phát triển JDBC để tải trình điều khiển cơ sở dữ liệu.

  1. Lớp.forName("Tên gói. Tên lớp");

3.1.2. Lấy tên lớp.class.

Ví dụ:

  1. Lớp học intClass = số nguyên.lớp học;
  2. Lớp học lớp số nguyên = Số nguyên.KIỂU;
  3. Lớp #RelfectEntity là một ví dụ cho bài viết này
  4. Lớp relfectEntity2 = RelfectEntity.class;

3.1.3. Lấy đối tượng thông qua getClass().

  1. StringBuilder str = new StringBuilder("123");
  2. Lớp strClass = str.getClass();

Cả ba phương thức đều có thể được sử dụng để thu được các đối tượng lớp. Trong quá trình phát triển khung, phương thức đầu tiên thường được sử dụng nhiều hơn.

3.2 Lấy thông tin về hàm tạo của lớp

Để có được cách sử dụng hàm tạo của lớp, bạn chủ yếu lấy một thể hiện của lớp Constructor thông qua phương thức getConstructor của lớp Class và lớp Constructor có một phương thức newInstance có thể tạo một thể hiện đối tượng.

  1. công cộng T newInstance(Đối tượng ... initargs)

3.3 Lấy một thể hiện của một lớp

Có hai cách chính để tạo ra các đối tượng thông qua sự phản chiếu.

Sử dụng phương thức newInstance() của đối tượng Class để tạo một thể hiện của lớp tương ứng của đối tượng Class.

  1. Lớp c = String.class;
  2. Đối tượng str = c.newInstance();

Đầu tiên lấy đối tượng Constructor được chỉ định thông qua đối tượng Class, sau đó gọi phương thức newInstance() của đối tượng Constructor để tạo một thể hiện.

  1. //Lấy đối tượng Class tương ứng với String
  2. Lớp học c = String. class;
  3. //Lấy hàm tạo của lớp String với tham số String
  4. Trình xây dựng constructor = c.getConstructor(String.class);
  5. //Tạo một thể hiện dựa trên hàm tạo
  6. Đối tượng obj = constructor.newInstance("23333");
  7. Hệ thống.ngoài.println(đối tượng);

Phương thức này xây dựng một thể hiện của một lớp bằng cách sử dụng một hàm tạo được chỉ định.

3.4. Lấy biến lớp

Lớp thực thể:

  1. /**
  2. * Lớp cơ sở
  3. */
  4. công cộng lớp BaseClass {
  5. công cộng Chuỗi publicBaseVar1;
  6. công cộng Chuỗi publicBaseVar2;
  7. }
  8. /**
  9. * Phân lớp
  10. */
  11. công cộng lớp ChildClass mở rộng BaseClass{
  12. công cộng Chuỗi publicOneVar1;
  13. công cộng Chuỗi publicOneVar2;
  14. Chuỗi riêng tư privateOneVar1;
  15. Chuỗi riêng tư privateOneVar2;
  16. công cộng Chuỗi printOneMsg() {
  17. trở lại OneVar1 riêng tư;
  18. }
  19. }

Bài kiểm tra:

  1. công cộng lớp VarTest {
  2. công cộng tĩnh void main(String[] args) {
  3. //1. Lấy và xuất tên của lớp
  4. Lớp mClass = ChildClass.class;
  5. Hệ thống.ngoài.println("Tên lớp:" + mClass.getName());
  6. Hệ thống.ngoài.println("----Nhận tất cả các biến truy cập công khai (bao gồm cả những biến được khai báo bởi lớp này và những biến được kế thừa từ lớp cha)----");
  7. //2. Nhận tất cả công cộng Các biến quyền truy cập (bao gồm các biến được khai báo bởi lớp này và các biến được kế thừa từ lớp cha)
  8. Trường[] các trường = mClass.getFields();
  9. //Truyền các biến và xuất thông tin biến
  10. (Trường trường : các trường) {
  11. // Nhận quyền truy cập và đầu ra
  12. số nguyên bộ sửa đổi = field.getModifiers();
  13. Hệ thống.ngoài.print(Modifier.toString(các trình sửa đổi) + " ");
  14. //Loại biến đầu ra và tên biến
  15. Hệ thống.ngoài.println(trường.getType().getName() + " " + field.getName());
  16. }
  17. Hệ thống.ngoài.println("----Lấy tất cả các biến được khai báo trong lớp này----");
  18. //3. Lấy tất cả các biến được khai báo trong lớp này
  19. Trường[] tất cả các trường = mClass.getDeclaredFields();
  20. (Trường trường: allFields) {
  21. // Nhận quyền truy cập và đầu ra
  22. số nguyên bộ sửa đổi = field.getModifiers();
  23. Hệ thống.ngoài.print(Modifier.toString(các trình sửa đổi) + " ");
  24. //Loại biến đầu ra và tên biến
  25. Hệ thống.ngoài.println(trường.getType().getName() + " " + field.getName());
  26. }
  27. }
  28. }

Kết quả đầu ra:

  1. Tên lớp: com.example.java.reflect.ChildClass
  2. ----Nhận tất cả các biến truy cập công khai (bao gồm cả các biến được khai báo bởi lớp này và kế thừa từ lớp cha)----
  3. công cộng java.lang.String publicOneVar1
  4. công cộng java.lang.String publicOneVar2
  5. công cộng java.lang.String publicBaseVar1
  6. công cộng java.lang.String publicBaseVar2
  7. ----Lấy tất cả các biến được khai báo trong lớp này----
  8. công cộng java.lang.String publicOneVar1
  9. công cộng java.lang.String publicOneVar2
  10. java.lang.String riêng tư privateOneVar1
  11. java.lang.String riêng tư privateOneVar2

3.5 Sửa đổi các biến lớp

Sửa đổi các lớp con.

  1. /**
  2. * Phân lớp
  3. */
  4. công cộng lớp ChildClass mở rộng BaseClass{
  5. công cộng Chuỗi publicOneVar1;
  6. công cộng Chuỗi publicOneVar2;
  7. Chuỗi riêng tư privateOneVar1;
  8. Chuỗi riêng tư privateOneVar2;
  9. công cộng Chuỗi printOneMsg() {
  10. trở lại OneVar1 riêng tư;
  11. }
  12. }

Bài kiểm tra:

  1. công cộng lớp VarModfiyTest {
  2. công cộng tĩnh void main(String[] args) ném ra ngoại lệ {
  3. //1. Lấy và xuất tên của lớp
  4. Lớp mClass = ChildClass.class;
  5. Hệ thống.ngoài.println("Tên lớp:" + mClass.getName());
  6. Hệ thống.ngoài.println("----Lấy biến riêng tư PrivateOneVar1 trong lớp ChildClass----");
  7. //2. Lấy biến riêng tư PrivateOneVar1 trong lớp ChildClass
  8. Trường privateField = mClass.getDeclaredField("privateOneVar1");
  9. //3. Thao tác với các biến riêng tư
  10. nếu (privateField != vô giá trị) {
  11. // Truy cập vào các biến riêng tư
  12. privateField.setAccessible(ĐÚNG VẬY);
  13. // khởi tạo đối tượng
  14. ChildClass obj = (ChildClass) mClass.newInstance();
  15. // Sửa đổi các biến riêng tư và đầu ra để thử nghiệm
  16. Hệ thống.ngoài.println("biến PrivateOneVar1, giá trị trước khi sửa đổi: " + obj.printOneMsg());
  17. //gọi bộ(đối tượng, giá trị) Sửa đổi giá trị của một biến
  18. //privateField là biến riêng tư thu được
  19. //obj Đối tượng được thao tác
  20. //"Xin chào thế giới" là giá trị được sửa đổi thành
  21. Trường riêng tư.bộ(đối tượng, "Xin chào thế giới");
  22. Hệ thống.ngoài.println("biến PrivateOneVar1, giá trị được sửa đổi: " + obj.printOneMsg());
  23. }
  24. }
  25. }

Kết quả đầu ra:

  1. Tên lớp: com.example.java.reflect.ChildClass
  2. ----Lấy biến riêng tư PrivateOneVar1 trong lớp ChildClass----
  3. Biến riêngOneVar1, giá trị trước khi sửa đổi: vô giá trị
  4. Biến riêngOneVar1, giá trị được sửa đổi: hello world

3.6 Lấy tất cả các phương thức của một lớp

Sửa đổi lớp thực thể.

  1. /**
  2. * Lớp cơ sở
  3. */
  4. công cộng lớp BaseClass {
  5. công cộng Chuỗi publicBaseVar1;
  6. công cộng Chuỗi publicBaseVar2;
  7. khoảng trống riêng tưprivatePrintBaseMsg(String var) {
  8. Hệ thống.ngoài.println("Lớp cơ sở - phương thức riêng, biến:" + đã);
  9. }
  10. công cộng void publicPrintBaseMsg(String var) {
  11. Hệ thống.ngoài.println("Lớp cơ sở - phương thức công khai, biến:" + đã);
  12. }
  13. }
  14. /**
  15. * Phân lớp
  16. */
  17. công cộng lớp ChildClass mở rộng BaseClass{
  18. công cộng Chuỗi publicOneVar1;
  19. công cộng Chuỗi publicOneVar2;
  20. Chuỗi riêng tư privateOneVar1;
  21. Chuỗi riêng tư privateOneVar2;
  22. công cộng Chuỗi printOneMsg() {
  23. trở lại OneVar1 riêng tư;
  24. }
  25. khoảng trống riêng tư PrivatePrintOneMsg(String var) {
  26. Hệ thống.ngoài.println("Lớp con - phương thức riêng, biến:" + đã);
  27. }
  28. công cộng void publicPrintOneMsg(String var) {
  29. Hệ thống.ngoài.println("Lớp con - phương thức công khai, biến:" + đã);
  30. }
  31. }

Bài kiểm tra:

  1. công cộng lớp MethodTest {
  2. công cộng tĩnh void main(String[] args) {
  3. //1. Lấy và xuất tên của lớp
  4. Lớp mClass = ChildClass.class;
  5. Hệ thống.ngoài.println("Tên lớp:" + mClass.getName());
  6. Hệ thống.ngoài.println("----Các phương pháp để có được tất cả các quyền truy cập công khai, bao gồm cả những quyền do chính bạn khai báo và những quyền được kế thừa từ các lớp cha---");
  7. //2 lấy tất cả công cộng Truy cập các phương thức cấp phép, bao gồm các phương thức do chính bạn khai báo và các phương thức được kế thừa từ các lớp cha
  8. Phương thức[] mMethods = mClass.getMethods();
  9. (Phương pháp phương pháp: mMethods) {
  10. //Nhận và xuất các quyền truy cập của phương thức (Modifiers: modifier)
  11. số nguyên bộ sửa đổi = phương thức.getModifiers();
  12. Hệ thống.ngoài.print(Modifier.toString(các trình sửa đổi) + " ");
  13. //Lấy và xuất kiểu giá trị trả về của phương thức
  14. Lớp returnType = Method.getReturnType();
  15. Hệ thống.ngoài.print(returnType.getName() + " " + phương thức.getName() + "( ");
  16. // Lấy và xuất tất cả các tham số của phương thức
  17. Tham số[] tham số = phương thức.getParameters();
  18. (Tham số tham số: các tham số) {
  19. Hệ thống.ngoài.print(tham số.getType().getName() + " " + tham số.getName() + ",");
  20. }
  21. //Nhận và xuất ngoại lệ do phương thức đưa ra
  22. Lớp[] exceptionTypes = phương thức.getExceptionTypes();
  23. nếu (exceptionTypes.length == 0){
  24. Hệ thống.ngoài.println(" )");
  25. } khác {
  26. (Lớp c: exceptionTypes) {
  27. Hệ thống.ngoài.println(" ) ném " + c. getName());
  28. }
  29. }
  30. }
  31. Hệ thống.ngoài.println("----Nhận tất cả các phương thức của lớp này---");
  32. //3. Lấy tất cả các phương thức của lớp này
  33. Phương thức[] allMethods = mClass.getDeclaredMethods();
  34. (Phương pháp phương pháp: allMethods) {
  35. //Nhận và xuất các quyền truy cập của phương thức (Modifiers: modifier)
  36. số nguyên bộ sửa đổi = phương thức.getModifiers();
  37. Hệ thống.ngoài.print(Modifier.toString(các trình sửa đổi) + " ");
  38. //Lấy và xuất kiểu giá trị trả về của phương thức
  39. Lớp returnType = Method.getReturnType();
  40. Hệ thống.ngoài.print(returnType.getName() + " " + phương thức.getName() + "( ");
  41. // Lấy và xuất tất cả các tham số của phương thức
  42. Tham số[] tham số = phương thức.getParameters();
  43. (Tham số tham số: các tham số) {
  44. Hệ thống.ngoài.print(tham số.getType().getName() + " " + tham số.getName() + ",");
  45. }
  46. //Nhận và xuất ngoại lệ do phương thức đưa ra
  47. Lớp[] exceptionTypes = phương thức.getExceptionTypes();
  48. nếu (exceptionTypes.length == 0){
  49. Hệ thống.ngoài.println(" )");
  50. } khác {
  51. (Lớp c: exceptionTypes) {
  52. Hệ thống.ngoài.println(" ) ném " + c. getName());
  53. }
  54. }
  55. }
  56. }
  57. }

Đầu ra:

  1. Tên lớp: com.example.java.reflect.ChildClass
  2. ----Các phương thức để có được tất cả các quyền truy cập công cộng, bao gồm cả những quyền do chính bạn khai báo và những quyền được kế thừa từ các lớp cha---
  3. công cộng java.lang.String printOneMsg()
  4. công cộng void publicPrintOneMsg( java.lang.String arg0, )
  5. công cộng void publicPrintBaseMsg( java.lang.String arg0, )
  6. công cộng void wait( arg0 dài cuối cùng,số nguyên arg1, ) ném java.lang.InterruptedException
  7. công cộng cuối cùng void wait( long arg0, ) gốc ném java.lang.InterruptedException
  8. công cộng void wait() cuối cùng ném java.lang.InterruptedException
  9. công cộng boolean bằng( java.lang.Object arg0, )
  10. công cộng java.lang.String thànhChuỗi()
  11. công cộng tự nhiên số nguyên Mã băm ( )
  12. công cộng java.lang.Class gốc cuối cùng getClass()
  13. công cộng cuối cùng bản địa void notify()
  14. công cộng cuối cùng bản địa void notifyAll()
  15. ----Nhận tất cả các phương thức của lớp này---
  16. công cộng java.lang.String printOneMsg()
  17. riêng tư void privatePrintOneMsg( java.lang.String arg0, )
  18. công cộng void publicPrintOneMsg( java.lang.String arg0, )

Tại sao có nhiều đầu ra như vậy?

Bởi vì tất cả các lớp đều kế thừa lớp đối tượng theo mặc định, nên bạn sẽ tìm thấy một số phương thức công khai khi mở lớp đối tượng, để chúng được in ra cùng nhau.

3.7. Phương thức gọi

  1. công cộng lớp MethodInvokeTest {
  2. công cộng tĩnh void main(String[] args) ném ra ngoại lệ {
  3. // 1. Lấy và xuất tên lớp
  4. Lớp mClass = ChildClass.class;
  5. Hệ thống.ngoài.println("Tên lớp:" + mClass.getName());
  6. Hệ thống.ngoài.println("----Lấy phương thức riêng tư PrivatePrintOneMsg của lớp ChildClass---");
  7. // 2. Lấy phương thức riêng tư tương ứng
  8. // Tham số đầu tiên là tên của phương thức riêng cần lấy
  9. // Cái thứ hai là loại tham số cần lấy. Tham số là Class..., nếu không có tham số thì là.vô giá trị
  10. //Các tham số của phương thức cũng có thể được viết như thế này: new Class[]{String.class}
  11. Phương thức privateMethod = mClass.getDeclaredMethod("privatePrintOneMsg", String. class);
  12. // 3. Bắt đầu phương thức hoạt động
  13. nếu (privateMethod != vô giá trị) {
  14. // Truy cập vào các phương thức riêng tư
  15. // Chỉ cần có quyền truy cập, không sửa đổi quyền thực tế
  16. PrivateMethod.setAccessible(ĐÚNG VẬY);
  17. // khởi tạo đối tượng
  18. ChildClass obj = (ChildClass) mClass.newInstance();
  19. // Sử dụng sự phản chiếu gọi để gọi các phương thức riêng tư
  20. // obj Đối tượng được thao tác
  21. // Các tham số sau được truyền dưới dạng tham số thực tế
  22. privateMethod.invoke(obj, "Xin chào thế giới");
  23. }
  24. }
  25. }

Kết quả đầu ra:

  1. Tên lớp: com.example.java.reflect.ChildClass
  2. ----Lấy phương thức riêng tư PrivatePrintOneMsg của lớp ChildClass---
  3. Lớp con - phương thức riêng, biến: hello world

4. Tóm tắt

Vì sự phản chiếu tiêu tốn một lượng tài nguyên hệ thống bổ sung nhất định, nên nếu bạn không cần tạo động một đối tượng thì không cần sử dụng sự phản chiếu. Ngoài ra, việc kiểm tra quyền có thể bị bỏ qua khi gọi các phương thức thông qua phản chiếu, do đó có khả năng phá vỡ tính năng đóng gói và gây ra các vấn đề bảo mật.

5. Bài viết tham khảo

sczyh30: Phân tích chuyên sâu về phản ánh Java.

Burt: Phản ánh Java từ cơ bản đến nâng cao.

Liên kết gốc: https://mp.weixin.qq.com/s/CxRmB8xko2nou_4tZxCJdg.

Cuối cùng, bài viết thảo luận ngắn gọn về công nghệ phản chiếu Java này kết thúc tại đây. Nếu bạn muốn biết thêm về một cuộc thảo luận ngắn gọn về công nghệ phản chiếu Java, vui lòng tìm kiếm các bài viết về CFSDN hoặc tiếp tục duyệt các bài viết liên quan. tương lai! .

35 4 0
qq735679552
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress