ในบทความนี้ เราจะอธิบายว่าการทำให้เป็นอนุกรมคืออะไรและทำงานอย่างไรใน Java
รูปที่ 1 การแสดงเธรดแบบกราฟิก
สตรีมแบ่งออกเป็นสองประเภทหลัก:
การแนะนำ
การทำให้เป็นอนุกรมของออบเจ็กต์คือความสามารถของออบเจ็กต์ในการจัดเก็บสำเนาที่สมบูรณ์ของตัวเองและออบเจ็กต์อื่น ๆ ที่อ้างอิงโดยใช้สตรีมเอาต์พุต (เช่น ไปยังไฟล์ภายนอก) ด้วยวิธีนี้ วัตถุจะถูกสร้างขึ้นใหม่จากสำเนาซีเรียลไลซ์ (ที่บันทึกไว้) ในภายหลังเล็กน้อยเมื่อจำเป็น การทำให้เป็นอนุกรมของอ็อบเจ็กต์เป็นคุณสมบัติใหม่ที่นำมาใช้ใน JDK 1.1 มีฟังก์ชันสำหรับการแปลงกลุ่มหรืออ็อบเจ็กต์แต่ละรายการให้เป็นบิตสตรีมหรืออาร์เรย์ไบต์ สำหรับการจัดเก็บหรือการส่งผ่านเครือข่าย และตามที่ระบุไว้ บิตสตรีมหรืออาร์เรย์ไบต์ที่กำหนดสามารถแปลงกลับเป็นอ็อบเจ็กต์ Java ได้ สิ่งนี้ส่วนใหญ่เกิดขึ้นโดย อัตโนมัติด้วย คลาสObjectInputStream
และ ObjectOutputStream
โปรแกรมเมอร์อาจตัดสินใจที่จะใช้ฟังก์ชันนี้โดยการใช้อินเทอร์เฟซSerializable
เมื่อสร้างคลาส กระบวนการทำให้เป็นอนุกรมเรียกอีกอย่างว่า object marshalingในขณะที่การดีซีเรียลไลซ์เรียกว่าunmarshaling การทำให้เป็นอนุกรมเป็นกลไกที่อนุญาตให้ออบเจ็กต์บันทึกสำเนาของตัวเองและออบเจ็กต์อื่น ๆ ทั้งหมดที่อ้างอิงโดยออบเจ็กต์นั้นไปยังไฟล์ภายนอกโดยใช้นามสกุลObjectOutputStream
. ออบเจ็กต์ที่บันทึกไว้อาจเป็นโครงสร้างข้อมูล ไดอะแกรม ออบเจ็กต์คลาสJFrame
หรือออบเจ็กต์อื่นใด โดยไม่คำนึงถึงประเภทของออบเจ็กต์ ในเวลาเดียวกัน การซีเรียลไลซ์จะเก็บข้อมูลเกี่ยวกับประเภทของออบเจ็กต์ เพื่อว่าในภายหลังเมื่อดีซีเรียลไลซ์ ข้อมูลนั้นจะถูกใช้เพื่อสร้างประเภทออบเจ็กต์ที่แน่นอนอีกครั้ง ดังนั้นการทำให้เป็นอนุกรมจึงมีความสามารถดังต่อไปนี้:
- ระบบสำหรับจัดเก็บอ็อบเจ็กต์ เช่น การบันทึกคุณสมบัติลงในไฟล์ภายนอก ลงดิสก์ หรือในฐานข้อมูล
- ระบบเรียกขั้นตอนระยะไกล
- ระบบการกระจายออบเจ็กต์ ตัวอย่างเช่น ในส่วนประกอบซอฟต์แวร์ เช่น COM, COBRA
- ระบบระบุการเปลี่ยนแปลงของข้อมูลตัวแปรในช่วงเวลาหนึ่ง
สตรีม:
ทุกโปรแกรมจะต้องเขียนข้อมูลไปยังตำแหน่งหน่วยเก็บข้อมูลหรือไปป์ และทุกโปรแกรมจะต้องอ่านข้อมูลจากไปป์หรือตำแหน่งหน่วยเก็บข้อมูล ใน Java ช่องทางเหล่านี้ที่โปรแกรมเขียนถึงและจาก ที่ โปรแกรมอ่านข้อมูลเรียกว่าStreams (Stream
)
- คลาสสตรีมไบต์ที่เรียกว่า *Streams
- คลาสสตรีมอักขระที่เรียกว่า *Reader และ *Writer
วิริยะ
ความคงอยู่ของวัตถุคือความสามารถของวัตถุที่จะมีชีวิตอยู่หรือกล่าวอีกนัยหนึ่งคือการ "รอด" การทำงานของโปรแกรม ซึ่งหมายความว่าอ็อบเจ็กต์ใดๆ ที่ถูกสร้างขึ้นตอนรันไทม์จะถูกทำลายโดย JVM scavenger ทุกครั้งที่ไม่มีการใช้อ็อบเจ็กต์นั้นอีกต่อไป แต่หากมีการนำ Peristence API มาใช้ ออบเจ็กต์เหล่านี้จะไม่ถูกทำลายโดย JVM Scavenger แต่จะได้รับอนุญาตให้ "ใช้งานอยู่" แทน ซึ่งทำให้สามารถเข้าถึงได้ในครั้งถัดไปที่เปิดตัวแอปพลิเคชัน กล่าวอีกนัยหนึ่ง การคงอยู่หมายความว่าออบเจ็กต์จะมีอายุการใช้งานตลอดชีวิต โดยไม่ขึ้นกับอายุการใช้งานของแอปพลิเคชันที่กำลังทำงานอยู่ วิธีหนึ่งในการนำการคงอยู่ไปใช้คือการจัดเก็บออบเจ็กต์ไว้ที่ใดที่หนึ่งในไฟล์หรือฐานข้อมูลภายนอก แล้วคืนค่าในภายหลังโดยใช้ไฟล์เหล่านั้นหรือฐานข้อมูลเป็นแหล่งที่มา นี่คือที่มาของการทำให้เป็นอนุกรม อ็อบเจ็กต์ที่ไม่ถาวรใดๆ มีอยู่ตราบเท่าที่ JVM กำลังทำงานอยู่ อ็อบเจ็กต์แบบอนุกรมเป็นเพียงอ็อบเจ็กต์ที่ถูกแปลงเป็นสตรีม ซึ่งจากนั้นจะถูกบันทึกเป็นไฟล์ภายนอกหรือถ่ายโอนผ่านเครือข่ายเพื่อจัดเก็บและกู้คืนการใช้งานอินเทอร์เฟซแบบอนุกรม
คลาสใด ๆ ต้องใช้อินเทอร์เฟซjava.io.Serializable
เพื่อทำให้วัตถุเป็นอนุกรมของคลาสนั้น อินเทอร์เฟซSerializable
ไม่มีวิธีการและทำเครื่องหมายเฉพาะคลาสเพื่อให้สามารถระบุเป็นอนุกรมได้ สามารถบันทึกได้เฉพาะฟิลด์ของอ็อบเจ็กต์คลาสซีเรียลไลซ์เท่านั้น วิธีการหรือตัวสร้างจะไม่ถูกจัดเก็บเป็นส่วนหนึ่งของกระแสข้อมูลแบบอนุกรม หากวัตถุใดทำหน้าที่เป็นการอ้างอิงไปยังวัตถุอื่น ฟิลด์ของวัตถุนั้นก็จะถูกทำให้เป็นอนุกรมเช่นกัน หากคลาสของวัตถุนั้นใช้อินเทอร์เฟSerializable
ซ กล่าวอีกนัยหนึ่ง กราฟของวัตถุนี้ที่ได้รับจึงสามารถทำให้เป็นอนุกรมได้อย่างสมบูรณ์ กราฟวัตถุประกอบด้วยแผนภูมิหรือโครงสร้างของช่องของวัตถุและวัตถุย่อย สองคลาสหลักที่ช่วยปรับใช้อินเทอร์เฟซSeriliazable
:
ObjectInputStream
ObjectOutputStream
import java.io.*;
public class RandomClass implements Serializable {
// Генерация рандомного значения
private static int r() {
return (int)(Math.random() * 10);
}
private int data[];
// Конструктор
public RandomClass() {
datafile = new int[r()];
for (int i=0; i<datafile.length; i++)
datafile[i]=r();
}
public void printout() {
System.out.println("This RandomClass has "+datafile.length+" random integers");
for (int i=0; i<datafile.length; i++) {
System.out.print(datafile[i]+":");
System.out.println();
}
}
ในโค้ดข้างต้น มีการสร้างคลาสที่สามารถซีเรียลไลซ์ได้เนื่องจาก "ทำเครื่องหมาย" โดยอินเทอร์เฟซการทำให้เป็นอนุกรม คลาสจะสร้างอาร์เรย์ของจำนวนเต็มสุ่มเมื่อมีการสร้างอินสแตนซ์ขึ้นมา โค้ดด้านล่างแสดงความสามารถในการเขียนออบเจ็กต์ไปยังสตรีมโดยใช้ส่วนขยายObjectOutputStream
. โปรแกรมมีอาร์เรย์ของจำนวนเต็ม แต่สำหรับการทำให้เป็นอนุกรม เราไม่จำเป็นต้องวนซ้ำอ็อบเจ็กต์ภายใน อินเทอร์เฟซSeriliazable
จะดูแลสิ่งนี้โดยอัตโนมัติ รายการ 2 ตัวอย่างง่ายๆ ของการทำให้วัตถุเป็นอนุกรมสำหรับเอาต์พุตไปยังไฟล์
import java.io.*;
import java.util.*;
public class OutSerialize {
public static void main (String args[]) throws IOException {
RandomClass rc1 = new RandomClass();
RandomClass rc2 = new RandomClass();
//создание цепи потоков с потоком вывода an object в конце
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objects.dat"));
Date now = new Date(System.currentTimeMillis());
//java.util.* был импортирован для использования класса Date
out.writeObject(now);
out.writeObject(rc1);
out.writeObject(rc2);
out.close();
System.out.println("I have written:");
System.out.println("A Date object: "+now);
System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
}
}
โค้ดด้านล่างแสดงให้เห็นถึงความสามารถของคลาสObjectInputStream
ซึ่งอ่านข้อมูลซีเรียลไลซ์จากไฟล์ภายนอกลงในโปรแกรม โปรดทราบว่าวัตถุจะถูกอ่านในลำดับเดียวกับที่เขียนลงในไฟล์ รายการ 3. การอ่านวัตถุแบบอนุกรมหรือการดีซีเรียลไลซ์
import java.io.*;
import java.util.*;
public class InSerialize {
public static void main (String args[]) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream (new FileInputStream("objects.dat"));
Date d1 = (Date)in.readObject();
RandomClass rc1 = (RandomClass)in.readObject();
RandomClass rc2 = (RandomClass)in.readObject();
System.out.println("I have read:");
System.out.println("A Date object: "+d1);
System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
}
}
คลาส Java เกือบทั้งหมดสามารถซีเรียลไลซ์ได้ รวมถึงคลาส AWT เฟรม ซึ่งเป็นหน้าต่าง ประกอบด้วยชุดของส่วนประกอบกราฟิก หากเฟรมถูกทำให้เป็นอนุกรม โปรแกรมทำให้เป็นอนุกรมจะดูแลสิ่งนี้และทำให้เป็นอนุกรมส่วนประกอบและข้อมูลทั้งหมด (ตำแหน่ง เนื้อหา ฯลฯ) อ็อบเจ็กต์คลาส Java บางตัวไม่สามารถทำให้เป็นอนุกรมได้เนื่องจากมีข้อมูลที่อ้างอิงถึงทรัพยากรระบบปฏิบัติการชั่วคราว เช่น คลาสjava.io.FileInputStream
และjava.lang.Thread
. หากออบเจ็กต์มีการอ้างอิงถึงองค์ประกอบที่ไม่ทำให้เป็นอนุกรม การดำเนินการทำให้เป็นอนุกรมทั้งหมดจะล้มเหลวและข้อยกเว้นจะถูกส่งออกNotSerializableException
ไป หากอ็อบเจ็กต์ใดๆ อ้างถึงการ อ้างอิง ของอ็อบเจ็กต์ที่ไม่ต่อเนื่อง ก็สามารถทำให้เป็นอนุกรมได้โดยใช้ คีย์เวิร์ด ชั่วคราว รายการ 4 การสร้างออบเจ็กต์ที่ทำให้ซีเรียลไลซ์ได้โดยใช้ คีย์เวิร์ดชั่วคราว
public class Sclass implements Serializable{
public transient Thread newThread;
//помните, что поток(поток параллельного исполнения) по умолчанию не сериализуемый класс
private String studentID;
private int sum;
}
ความปลอดภัยในการทำให้เป็นอนุกรม
การทำให้คลาสเป็นอนุกรมใน Java เกี่ยวข้องกับการส่งข้อมูลทั้งหมดไปยังไฟล์ภายนอกหรือฐานข้อมูลผ่านทางสตรีม เราสามารถจำกัดข้อมูลที่จะถูกซีเรียลไลซ์ได้ทุกเมื่อที่ต้องการ มีสองวิธีในการทำเช่นนี้:- พารามิเตอร์คลาสแต่ละรายการที่ประกาศเป็นแบบชั่วคราวจะไม่ถูกทำให้เป็นอนุกรม (โดยค่าเริ่มต้น พารามิเตอร์ของคลาสทั้งหมดจะถูกทำให้เป็นอนุกรม)
- หรือแต่ละพารามิเตอร์คลาสที่เราต้องการทำให้เป็นอนุกรมจะถูกทำเครื่องหมายด้วยแท็ก
Externalizable
(โดยค่าเริ่มต้น ไม่มีพารามิเตอร์ใดที่ทำให้เป็นอนุกรม)
ObjectOutputStream
เมื่อเรียกใช้บนออบเจ็กต์ หากเขตข้อมูลของออบเจ็กต์นั้นถูกทำเครื่องหมายว่าชั่วคราว ตัวอย่างเช่น: private transient String password
. ในทางกลับกัน เพื่อประกาศข้อมูลของวัตถุอย่างชัดเจนว่าเป็นอนุกรมได้ เราต้องทำเครื่องหมายชั้นเรียนว่าเขียนและอ่านข้อมูลของวัตถุนั้น ExternalizablewriteExternal
อย่างชัดเจนreadExteranl
บทสรุป
คุณลักษณะของการทำให้เป็นอนุกรมของอ็อบเจ็กต์นั้นใช้ในระบบแบบกระจายจำนวนมากเพื่อเป็นวิธีการถ่ายโอนข้อมูล แต่การทำให้เป็นอนุกรมจะเปิดเผยรายละเอียดที่ซ่อนอยู่ ซึ่งทำลายความถูกต้องของประเภทข้อมูลนามธรรม ซึ่งจะทำลายการห่อหุ้ม ในเวลาเดียวกัน เป็นเรื่องดีที่ทราบว่าข้อมูลของออบเจ็กต์ซีเรียลไลซ์นั้นเป็นข้อมูลเดียวกับที่อยู่ในออบเจ็กต์ดั้งเดิม นี่เป็นโอกาสอันดีในการใช้อินเทอร์เฟซObjectInputValidation
และแทนที่เมธอดvalidateObject()
แม้ว่าจะใช้โค้ดหลายบรรทัดก็ตาม หากไม่พบวัตถุ เราก็สามารถโยนข้อยกเว้นได้อย่างInvalidObjectException
เหมาะสม บทความต้นฉบับ: วิธีการทำงานของการทำให้เป็นอนุกรมใน Java
GO TO FULL VERSION