ความแตกต่างระหว่าง Java และภาษาอื่นๆ คือ Java ทำงานบน Java Virtual Machine (JVM) ซึ่งหมายความว่าโค้ดที่คอมไพล์แล้วจะถูกบันทึกในรูปแบบที่ไม่ขึ้นกับแพลตฟอร์ม แทนที่จะเป็นรูปแบบที่ทำงานบนเครื่องเฉพาะ รูปแบบนี้มีความแตกต่างที่สำคัญมากมายจากรูปแบบโค้ดปฏิบัติการแบบเดิม โดยเฉพาะอย่างยิ่ง ไม่เหมือนกับโปรแกรม C หรือ C++ ตรงที่โปรแกรม Java ไม่ใช่ไฟล์ปฏิบัติการอิสระ แต่ประกอบด้วยไฟล์คลาสแยกจำนวนมาก แต่ละไฟล์คลาสสอดคล้องกับคลาส Java นอกจากนี้ไฟล์คลาสเหล่านี้จะไม่โหลดลงในหน่วยความจำทันที แต่จะโหลดเมื่อโปรแกรมต้องการ ตัวโหลดคลาสเป็นเครื่องมือที่ใช้ในเครื่องเสมือน Java เพื่อโหลดคลาสลงในหน่วยความจำ ยิ่งไปกว่านั้น ตัวโหลดคลาส Java ยังถูกนำไปใช้ใน Java อีกด้วย วิธีนี้ทำให้คุณสามารถสร้างคลาสโหลดเดอร์ของคุณเองได้อย่างง่ายดาย โดยไม่ต้องมีความเข้าใจเชิงลึกเกี่ยวกับ Java virtual machine
ทำไมต้องสร้างคลาสโหลดเดอร์?
ตอนนี้ Java virtual machine มีคลาสโหลดเดอร์อยู่แล้ว เราจำเป็นต้องสร้างคลาสอื่นขึ้นมาเองหรือไม่ เป็นคำถามที่ดี ตัวโหลดคลาสเริ่มต้นรู้วิธีโหลดคลาสจากระบบโลคัลเท่านั้น เมื่อโปรแกรมของคุณถูกคอมไพล์อย่างสมบูรณ์ โดยทั่วไปแล้วคลาสโหลดเดอร์เริ่มต้นจะทำงานได้ดี แต่สิ่งที่น่าตื่นเต้นที่สุดอย่างหนึ่งเกี่ยวกับ Java ก็คือการโหลดคลาสจากเครือข่ายได้ง่ายเพียงใด แทนที่จะโหลดเฉพาะในเครื่อง
ตัวอย่างเช่น เบราว์เซอร์สามารถโหลดคลาสผ่านตัวโหลดคลาสแบบกำหนดเองได้ มีหลายวิธีในการโหลดคลาส หนึ่งในสิ่งที่น่าตื่นเต้นที่สุดเกี่ยวกับ Java ก็คือ คุณสามารถปรับแต่งมันได้นอกเหนือจากจากท้องถิ่นหรือเครือข่าย:
* ตรวจสอบลายเซ็นดิจิทัลโดยอัตโนมัติก่อนที่จะรันโค้ดที่ไม่น่าเชื่อถือ
* ถอดรหัสรหัสตามรหัสผ่านที่ผู้ใช้ให้ไว้
* สร้างคลาสแบบไดนามิกตามความต้องการของผู้ใช้ ทุกสิ่งที่คุณสนใจสามารถรวมเข้ากับแอปพลิเคชันของคุณได้อย่างง่ายดายในรูปแบบของ bytecode ตัวอย่างของตัวโหลดคลาสแบบกำหนดเองหากคุณใช้ JDK (Java Software Development Kit) appletviewer (เบราว์เซอร์แอปพลิเคชันขนาดเล็ก) หรืออื่น ๆ
สำหรับเบราว์เซอร์ที่ฝังตัว Java คุณใช้คลาสโหลดเดอร์แบบกำหนดเองอยู่แล้ว เมื่อ Sun เปิดตัวภาษา Java ครั้งแรก หนึ่งในสิ่งที่น่าตื่นเต้นที่สุดคือการได้เห็นว่า Java รันโค้ดที่ดาวน์โหลดจากเว็บไซต์ระยะไกลอย่างไร ดำเนินการจากไซต์ระยะไกลผ่าน HTTP
รหัสไบต์ที่ส่งโดยการเชื่อมต่อ P ดูแปลกไปเล็กน้อย ใช้งานได้เนื่องจาก Java มีความสามารถในการติดตั้งคลาสโหลดเดอร์แบบกำหนดเอง เบราว์เซอร์แอปเพล็ตมีคลาสโหลดเดอร์ คลาสโหลดเดอร์นี้ไม่พบคลาส Java ในเครื่อง แต่จะเข้าถึงเซิร์ฟเวอร์ระยะไกล โหลดไฟล์ bytecode ดั้งเดิมผ่าน HTTP จากนั้นแปลงเป็นคลาส Java ในเครื่องเสมือน Java แน่นอนว่าคลาสโหลดเดอร์ทำสิ่งอื่นๆ มากมาย: พวกมันบล็อกคลาส Java ที่ไม่ปลอดภัย และป้องกันไม่ให้แอปเพล็ตที่แตกต่างกันบนเพจต่างๆ เข้ามารบกวนซึ่งกันและกัน Echidna ซึ่งเป็นแพ็คเกจที่เขียนโดย Luke Gorrie เป็นแพ็คเกจซอฟต์แวร์ Java แบบเปิดที่อนุญาตให้แอปพลิเคชัน Java หลายตัวทำงานอย่างปลอดภัยในเครื่องเสมือน Java ป้องกันการรบกวนระหว่างแอปพลิเคชันโดยใช้ตัวโหลดคลาสแบบกำหนดเองเพื่อให้แต่ละแอปพลิเคชันมีสำเนาของไฟล์คลาส
ตัวโหลดคลาส Java:
มีตัวโหลดคลาสสามตัวตามค่าเริ่มต้นใน Java: ตัวโหลดคลาส bootstrap, ตัวโหลดคลาสส่วนขยาย และตัวโหลดคลาสระบบ (เรียกอีกอย่างว่าตัวโหลดคลาสแอปพลิเคชัน)
Class Loader เป็นหนึ่งในคุณสมบัติที่ทรงพลังที่สุดของ Java แต่นักพัฒนามักจะลืมส่วนประกอบของคลาสโหลด ตัวโหลดคลาสเป็นคลาสที่รับผิดชอบในการค้นหาและโหลดไฟล์คลาสขณะรันไทม์ Java อนุญาตให้ใช้คลาสโหลดเดอร์ที่แตกต่างกัน แม้แต่คลาสโหลดเดอร์แบบกำหนดเอง
โปรแกรม Java มีไฟล์คลาสจำนวนมาก แต่ละไฟล์สอดคล้องกับคลาส Java เดียว ไฟล์คลาสเหล่านี้แตกต่างจากโปรแกรม C แบบคงที่ตรงที่ไฟล์คลาสเหล่านี้จะถูกโหลดลงในหน่วยความจำหนึ่งครั้งและจำเป็นต้องโหลดเมื่อใดก็ได้ นี่คือสิ่งที่ทำให้คลาสโหลดเดอร์แตกต่าง โดยรับไบต์โค้ดที่ไม่ขึ้นอยู่กับแพลตฟอร์มจากไฟล์ต้นฉบับ (โดยปกติจะเป็นไฟล์ .class หรือ .jar) จากนั้นโหลดลงในพื้นที่หน่วยความจำ JVM เพื่อให้สามารถตีความและดำเนินการได้ ตามค่าเริ่มต้น แต่ละคลาสของแอปพลิเคชันจะถูกโหลดโดย java.lang.ClassLoader เนื่องจากสามารถสืบทอดได้ จึงสามารถปรับปรุงฟังก์ชันการทำงานได้อย่างอิสระ
ตัวโหลดคลาสแบบกำหนดเอง
นำเข้า java.io.*;
นำเข้า java.net.*;
นำเข้า java.util.*;
นำเข้า java.lang.reflect.Method;
CustomClassLoader คลาสสาธารณะขยาย URLClassLoader {
อินพุต FileInputStream ส่วนตัว = null; // สตรีมอินพุตไฟล์
ByteArrayOutputStream ส่วนตัวออก = null; // สตรีมเอาต์พุตอาร์เรย์ไบต์
สตริงส่วนตัว [] url = null; // เส้นทางการโหลดไฟล์คลาส
ไบต์ส่วนตัว [] data = null; //Class file bytecode
ส่วนตัว String extensionalName = ""; //นามสกุลไฟล์คลาส
CustomClassLoader สาธารณะ (URL [] url) ส่งข้อยกเว้น {
ซุปเปอร์(URL);
this.url = สตริงใหม่ [urls.length];
สำหรับ (int i = 0; i < urls.length; i++) {
this.url[i] = urls[i].toURI().toString();
-
-
-
* แยกวิเคราะห์ URL
-
setFilePath เป็นโมฆะส่วนตัว () {
สำหรับ (int i = 0; i < this.url.length; i++) {
ถ้า (this.url[i].substring(0,4).toLowerCase().equals("file") == true) {
this.url[i] = this.url[i].สตริงย่อย(5);
-
-
-
-
* รับ bytecode ของไฟล์ที่มีชื่อคลาสที่ระบุ (ชื่อแพ็คเกจ + ชื่อคลาส)
* @ชื่อ ชื่อสตริง
* @return ไบต์[]
-
ไบต์ส่วนตัว [] getFileData (ชื่อสตริง) {
พยายาม {
this.setFilePath();
สำหรับ (URL สตริง: this.url) {
ชื่อไฟล์สตริง = url + name.replace('.', '/').concat(".") +
this.getExtensionalName();
input = new FileInputStream (ไฟล์ใหม่ (ชื่อไฟล์));
ถ้า (อินพุต != null) {
หยุดพัก;
-
-
ออก = ByteArrayOutputStream ใหม่ ();
ข้อมูล = ไบต์ใหม่ [1024];
อินท์เลน = -1;
ในขณะที่ ((len = input.read (ข้อมูล)) != -1) {
out.write (ข้อมูล, 0, เลน);
-
ข้อมูล = out.toByteArray();
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
} ในที่สุด {
พยายาม {
ถ้า (อินพุต != null)
อินพุต.ปิด();
ถ้า (ออก != null)
ออก.ปิด();
ส่งคืนข้อมูล
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
กลับเป็นโมฆะ;
-
-
-
-
* ค้นหาไฟล์คลาสตามชื่อคลาสที่ระบุ
* @param ชื่อ String
* @รีเทิร์นคลาส
-
คลาสที่ได้รับการป้องกัน findClassByName (ชื่อสตริง) {
พยายาม {
ไบต์ [] data = this.getFileData (ชื่อ);
ถ้า (ข้อมูล == null) {
กลับเป็นโมฆะ;
-
กลับ this.defineClass (ชื่อ, ข้อมูล, 0, data.length);
} จับ (ข้อยกเว้นจ) {
e.printStackTrace();
กลับเป็นโมฆะ;
-
-
-
* แทนที่วิธี loadClass()
* @param ชื่อ String
* @รีเทิร์นคลาส
-
loadClass ระดับสาธารณะ (ชื่อสตริง) {
คลาส c = โมฆะ;
พยายาม {
c = super.loadClass(ชื่อ);
} จับ (ClassNotFoundException จ) {
e.printStackTrace();
} ในที่สุด {
ถ้า (c == null) // เมื่อไม่ได้โหลดวิธีการเริ่มต้นของคลาสพาเรนต์ลงในคลาสที่ระบุ ให้ใช้วิธีการที่กำหนดเองเพื่อค้นหา
c = this.findClassByName (ชื่อ);
กลับค;
-
-
สตริงสาธารณะ getExtensionalName() {
กลับนามสกุลนามสกุล;
-
โมฆะสาธารณะ setExtensionalName (String extensionalName) {
นี้.extensionalName = extensionalName;
-
โมฆะคงที่สาธารณะ main (String [] args) พ่นข้อยกเว้น {
URL[] url = new URL[] {new URL("file:e:/"}); //เพิ่มพาธไปยังคลาสที่คุณต้องการโหลด
//สามารถเป็นเครือข่ายหรือท้องถิ่น
CustomClassLoader csl = CustomClassLoader ใหม่ (url);
csl.setExtensionalName("อาร์เอส");
คลาส c1 = csl.loadClass("com.demo");
วัตถุ obj = c1.newInstance();
วิธีการ วิธีการ = c1.getMethod("printText", null);
วิธีการวิงวอน (obj, null);
-