เมื่อฉันเริ่มเรียน Java ครั้งแรก มันยากมากที่จะเข้าใจว่าการสะท้อนคืออะไร
หนังสือบางเล่มแม้จะเป็นหนังสือคลาสสิกก็ตาม อธิบายสิ่งต่าง ๆ ในลักษณะที่ทำให้ผู้คนรู้สึกสับสน บางทีฉันอาจจะโง่เกินไป
ยิ่งไปกว่านั้น มีการกล่าวในโลกออนไลน์ว่าจำเป็นต้องใช้กลไกการสะท้อนบ่อยครั้งในการเรียนรู้กรอบการทำงานในอนาคต ซึ่งทำให้ผู้คนรู้สึกไม่สบายใจเล็กน้อยอยู่เสมอ
ฉันเพิ่งดูบางบทและวิดีโอที่อธิบายการไตร่ตรองโดยไม่ได้ตั้งใจ และฉันคิดว่าฉันสามารถเข้าใจได้ดีขึ้นนิดหน่อย
ตอนนี้ฉันตัดสินใจที่จะทำงานหนัก อ่านและเขียนไปพร้อมๆ กัน และบันทึกเนื้อหาหลักและการดำเนินการบางส่วนไว้ที่นี่
ฉันคิดว่าสำหรับคนโง่เช่นฉัน บางทีวิธีที่ดีที่สุดในการเรียนรู้คือการทำซ้ำ
เมื่อฉันพบกับสิ่งที่ฉันไม่เข้าใจฉันก็หยุดและเรียนรู้มันใหม่อีกครั้งแม้ว่ามันจะเสียเวลามาก แต่มันก็มีผลกระทบต่อฉันเช่นกัน
ความเข้าใจของฉันคือ: สิ่งที่เรียกว่าการสะท้อนคือการกู้คืนข้อมูลที่สมบูรณ์ของคลาสโดยอิงจากวัตถุที่สร้างอินสแตนซ์แล้ว
อย่างน้อยสำหรับฉัน ฉันคิดว่าประโยชน์ที่ฉันได้รับคือการช่วยให้ฉันเข้าใจเชิงวัตถุจากล่างขึ้นบน
x_x ฉันเกลียดไอ้หัวหนาพวกนั้นอีกแล้ว มันฆ่าเซลล์สมองของฉันหมดเลย
คลาสเรียนถ้าอยากสะท้อนให้สมบูรณ์ คุณต้องเข้าใจคลาส Class
ตัวอย่างที่ 1: รับชื่อแพ็คเกจและชื่อคลาสผ่านอ็อบเจ็กต์การทดสอบชั้นเรียน {
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะสาธารณะคงหลัก (สตริง [] args) {
ทดสอบ t = การทดสอบใหม่ ();
System.out.println(t.getClass());
System.out.println(t.getClass().getName());
-
-
ผลลัพธ์การคอมไพล์มีดังนี้ เพียงใส่ใจกับวิธีการคอมไพล์แพ็คเกจ
เมธอด getClass() ที่นี่สืบทอดมาจากคลาส Object ตามค่าเริ่มต้น
ใน Java คลาส Object คือคลาสหลักของคลาสทั้งหมด ในทำนองเดียวกัน อ็อบเจ็กต์ที่สร้างอินสแตนซ์ของคลาสทั้งหมดก็เป็นอินสแตนซ์ของคลาส Class เช่นกัน
ดังนั้นสิ่งนี้จะเกี่ยวข้องกับแนวคิดของการเปลี่ยนแปลงขึ้นและการเปลี่ยนแปลงลง
ข้อมูลทั่วไปจะตามมาที่นี่เนื่องจากความไม่มั่นคงของการปลดเปลื้องลง
(แต่สิ่งที่ฉันอยากจะพูดก็คือการออกแบบทั่วไปที่นี่น่าทึ่งมาก! ให้ตายเถอะ การออกแบบไวยากรณ์ของ Java ทั้งหมดนั้นน่าทึ่งและน่ารังเกียจอย่างยิ่ง!!!)
ตัวอย่างที่ 2: การสร้างอินสแตนซ์ของคลาสคลาสเนื่องจากคลาส Class ไม่มี Constructor วิธีการสร้างอินสแตนซ์ของคลาสจึงค่อนข้างพิเศษ มีสามวิธี:
Object.getClass()-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะสาธารณะคงหลัก (สตริง [] args) {
//วิธีที่ 1:
ทดสอบ t = การทดสอบใหม่ ();
คลาส<? ขยายการทดสอบ> c1 = t.getClass();
System.out.println(c1);
//วิธีที่ 2:
//เพื่อหลีกเลี่ยงความจำเพาะ จึงไม่ได้ใช้คลาส Test ที่นี่ แต่จะใช้คลาส String ในไลบรารี java
คลาส<String> c2 = String.class;
System.out.println(c2);
//วิธีที่ 3:
//forName() วิธีการจะส่งข้อยกเว้น
คลาส<?> c3 = null;
พยายาม {
c3 = Class.forName("ทดสอบ");
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
-
System.out.println(c3);
-
-
มีวิธีการในคลาสคลาสที่เรียกว่า newInstance() ซึ่งสามารถใช้เพื่อสร้างอินสแตนซ์ใหม่ของวัตถุคลาสคลาส
จะพูดยังไงดี? เนื้อหาที่มีอยู่ในคลาสวัตถุเป็นคลาสที่สะท้อน เราจำเป็นต้องสร้างอินสแตนซ์ใหม่ (วัตถุใหม่) ของคลาสนั้น
ตัวอย่างที่ 3: การสร้างวัตถุโดยไม่มีพารามิเตอร์ของคลาสคลาส //สร้างการอ้างอิงถึงสตริง
สตริง s = null;
พยายาม {
//ดาวน์แคสต์อ็อบเจ็กต์ที่สร้างขึ้นไปที่คลาส String
//newInstance() วิธีการจะส่งข้อยกเว้น
s = (สตริง) c.newInstance();
} จับ (InstantiationException e) {
e.printStackTrace();
} จับ (IllegalAccessException e) {
e.printStackTrace();
-
System.out.println("ความยาวสตริง: " + s.length());
-
-
สิ่งนี้จะสร้างออบเจ็กต์ใหม่ในรูปแบบที่ไม่มีพารามิเตอร์ เช่นเดียวกับในโหมดปกติ
การสร้างวัตถุใหม่ผ่านตัวสร้างที่ไม่มีอาร์กิวเมนต์จะเหมือนกับ
เรารู้ว่านอกเหนือจากตัวสร้างแบบไม่มีพารามิเตอร์แล้ว ยังมีตัวสร้างแบบกำหนดพารามิเตอร์ในคลาสด้วย
แล้วจะสร้างวัตถุในรูปแบบของพารามิเตอร์ในการสะท้อนได้อย่างไร? อ่านต่อ
ตัวอย่างที่ 4: อ็อบเจ็กต์ที่สร้างด้วยพารามิเตอร์ของคลาสคลาส การสาธิตชั้นเรียนสาธารณะ {
//วิธีการต่อไปนี้ทำให้เกิดข้อยกเว้นมากเกินไป เพื่อความกระชับของโค้ด จึงถูกส่งไปที่เครื่องเสมือนโดยตรงที่นี่
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
คลาส<?> c = null;
พยายาม {
c = Class.forName("java.lang.String");
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
-
ถ่าน [] ch = {'h','e','l','l','o'};
สตริง s = null;
// รับตัวสร้างพารามิเตอร์ของวัตถุคลาส พารามิเตอร์ในวงเล็บจะเขียนเป็น: type.class
ตัวสร้าง<?> con = c.getConstructor(char[].class);
//ใช้วิธีการก่อสร้างนี้เพื่อสร้างวัตถุสตริงใหม่ พารามิเตอร์คืออาร์เรย์ถ่าน
s = (สตริง) con.newInstance(ch);
System.out.println("สตริงที่สร้างขึ้น: " + s);
-
-
เรายังคงใช้คลาส String เป็นตัวอย่าง เนื่องจากคลาส String ถูกใช้บ่อยกว่าและเข้าใจง่ายกว่า
สิ่งที่ต้องสังเกตที่นี่คือตัวสร้างจะต้องได้รับโดยใช้เมธอด getConstructor()
สำหรับประเภทพารามิเตอร์คือ: original type.class
อีกประเด็นหนึ่งคือ ไม่ว่าจะมีพารามิเตอร์หรือไม่มีพารามิเตอร์ วิธีการก่อสร้างที่ใช้ที่นี่จะต้องมีอยู่ในคลาสดั้งเดิม
แล้วเราจะรู้ข้อมูลโดยละเอียดได้อย่างไร เช่น วิธีคอนสตรัคเตอร์ วิธีธรรมดา คลาสพาเรนต์ที่สืบทอด และอื่นๆ ในคลาสดั้งเดิม อ่านต่อ
รับโครงสร้างของชั้นเรียนเพื่อให้ได้โครงสร้างของคลาสผ่านการสะท้อนกลับ เราจำเป็นต้องนำเข้าแพ็คเกจใหม่ java.lang.reflect
ตัวอย่างที่ 5: รับคอนสตรัคเตอร์ของคลาส การสาธิตชั้นเรียนสาธารณะ {
//วิธีการต่อไปนี้ทำให้เกิดข้อยกเว้นมากเกินไป เพื่อความกระชับของโค้ด จึงถูกส่งไปที่เครื่องเสมือนโดยตรงที่นี่
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
คลาส<?> c = null;
พยายาม {
c = Class.forName("java.lang.Boolean");
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
-
//เมธอด getConstructors() ที่นี่ส่งคืนอาร์เรย์ Constructor
ตัวสร้าง<?>[] ข้อเสีย = c.getConstructors();
//คุณสามารถเขียนวิธีการพิมพ์เองได้ เพื่อความสะดวก ผมใช้ Arrays.toString() ในการทำ
System.out.println(Arrays.toString(ข้อเสีย));
-
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
คลาส<?> c = null;
พยายาม {
c = Class.forName("java.lang.Boolean");
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
-
คลาส<?>[] ใน = c.getInterfaces();
System.out.println(อาร์เรย์.toString(ใน));
-
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
คลาส<?> c = null;
พยายาม {
c = Class.forName("java.lang.Boolean");
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
-
วิธีการ[] m = c.getMethods();
//เอาล่ะ คราวนี้ฉันจะเมตตาและเขียนรายการพิมพ์ออกมา
สำหรับ (int i = 0; i < m.length; i++) {
System.out.println(ม[i]);
-
-
-
บุคคลในชั้นเรียน {
ชื่อสตริงส่วนตัว
อายุ int ส่วนตัว
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
คลาส<?> c = null;
พยายาม {
c = Class.forName("บุคคล");
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
-
ฟิลด์[] f = c.getDeclaredFields();
สำหรับ (int i = 0; i < f.length; i++) {
System.out.println(ฉ[i]);
-
-
-
เมธอด getDeclaredFielsd() สามารถรับคุณสมบัติทั้งหมดได้ และ getFields() สามารถรับได้เฉพาะคุณสมบัติสาธารณะเท่านั้น
ตัวอย่างที่ 10: รับค่าของแอตทริบิวต์ในคลาสนี้ บุคคลในชั้นเรียน {
ชื่อสตริงสาธารณะ
อายุ int ส่วนตัว
บุคคลสาธารณะ (ชื่อสตริง อายุ int) {
this.name = ชื่อ;
this.age = อายุ;
-
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
บุคคล p = บุคคลใหม่ ("จางซาน",12);
คลาส<?> c = p.getClass();
// รับค่าของแอตทริบิวต์สาธารณะ
ฟิลด์ f1 = c.getField("ชื่อ");
//get(p) ระบุค่าอ็อบเจ็กต์ที่ต้องการรับ
สตริง str = (สตริง) f1.get(p);
System.out.println("ชื่อ: " + str);
// รับค่าของแอตทริบิวต์ส่วนตัว
ฟิลด์ f2 = c.getDeclaredField("อายุ");
//อายุเป็นทรัพย์สินส่วนบุคคล ดังนั้นให้ตั้งค่าการตรวจสอบความปลอดภัยเป็นจริง
f2.setAccessible (จริง);
อายุ int = (int) f2.get(p);
System.out.println("อายุ: " + อายุ);
-
-
พูดตามตรง ฉันไม่พบความรู้ใด ๆ ใน Java ที่สามารถทำให้ดวงตาไทเทเนียมของฉันบอดได้
ทุกครั้ง ฉันต้องเขียนไวยากรณ์ที่น่าเบื่อจำนวนมากเพื่อใช้งาน Gadget ไม่เช่นนั้น ฉันต้องเรียกใช้ API อย่างสิ้นหวังและทิ้งข้อยกเว้นอย่างสิ้นหวัง
ทำให้โค้ดที่ไม่กะทัดรัดกลายเป็นเรื่องยุ่งยาก
ถ้าฉันชอบภาษาหนึ่ง ลักษณะของมันจะต้องทำให้ฉันประทับใจก่อนจึงจะสามารถนำไปใช้ทำอะไรสักอย่างได้
แน่นอนว่า Java ไม่ได้ทำให้ฉันมีความสุข บางทีโปรแกรมเมอร์หลายคนเช่นฉันอาจถูกบังคับให้ใช้ Java
เพียงเพื่อเอาใจหัวใจการเขียนโค้ดที่โดดเดี่ยวของฉัน โปรดอ่านด้านล่าง
ตัวอย่างการใช้งาน Reflection 11: ปรับเปลี่ยนคุณลักษณะผ่านการสะท้อนกลับ บุคคลในชั้นเรียน {
ชื่อสตริงส่วนตัว
บุคคลสาธารณะ (ชื่อสตริง) {
this.name = ชื่อ;
-
สตริงสาธารณะ toString() {
กลับ "ชื่อ: " + this.name;
-
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
บุคคล p = บุคคลใหม่ ("王二狗");
System.out.println(p);
คลาส<?> c = p.getClass();
//กำหนดคุณสมบัติที่จะแก้ไข
ฟิลด์ f = c.getDeclaredField("ชื่อ");
f.setAccessible(จริง);
//แก้ไขคุณสมบัติและส่งผ่านวัตถุและค่าที่จะตั้งค่า
f.set(p, "จาง เออร์ดาน");
System.out.println(p);
-
-
บุคคลในชั้นเรียน {
การพิมพ์โมฆะสาธารณะ (int i) {
System.out.println("ฉันกำลังเขียนตัวเลข: " + i);
-
โมฆะคงสาธารณะพูด (String str) {
System.out.println("ฉันกำลังพูดว่า: " + str);
-
-
การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
บุคคล p = บุคคลใหม่ ();
คลาส<?> c = p.getClass();
//getMethod() วิธีการต้องส่งผ่านชื่อวิธีการและประเภทพารามิเตอร์
วิธี m1 = c.getMethod("print", int.class);
//invoke() หมายถึงการโทรและจำเป็นต้องส่งผ่านวัตถุและพารามิเตอร์
m1.วิงวอน(หน้า 10);
วิธี m2 = c.getMethod("พูด", String.class);
//ค่าว่างในที่นี้หมายถึงไม่ได้ถูกเรียกโดยอ็อบเจ็กต์ นั่นคือเมธอดแบบสแตติก
m2.inurge(null, "น้องสาวของคุณ");
-
-
ต่อไปนี้เป็นการสาธิตวิธีการแบบกำหนดพารามิเตอร์ปกติและวิธีการแบบคงที่
ตอนนี้เมื่อพารามิเตอร์ทั้งหมดถูกเขียนออกไปแล้ว พารามิเตอร์ที่ไม่มีพารามิเตอร์ก็จะยิ่งง่ายขึ้น เพียงแค่ส่งผ่านวัตถุโดยตรง
ตัวอย่างที่ 13: การจัดการอาร์เรย์ผ่านการสะท้อน การสาธิตชั้นเรียนสาธารณะ {
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
อินท์[] arr = {1,2,3,4,5};
คลาส<?> c = arr.getClass().getComponentType();
System.out.println("ประเภทอาร์เรย์: " + c.getName());
int len = Array.getLength(arr);
System.out.println("ความยาวอาร์เรย์: " + len);
System.out.print("สำรวจอาร์เรย์: ");
สำหรับ (int i = 0; i <len; i++) {
System.out.print(Array.get(arr, i) + " ");
-
System.out.println();
//แก้ไขอาร์เรย์
System.out.println("องค์ประกอบแรกก่อนการแก้ไข: " + Array.get(arr, 0));
Array.set(arr, 0, 3);
System.out.println("องค์ประกอบแรกที่แก้ไข: " + Array.get(arr, 0));
-
-
ในตอนนี้หนังสือที่ฉันอ่านมีการใช้งานการสะท้อนกลับในโหมดโรงงานด้วย
ไม่มีอะไรมากไปกว่าการแทนที่ด้วยเมธอด forName()
ฉันเป็นมือใหม่ใน Java ฉันเกลียดไวยากรณ์และการออกแบบที่น่าขยะแขยงของ Java
ทั้งหมดนี้มีไว้สำหรับ Android เพื่อวางรากฐาน และปรับให้เข้ากับงานในอนาคต