1. กลไกการสะท้อนคืออะไร?
พูดง่ายๆ ก็คือ กลไกการสะท้อนหมายความว่าโปรแกรมสามารถรับข้อมูลของตัวเองในขณะที่ทำงาน ใน Java ตราบใดที่ระบุชื่อของคลาส ข้อมูลทั้งหมดเกี่ยวกับคลาสสามารถรับได้ผ่านกลไกการสะท้อนกลับ
2. กลไกการสะท้อนใช้อยู่ที่ไหน?
บางครั้งเราใช้ความรู้มาบ้างแล้ว แต่เราไม่รู้ว่าคำศัพท์ทางวิชาชีพคืออะไร เมื่อเราเพิ่งเรียน jdbc เราใช้บรรทัดของโค้ด Class.forName("com.mysql.jdbc.Driver.class") newInstance() ; แต่ในเวลานั้น ฉันรู้แค่ว่าบรรทัดของโค้ดนั้นสร้างอินสแตนซ์อ็อบเจ็กต์ไดรเวอร์ และฉันไม่รู้ความหมายเฉพาะของมัน หลังจากฟังบทเรียนเกี่ยวกับกลไกการสะท้อนกลับ ฉันพบว่านี่คือการสะท้อนกลับ ในปัจจุบัน กรอบงานแบบเปิดจำนวนมากใช้กลไกการสะท้อนกลับทั้งหมดถูกนำไปใช้โดยใช้กลไกการสะท้อนกลับ
3. ข้อดีและข้อเสียของกลไกการสะท้อนแสง
ทำไมต้องใช้กลไกการสะท้อน? การสร้างวัตถุโดยตรงยังไม่เพียงพอหรือ สิ่งนี้เกี่ยวข้องกับแนวคิดเรื่องไดนามิกและแบบคงที่
การคอมไพล์แบบคงที่: ประเภทจะถูกกำหนด ณ เวลาคอมไพล์ และอ็อบเจ็กต์ถูกผูกไว้ นั่นคือ ผ่านแล้ว
การคอมไพล์แบบไดนามิก: กำหนดประเภทและผูกอ็อบเจ็กต์ขณะรันไทม์ การคอมไพล์แบบไดนามิกเพิ่มความยืดหยุ่นของ Java ให้สูงสุด รวมแอปพลิเคชันแบบโพลีมอร์ฟิก และลดการเชื่อมต่อระหว่างคลาส
กล่าวอีกนัยหนึ่ง ข้อดีของกลไกการสะท้อนคือสามารถสร้างวัตถุแบบไดนามิกและคอมไพล์ได้ ซึ่งแสดงให้เห็นถึงความยืดหยุ่นอย่างมาก โดยเฉพาะอย่างยิ่งในการพัฒนา J2EE ความยืดหยุ่นของมันชัดเจนมาก ตัวอย่างเช่น สำหรับซอฟต์แวร์ขนาดใหญ่ มันเป็นไปไม่ได้ที่จะออกแบบได้อย่างสมบูรณ์แบบในคราวเดียว หลังจากที่โปรแกรมถูกคอมไพล์และเผยแพร่แล้ว เมื่อพบว่าจำเป็นต้องอัปเดตฟังก์ชันบางอย่าง เราไม่สามารถขอให้ผู้ใช้ถอนการติดตั้งเวอร์ชันก่อนหน้าได้ แล้วติดตั้งใหม่ ในกรณีนี้ ซอฟต์แวร์นี้จะไม่ถูกใช้งานโดยคนจำนวนมากอย่างแน่นอน หากเป็นแบบคงที่ โปรแกรมทั้งหมดจะต้องได้รับการคอมไพล์ใหม่หนึ่งครั้งจึงจะทราบถึงการอัปเดตฟังก์ชัน หากใช้กลไกการสะท้อน ก็ไม่จำเป็นต้องถอนการติดตั้ง เพียงสร้างและคอมไพล์ขณะรันไทม์เท่านั้นจึงจะทราบฟังก์ชันดังกล่าว
ข้อเสียของมันคือผลกระทบต่อประสิทธิภาพ การใช้การสะท้อนกลับนั้นเป็นการดำเนินการแบบตีความ ซึ่งเราสามารถบอก JVM ว่าเราต้องการทำอะไรและตรงตามข้อกำหนดของเรา การดำเนินการดังกล่าวจะช้ากว่าการดำเนินการเดียวกันโดยตรงเสมอ
4. ข้อมูลใดบ้างที่สามารถรับได้โดยใช้กลไกการสะท้อนกลับ?
พูดง่ายๆ ก็คือ สามารถรับข้อมูลใดๆ ก็ตามที่มีอยู่ในคลาสได้ แต่สิ่งที่จำเป็นต้องมีคือต้องทราบชื่อของคลาส ไม่เช่นนั้นจะไม่มีข้อมูลเพิ่มเติม ขั้นแรก จะต้องสร้างออบเจ็กต์ Class ตามชื่อเต็มของคลาส ชั้นเรียนที่เข้ามา
Class c=Class.forName("className"); หมายเหตุ: className ต้องเป็นชื่อเต็ม นั่นคือ ต้องมีชื่อแพ็กเกจ เช่น cn.netjava.pojo.UserInfo;
วัตถุ obj=c.newInstance();//สร้างอินสแตนซ์ของวัตถุ
ตกลง เมื่อคุณมีวัตถุแล้ว ทุกอย่างก็จัดการได้ง่าย คุณสามารถรับข้อมูลอะไรก็ได้ที่คุณต้องการ
วิธีรับคอนสตรัคเตอร์
Constructor getConstructor(Class[] params)//รับ Constructor สาธารณะตามพารามิเตอร์ที่ระบุ
Constructor[] getConstructors()//รับ Constructor สาธารณะทั้งหมด
Constructor getDeclaredConstructor(Class[] params)//รับตัวสร้างสาธารณะและไม่ใช่สาธารณะตามพารามิเตอร์ที่ระบุ
Constructor[] getDeclaredConstructors()//รับ Constructor สาธารณะทั้งหมด
รับวิธีการของวิธีการเรียน
เมธอด getMethod(ชื่อสตริง พารามิเตอร์คลาส[]) รับเมธอดตามชื่อเมธอดและประเภทพารามิเตอร์
Method[] getMethods()//รับวิธีการสาธารณะทั้งหมด
เมธอด getDeclaredMethod(ชื่อสตริง พารามิเตอร์คลาส[])//ตามชื่อเมธอดและประเภทพารามิเตอร์ ขอรับเมธอดสาธารณะและไม่ใช่สาธารณะ
Method[] getDeclaredMethods()//รับวิธีการสาธารณะและไม่ใช่สาธารณะทั้งหมด
วิธีรับคุณสมบัติในคลาส
ฟิลด์ getField(ชื่อสตริง)//รับตัวแปรสาธารณะที่สอดคล้องกันตามชื่อตัวแปร
Field[] getFields()//รับวิธีการสาธารณะทั้งหมดในชั้นเรียน
ฟิลด์ getDeclaredField(ชื่อสตริง)//รับตัวแปรสาธารณะและไม่ใช่สาธารณะตามชื่อวิธีการ
Field[] getDeclaredFields()//รับวิธีการสาธารณะและไม่ใช่สาธารณะทั้งหมดในชั้นเรียน
สิ่งเหล่านี้คือสิ่งที่ใช้กันทั่วไป หากคุณรู้สิ่งเหล่านี้ ทุกอย่างก็จะจัดการได้ง่าย...
5. กลไกการสะท้อนสามารถทำอะไรได้บ้าง?
เมื่อฉันเริ่มใช้ jdbc ครั้งแรก ฉันรู้สึกอยากจะอาเจียนเมื่อเขียนเพื่อเข้าถึงฐานข้อมูล มีแปดตาราง และแต่ละตารางมีการบวก ลบ ปรับเปลี่ยน และค้นหา ในเวลานั้นฉันไม่รู้แนวคิดของ กลไกการสะท้อนกลับ ดังนั้นฉันจึงเขียนเกี่ยวกับการสร้างคลาส DAO ที่แตกต่างกันในตาราง ซึ่งไม่เพียงแต่เร่งการพัฒนา แต่ยังทำให้โค้ดซ้ำซ้อนอีกด้วย เนื่องจากเป็นเรื่องง่ายที่จะทำข้อผิดพลาดระดับต่ำต่างๆ (ตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก หายไปอีกหนึ่งตัวหรือตัวอักษรหายไปหนึ่งตัว...) ข้อผิดพลาดเพียงครั้งเดียวอาจทำให้คุณใช้เวลานานในการค้นหา
ด้วยกลไกการสะท้อนของ Java ทุกอย่างเป็นเรื่องง่ายที่จะจัดการ คุณเพียงแค่ต้องเขียนคลาส dao ด้วยสี่วิธี เพิ่ม ลบ แก้ไข และสอบถาม และส่งผ่านไปยังอ็อบเจ็กต์ต่างๆ คลาส dao สำหรับแต่ละตาราง กลไกการสะท้อนจะทำส่วนที่เหลือให้เราโดยอัตโนมัติ นั่นคือประโยชน์ของมัน พูดตรงๆ ก็คือ กลไกการสะท้อนกลับได้รับการออกแบบมาเพื่อช่วยเราทำสิ่งซ้ำๆ และสม่ำเสมอ ดังนั้นซอฟต์แวร์จำนวนมากที่สร้างโค้ดโดยอัตโนมัติจึงใช้กลไกการสะท้อนเพื่อทำให้เสร็จสมบูรณ์ ตราบใดที่คุณป้อนพารามิเตอร์ที่เกี่ยวข้องตามกฎ ต่ำ- โปรแกรมเมอร์ระดับนั้นช้า ตัวที่ช้าก็ถูกกำจัดไป เพราะเหตุใด? เพราะไม่จำเป็นต้องเขียนโค้ด ใครๆ ก็พัฒนาได้ แล้วทำไมโปรแกรมเมอร์ถึงทำล่ะ? เรามีทางออกทางเดียวเท่านั้น นั่นคือทำงานหนักและทำงานหนักขึ้น เป็นโปรแกรมเมอร์อาวุโส เชี่ยวชาญในการพัฒนาซอฟต์แวร์โง่ ๆ และปล่อยให้โปรแกรมเมอร์คนอื่น ๆ ใจเย็น ๆ 555
6. ตัวอย่างการใช้กลไกการสะท้อนเพื่อเพิ่มและตรวจสอบข้อมูลฐานข้อมูล
หลักการพื้นฐาน: เมื่อบันทึกข้อมูล ให้นำค่าแอตทริบิวต์ทั้งหมดของออบเจ็กต์ที่ต้องการบันทึกออก จากนั้นจึงรวบรวมคำสั่ง SQL สำหรับการสืบค้น และรวมข้อมูลที่สืบค้นทั้งหมดไว้ในออบเจ็กต์ Java
กฎของเกม: ดังคำกล่าวที่ว่า ไม่มีอะไรที่ปราศจากกฎเกณฑ์ โดยเฉพาะอย่างยิ่งสำหรับโปรแกรม มันสามารถทำอะไรได้โดยมีกฎเกณฑ์เท่านั้น โอเค มาตั้งกฎกันก่อน
1) แต่ละวัตถุตารางในฐานข้อมูลมีคลาส pojo และแต่ละฟิลด์ในตารางสอดคล้องกับแอตทริบิวต์ในคลาส pojo นอกจากนี้ ชื่อของคลาส pojo จะเหมือนกับชื่อของตาราง และชื่อแอ็ตทริบิวต์และชื่อฟิลด์จะเหมือนกัน เนื่องจากฐานข้อมูลโดยทั่วไปไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
2) เพิ่มชุดมาตรฐานและรับวิธีการสำหรับแต่ละแอตทริบิวต์ในคลาส pojo
ด้วยกฎของเกมเรามาเริ่มเล่นกัน
1. ขั้นแรก มีตารางในฐานข้อมูล สมมติว่าชื่อฐานข้อมูลคือ: blogsystem และชื่อตารางในนั้นเป็นข้อมูลผู้ใช้ ดังแสดงในภาพ:
2. สร้างคลาส pojo ที่เกี่ยวข้อง:
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ cn.netjava.pojo;
ข้อมูลผู้ใช้คลาสสาธารณะ {
รหัสส่วนตัวส่วนตัว;
ชื่อสตริงส่วนตัว
pwd สตริงส่วนตัว;
อายุ int ส่วนตัว
@แทนที่
สตริงสาธารณะ toString() {
กลับ "UserInfo [id=" + id + ", name=" + name + ", pwd=" + pwd + ", age="
+ อายุ + "]";
-
สาธารณะ int getId() {
รหัสส่งคืน;
-
setId โมฆะสาธารณะ (int id) {
this.id = ไอดี;
-
สตริงสาธารณะ getName() {
ชื่อผู้ส่งคืน;
-
setName โมฆะสาธารณะ (ชื่อสตริง) {
this.name = ชื่อ;
-
สตริงสาธารณะ getPwd() {
ส่งคืน pwd;
-
โมฆะสาธารณะ setPwd (สตริง pwd) {
นี่.pwd = pwd;
-
สาธารณะ int getAge() {
อายุกลับ;
-
setAge โมฆะสาธารณะ (อายุ int) {
this.age = อายุ;
-
-
2. เขียนคลาสโรงงานเพื่อรับการเชื่อมต่อฐานข้อมูล:
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ cn.netjava.factory;
นำเข้า java.sql.Connection;
นำเข้า java.sql.DriverManager;
Connect2DBFactory ระดับสาธารณะ {
การเชื่อมต่อสาธารณะ getDBConnection () {
การเชื่อมต่อการเชื่อมต่อ = null;
พยายาม {
Class.forName("com.mysql.jdbc.Driver");
สตริง url = "jdbc:mysql://localhost:3306/blogsystem";
ผู้ใช้สตริง = "root";
รหัสผ่านสตริง = "netjava";
conn = DriverManager.getConnection (url, ผู้ใช้, รหัสผ่าน);
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
-
กลับคอน;
-
-
3. ความสนุกเริ่มต้นขึ้นด้วยการเขียนคลาส dao ที่ใช้งานฐานข้อมูล
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ cn.netjava.session;
นำเข้า java.lang.reflect.Field;
นำเข้า java.lang.reflect.Method;
นำเข้า java.sql.Connection;
นำเข้า java.sql.PreparedStatement;
นำเข้า java.sql.ResultSet;
นำเข้า java.sql.SQLException;
นำเข้า java.sql.Statement;
นำเข้า java.util.ArrayList;
นำเข้า java.util.List;
นำเข้า cn.netjava.factory.Connect2DBFactory;
นำเข้า cn.netjava.pojo.UserInfo;
NetJavaSession คลาสสาธารณะ {
-
* แยกวิเคราะห์คำสั่ง sql ที่บันทึกวัตถุ
-
* วัตถุ @param
*: วัตถุที่ต้องการบันทึก
* @return: คำสั่ง sql เพื่อบันทึกวัตถุ
-
สตริงสาธารณะ getSaveObjectSql (วัตถุวัตถุ) {
//กำหนดสตริง sql
สตริง sql = "ใส่ลงใน";
// รับคลาสของวัตถุ
คลาส c = object.getClass();
// รับวิธีการทั้งหมดในวัตถุ
วิธีการ [] วิธีการ = c.getMethods();
// รับคุณสมบัติทั้งหมดในวัตถุ
ฟิลด์ [] ฟิลด์ = c.getFields();
// รับชื่อของคลาสอ็อบเจ็กต์
สตริง cName = c.getName();
// แยกชื่อตารางออกจากชื่อคลาส
สตริง tableName = cName.substring(cName.lastIndexOf(".") + 1,
cName.ความยาว());
sql += ชื่อตาราง + "(";
รายการ <สตริง> mList = ใหม่ ArrayList<String>();
รายการ vList = ใหม่ ArrayList();
สำหรับ (วิธีการ วิธีการ : วิธีการ) {
สตริง mName = method.getName();
ถ้า (mName.startsWith("get") && !mName.startsWith("getClass")) {
สตริง fieldName = mName.substring(3, mName.length());
mList.add(ชื่อฟิลด์);
System.out.println("ชื่อฟิลด์----->" + ชื่อฟิลด์);
พยายาม {
ค่าวัตถุ = method.inurge (วัตถุ null);
System.out.println("ค่าที่ส่งคืนโดยวิธีการดำเนินการ: " + value);
ถ้า (ค่าอินสแตนซ์ของสตริง) {
vList.add("/"" + ค่า + "/"");
System.out.println("ค่าฟิลด์------>" + ค่า);
} อื่น {
vList.add(ค่า);
-
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
-
-
-
สำหรับ (int i = 0; i < mList.size(); i++) {
ถ้า (i < mList.size() - 1) {
sql += mList.get(i) + ",";
} อื่น {
sql += mList.get(i) + ") ค่า(";
-
-
สำหรับ (int i = 0; i < vList.size(); i++) {
ถ้า (i < vList.size() - 1) {
sql += vList.get(i) + ",";
} อื่น {
sql += vList.get(i) + ")";
-
-
ส่งคืน sql;
-
รายการสาธารณะคงที่ getDatasFromDB (String tableName, int Id) {
กลับเป็นโมฆะ;
-
-
* บันทึกวัตถุลงในฐานข้อมูล
-
* วัตถุ @param
*: วัตถุที่ต้องการบันทึก
* @return: ผลลัพธ์ของการดำเนินการเมธอด 1: บ่งชี้ถึงความสำเร็จ 0: บ่งชี้ถึงความล้มเหลว
-
int saveObject สาธารณะ (วัตถุวัตถุ) {
การเชื่อมต่อ = Connect2DBFactory.getDBConnection();
สตริง sql = getSaveObjectSql (วัตถุ);
พยายาม {
// คำสั่ง คำสั่ง=(คำสั่ง) con.createStatement();
ReadyStatement psmt = con.prepareStatement(sql);
psmt.executeUpdate();
กลับ 1;
} จับ (SQLException e) {
e.printStackTrace();
กลับ 0;
-
-
-
* รับวัตถุจากฐานข้อมูล
-
* @param arg0
*: คลาสที่วัตถุอยู่
* @param id
*: รหัสของวัตถุ
* @return: วัตถุที่จะพบ
-
วัตถุสาธารณะ getObject (String className, int Id) {
// รับชื่อตาราง
สตริง tableName = className.substring(className.lastIndexOf(".") + 1,
className.ความยาว());
//สร้างวัตถุคลาสตามชื่อคลาส
คลาส c = โมฆะ;
พยายาม {
c = Class.forName(ชื่อคลาส);
} จับ (ClassNotFoundException e1) {
e1.printStackTrace();
-
// รวมคำสั่ง query sql เข้าด้วยกัน
สตริง sql = "เลือก * จาก" + tableName + " โดยที่ Id=" + Id;
System.out.println("ค้นหาคำสั่ง sql: " + sql);
// รับลิงค์ฐานข้อมูล
การเชื่อมต่อ = Connect2DBFactory.getDBConnection();
//สร้างอินสแตนซ์ของคลาส
วัตถุ obj = โมฆะ;
พยายาม {
คำสั่ง stm = con.createStatement();
// รับชุดผลลัพธ์ที่ส่งคืนโดยดำเนินการคำสั่งการค้นหา
ชุด ResultSet = stm.executeQuery(sql);
// รับอาร์เรย์วิธีการของวัตถุ
วิธีการ [] วิธีการ = c.getMethods();
// สำรวจชุดผลลัพธ์
ในขณะที่ (set.next()) {
obj = c.newInstance();
//วิธีการสำรวจวัตถุ
สำหรับ (วิธีการ วิธีการ : วิธีการ) {
สตริง methodName = method.getName();
// ถ้าเมธอดของอ็อบเจ็กต์เริ่มต้นด้วย set
ถ้า (methodName.startsWith("set")) {
// รับชื่อของเขตข้อมูลในตารางข้อมูลตามชื่อวิธีการ
สตริง columnName = methodName.substring (3,
methodName.ความยาว());
// รับประเภทพารามิเตอร์ของวิธีการ
คลาส [] parmts = method.getParameterTypes();
ถ้า (parmts[0] == String.class) {
// หากพารามิเตอร์เป็นประเภท String ให้รับค่าที่สอดคล้องกันจากชุดผลลัพธ์ตามชื่อคอลัมน์ และดำเนินการเมธอด set
method.invoke(obj, set.getString(columnName));
-
ถ้า (parmts[0] == int.class) {
method.invoke(obj, set.getInt(columnName));
-
-
-
-
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
-
กลับ obj;
-
-
4. ผลของการเริ่มต้นการทดสอบเป็นอย่างไร:
คัดลอกรหัสรหัส ดังต่อไปนี้:
แพ็คเกจ cn.netjava.tester;
นำเข้า cn.netjava.pojo.UserInfo;
นำเข้า cn.netjava.session.NetJavaSession;
ผู้ทดสอบคลาสสาธารณะ {
โมฆะคงที่สาธารณะ main (String args []) {
// รับวัตถุ NetJavaSession
เซสชัน NetJavaSession = NetJavaSession ใหม่ ();
//สร้างวัตถุ UserInfo
ผู้ใช้ UserInfo = UserInfo ใหม่ ();
//กำหนดคุณสมบัติของวัตถุ
ผู้ใช้ setId(6988);
user.setAge(44);
user.setPwd("pwd");
user.setName("แชมป์");
//บันทึกวัตถุลงฐานข้อมูล
สตริง sql = session.getSaveObjectSql (ผู้ใช้);
System.out.println("คำสั่ง SQL เพื่อบันทึกวัตถุ: " + sql);
//ค้นหาวัตถุ
UserInfo userInfo = (ข้อมูลผู้ใช้) session.getObject(
"cn.netjava.pojo.UserInfo", 6988);
System.out.println("ข้อมูลที่ได้รับ: " + userInfo);
-
-
5. ผลลัพธ์ที่พิมพ์:
7. มาสรุปกันดีกว่า
โดยทั่วไปแล้วกลไกการสะท้อนกลับของ Java เป็นสิ่งที่มีประโยชน์มาก มันสามารถแก้ไขสิ่งที่ตายไปแล้วได้มากมายเนื่องจากกลไกการสะท้อนกลับนั้นมีความยืดหยุ่นมาก เราไม่จำเป็นต้องใช้เวลาเขียนการดำเนินการมากเกินไป แทนที่จะใช้โค้ดฐานข้อมูล วิธีการนี้ใช้เวลามากขึ้นกับฟังก์ชันลอจิคัลของโปรเจ็กต์ ซึ่งจะช่วยลดเวลาในการพัฒนาและทำให้โค้ดอ่านได้ง่ายขึ้น กรอบงานโอเพ่นซอร์สที่มีอยู่จำนวนมากใช้กลไกการสะท้อนกลับ พวกเขาเพียงต้องกำหนดค่าไฟล์แล้วเรียกวิธีการตามกฎ