ความแตกต่างระหว่างSerializable
และExternalizable
ใน Java คืออะไร?
ความแตกต่างระหว่างSerializable
และExternalizable
ใน Java คืออะไร?
คำตอบ:
หากต้องการเพิ่มคำตอบอื่น ๆjava.io.Serializable
คุณจะได้รับความสามารถในการทำให้เป็นอันดับ "อัตโนมัติ" สำหรับวัตถุในชั้นเรียนของคุณ ไม่จำเป็นต้องใช้ตรรกะอื่นใดมันจะทำงานได้ รันไทม์ Java จะใช้การสะท้อนเพื่อหาวิธีการจัดเรียงและยกเลิกการปิดกั้นวัตถุของคุณ
ใน Java เวอร์ชันก่อนหน้าการสะท้อนช้ามากและกราฟวัตถุขนาดใหญ่แบบอนุกรม (เช่นในแอปพลิเคชันไคลเอนต์เซิร์ฟเวอร์ RMI) เป็นปัญหาประสิทธิภาพเล็กน้อย เพื่อจัดการกับสถานการณ์นี้มีการjava.io.Externalizable
จัดเตรียมอินเทอร์เฟซซึ่งเป็นเหมือนjava.io.Serializable
แต่มีกลไกที่เขียนขึ้นเองเพื่อดำเนินการฟังก์ชันการจัดเรียงและการยกเลิกการจัดเรียง (คุณจำเป็นต้องใช้งานreadExternal
และwriteExternal
วิธีการในชั้นเรียน สิ่งนี้ช่วยให้คุณสามารถแก้ไขปัญหาคอขวดของการสะท้อนแสงได้
ใน Java เวอร์ชันล่าสุด (1.3 เป็นต้นไปอย่างแน่นอน) ประสิทธิภาพของการสะท้อนนั้นดีกว่าที่เคยเป็นมาอย่างมากดังนั้นนี่จึงเป็นปัญหาที่น้อยมาก ฉันสงสัยว่าคุณจะถูกกดดันอย่างหนักเพื่อรับผลประโยชน์ที่มีความหมายจากExternalizable
JVM ที่ทันสมัย
นอกจากนี้กลไกการทำให้เป็นอันดับของ Java ในตัวไม่ใช่เพียงอย่างเดียวคุณสามารถรับการเปลี่ยนจากบุคคลที่สามเช่น JBoss Serialization ซึ่งเร็วกว่ามากและเป็นการแทนที่แบบหล่นสำหรับค่าเริ่มต้น
ข้อเสียใหญ่Externalizable
คือคุณต้องรักษาตรรกะนี้ด้วยตัวเอง - ถ้าคุณเพิ่มลบหรือเปลี่ยนฟิลด์ในชั้นเรียนของคุณคุณต้องเปลี่ยนwriteExternal
/ readExternal
วิธีการของคุณเพื่อบัญชี
โดยสรุปExternalizable
เป็นที่ระลึกของ Java 1.1 วัน ไม่จำเป็นต้องใช้มันอีกแล้ว
Externalizable
จะช่วยได้มาก
Externalizable
เหมาะกับฉันดีกว่ามากเพราะฉันไม่ต้องการที่จะเอาท์พุทอาร์เรย์ด้วยช่องว่างหรือวัตถุตัวยึดรวมทั้งอินเทอร์เฟซที่ชัดเจนที่คุณสามารถจัดการมรดกได้ -class writeExternal()
สามารถเพิ่มล็อครอบการเรียกร้องให้ แน่นอนว่า Externalizable ยังมีความเกี่ยวข้องอย่างมากแน่นอนสำหรับวัตถุขนาดใหญ่หรือซับซ้อน
การทำให้เป็นอันดับให้การทำงานเริ่มต้นในการจัดเก็บและสร้างวัตถุในภายหลัง มันใช้รูปแบบ verbose เพื่อกำหนดกราฟทั้งหมดของวัตถุที่จะเก็บไว้เช่นสมมติว่าคุณมี linkedList และคุณโค้ดด้านล่างจากนั้นอนุกรมเริ่มต้นจะค้นพบวัตถุทั้งหมดที่มีการเชื่อมโยงและจะเป็นอันดับ ในการเริ่มต้นการทำให้เป็นอันดับวัตถุจะถูกสร้างขึ้นทั้งหมดจากบิตที่เก็บไว้โดยไม่มีการเรียกตัวสร้าง
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
แต่ถ้าคุณต้องการทำให้เป็นอันดับ จำกัด หรือไม่ต้องการให้บางส่วนของวัตถุของคุณเป็นอนุกรมแล้วใช้ Externalizable อินเตอร์เฟส Externalizable ขยายอินเตอร์เฟส Serializable และเพิ่มสองวิธีคือ writeExternal () และ readExternal () สิ่งเหล่านี้ถูกเรียกโดยอัตโนมัติในขณะที่การทำให้เป็นอนุกรมหรือดีซีเรียลไลเซชัน ในขณะที่ทำงานกับ Externalizable เราควรจำไว้ว่าตัวสร้างค่าเริ่มต้นควรเป็นแบบสาธารณะรหัสนั้นจะมีข้อยกเว้น โปรดปฏิบัติตามรหัสด้านล่าง:
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
ที่นี่ถ้าคุณแสดงความคิดเห็นผู้สร้างเริ่มต้นแล้วรหัสจะโยนด้านล่างยกเว้น:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
เราสามารถสังเกตได้ว่าเนื่องจากรหัสผ่านเป็นข้อมูลที่ละเอียดอ่อนดังนั้นฉันจึงไม่เป็นอนุกรมในวิธีการ writeExternal (ObjectOutput oo) และไม่ได้ตั้งค่าเหมือนกันใน readExternal (ObjectInput oi) นั่นเป็นความยืดหยุ่นที่จัดทำโดย Externalizable
ผลลัพธ์ของรหัสข้างต้นเป็นดังต่อไปนี้:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
เราสามารถสังเกตได้เนื่องจากเราไม่ได้ตั้งค่าของรหัสผ่านดังนั้นมันจึงเป็นโมฆะ
สามารถทำได้เช่นเดียวกันโดยการประกาศฟิลด์รหัสผ่านเป็นชั่วคราว
private transient String passWord;
หวังว่ามันจะช่วย ฉันขอโทษถ้าฉันทำผิดพลาด ขอบคุณ
ความแตกต่างที่สำคัญระหว่างSerializable
และExternalizable
Serializable
เป็นส่วนต่อประสานเครื่องหมายโดยไม่ใช้วิธีการใด ๆ Externalizable
อินเตอร์เฟซที่มีสองวิธี: และwriteExternal()
readExternal()
Serializable
ส่วนต่อประสาน กระบวนการ Serialization ที่โปรแกรมเมอร์กำหนดจะถูกเตะเข้าสำหรับคลาสที่ใช้Externalizable
อินเตอร์เฟสExternalizable
ส่วนต่อประสาน คุณสามารถรองรับวัตถุรุ่นต่าง ๆ ของคุณ หากคุณใช้งานExternalizable
เป็นความรับผิดชอบของคุณในการทำให้super
คลาสเป็นอนุกรมSerializable
ใช้การสะท้อนเพื่อสร้างวัตถุและไม่ต้องการตัวสร้าง arg แต่Externalizable
ต้องการตัวสร้างแบบไม่มีอาร์กิวเมนต์สาธารณะอ้างถึงบล็อกโดยHitesh Garg
สำหรับรายละเอียดเพิ่มเติม
การทำให้เป็นอันดับใช้พฤติกรรมเริ่มต้นบางอย่างเพื่อจัดเก็บและสร้างวัตถุในภายหลัง คุณอาจระบุในลำดับใดหรือวิธีการจัดการการอ้างอิงและโครงสร้างข้อมูลที่ซับซ้อน แต่ในที่สุดมันก็ลงมาเพื่อใช้พฤติกรรมเริ่มต้นสำหรับแต่ละเขตข้อมูลดั้งเดิม
Externalization จะถูกใช้ในกรณีที่ไม่ค่อยเกิดขึ้นซึ่งคุณต้องการจัดเก็บและสร้างวัตถุของคุณใหม่ในวิธีที่ต่างกันโดยสิ้นเชิงและไม่ใช้กลไกการทำให้เป็นอนุกรมเริ่มต้นสำหรับเขตข้อมูล ตัวอย่างเช่นลองจินตนาการว่าคุณมีรูปแบบการเข้ารหัสและการบีบอัดที่เป็นเอกลักษณ์ของคุณเอง
การทำให้เป็นอันดับวัตถุใช้อินเทอร์เฟซแบบอนุกรมและ Externalizable วัตถุ Java จะต่อเนื่องได้เท่านั้น ถ้าคลาสหรือซูเปอร์คลาสใด ๆ ของมันใช้ส่วนต่อประสาน java.io.Serializable หรือ subinterface, java.io.Externalizable คลาสจาวาส่วนใหญ่สามารถต่ออนุกรมได้
NotSerializableException
: packageName.ClassName
«ในการเข้าร่วม Class Object ในกระบวนการทำให้เป็นอนุกรมคลาสจะต้องใช้อินเตอร์เฟสที่ปรับให้เป็นแบบอนุกรมหรือแบบถอดได้การทำให้เป็นอันดับวัตถุจะสร้างสตรีมที่มีข้อมูลเกี่ยวกับคลาส Java สำหรับวัตถุที่กำลังถูกบันทึก สำหรับออบเจ็กต์ที่ทำให้เป็นอนุกรมข้อมูลที่เพียงพอจะถูกเก็บไว้เพื่อกู้คืนออบเจ็กต์เหล่านั้นแม้ว่าจะมีเวอร์ชันที่แตกต่างกัน อินเตอร์เฟส Serializable ถูกกำหนดเพื่อระบุคลาสที่ใช้โปรโตคอล serializable:
package java.io;
public interface Serializable {};
InvalidClassException
«ในกระบวนการดีซีเรียลไลเซชันถ้าค่าคลาสlocalVersionUIDแตกต่างจากคลาสของผู้ส่งที่สอดคล้องกัน จากนั้นผลลัพธ์จะขัดแย้งกันดังนี้
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
สำหรับวัตถุที่ปรับขนาดได้จะมีการบันทึกตัวตนของคลาสของวัตถุเท่านั้นโดยคอนเทนเนอร์ ชั้นจะต้องบันทึกและกู้คืนเนื้อหา อินเตอร์เฟส Externalizable ถูกกำหนดดังนี้:
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
OptionalDataException
«เขตข้อมูลต้องอยู่ในลำดับและประเภทเดียวกันขณะที่เราเขียนออกมา หากมีชนิดไม่ตรงกันใด ๆ จากสตรีมจะมีการระบุตัวเลือก DataException
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
เขตข้อมูลอินสแตนซ์ของคลาสที่เขียน(เปิดเผย)เพื่อObjectOutput
รับอนุกรม
ตัวอย่าง«ใช้ Serializable
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
ตัวอย่าง«ใช้ Externalizable
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
ตัวอย่าง
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@ดู
ไม่ได้ให้อินเทอร์เฟซภายนอกที่ปรับแต่งได้เพื่อเพิ่มประสิทธิภาพกระบวนการทำให้เป็นอันดับ! แต่เพื่อให้วิธีการใช้การประมวลผลแบบกำหนดเองของคุณเองและเสนอการควบคุมที่สมบูรณ์สำหรับรูปแบบและเนื้อหาของสตรีมสำหรับวัตถุและประเภทซุปเปอร์!
ตัวอย่างของการดำเนินการนี้คือการใช้งานของระยะไกล AMF (รูปแบบข้อความ ActionScript) เพื่อถ่ายโอนวัตถุสคริปต์การกระทำดั้งเดิมผ่านเครือข่าย
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
เริ่มต้นการทำให้เป็นอนุกรมค่อนข้าง verbose และสมมติสถานการณ์การใช้งานที่เป็นไปได้ที่กว้างที่สุดของวัตถุที่เป็นอนุกรมและตามรูปแบบเริ่มต้น (Serializable) บันทึกย่อกระแสข้อมูลผลลัพธ์กับข้อมูลเกี่ยวกับชั้นของวัตถุที่ทำให้เป็นอันดับ
การส่งออกทำให้ผู้ผลิตวัตถุสตรีมสามารถควบคุมข้อมูลเมตาของคลาสที่แม่นยำ (ถ้ามี) นอกเหนือจากการระบุคลาสที่น้อยที่สุด (เช่นชื่อของมัน) สิ่งนี้เป็นที่ต้องการอย่างชัดเจนในบางสถานการณ์เช่นสภาพแวดล้อมที่ปิดซึ่งผู้ผลิตกระแสข้อมูลวัตถุและผู้บริโภค (ซึ่ง reifies วัตถุจากกระแส) จะถูกจับคู่และข้อมูลเมตาเพิ่มเติมเกี่ยวกับชั้นเรียนไม่ได้มีวัตถุประสงค์และลดประสิทธิภาพ
นอกจากนี้การส่งออก (ตามที่ระบุ Uri) ยังมีการควบคุมการเข้ารหัสข้อมูลในสตรีมที่สอดคล้องกับประเภท Java อย่างสมบูรณ์ สำหรับตัวอย่าง (ที่วางแผนไว้) คุณอาจต้องการบันทึกบูลีนจริงเช่น 'Y' และเท็จเป็น 'N' Externalization ช่วยให้คุณทำเช่นนั้นได้
เมื่อพิจารณาตัวเลือกสำหรับการปรับปรุงประสิทธิภาพอย่าลืมการทำให้เป็นอันดับแบบกำหนดเอง คุณสามารถให้ Java ทำสิ่งที่มันไม่ดีหรือที่ดีพออย่างน้อยฟรีและให้การสนับสนุนที่กำหนดเองสำหรับสิ่งที่มันไม่แย่ ซึ่งมักจะเป็นรหัสน้อยกว่าการสนับสนุน Externalizable เต็มรูปแบบ
มีความแตกต่างมากมายระหว่าง Serializable และ Externalable แต่เมื่อเราเปรียบเทียบความแตกต่างระหว่าง Customizable (แทนที่ writeObject () & readObject ()) และ Externalizable จากนั้นเราพบว่าการใช้งานที่กำหนดเองถูกผูกไว้อย่างแน่นหนากับคลาส ObjectOutputStream จัดเตรียมการประยุกต์ใช้ ObjectOutput ซึ่งอาจเป็นคลาส ObjectOutputStream หรืออาจเป็นอย่างอื่นเช่น org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
ในกรณีที่อินเตอร์เฟสภายนอก
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
ฉันได้เพิ่มโค้ดตัวอย่างเพื่ออธิบายให้ดีขึ้น โปรดตรวจสอบกรณีวัตถุเข้า / ออกของ Externalable สิ่งเหล่านี้ไม่ได้ผูกพันกับการนำไปใช้โดยตรง
โดยที่ Outstream / Instream ผูกเข้ากับคลาสอย่างแน่นหนา เราสามารถขยาย ObjectOutputStream / ObjectInputStream แต่มันจะยากที่จะใช้
โดยพื้นฐานแล้วSerializable
อินเตอร์เฟสของตัวทำเครื่องหมายที่บอกเป็นนัยว่าคลาสนั้นปลอดภัยสำหรับการทำให้เป็นอนุกรมและ JVM กำหนดวิธีที่จะทำให้เป็นอนุกรม Externalizable
มี 2 วิธีการและreadExternal
อนุญาตให้ผู้ใช้ทำการตัดสินใจว่าวัตถุนั้นถูกทำให้เป็นอนุกรมอย่างไร, ในฐานะที่วัตถุเป็นอนุกรมวิธีที่เป็นค่าเริ่มต้นwriteExternal
Externalizable
Serializable
ความแตกต่างบางประการ:
สำหรับการทำให้เป็นอนุกรมไม่จำเป็นต้องมีคอนสตรัคเตอร์เริ่มต้นของคลาสนั้นเนื่องจาก Object เนื่องจาก JVM สร้างสิ่งเดียวกันด้วยความช่วยเหลือของ Reflection API ในกรณีที่มีสิ่งก่อสร้างภายนอกที่ไม่ต้องการอาร์คเนื่องจากตัวควบคุมอยู่ในมือของโปรแกรมและหลังจากนั้นกำหนดข้อมูลที่ดีซีเรียลไลซ์ให้กับวัตถุผ่านตัวตั้งค่า
ในการทำให้เป็นอนุกรมหากผู้ใช้ต้องการข้ามคุณสมบัติบางอย่างที่จะทำให้เป็นอนุกรมนั้นจะต้องทำเครื่องหมายคุณสมบัตินั้นว่าเป็นแบบชั่วคราวไม่จำเป็นต้องใช้ในทางกลับกัน
เมื่อคาดว่าจะรองรับการรองรับความเข้ากันได้แบบย้อนหลังสำหรับคลาสใดก็ตามแนะนำให้ใช้กับ Externalizable การทำให้เป็นอนุกรมรองรับ defaultObject persisting และถ้าโครงสร้างของวัตถุแตกแล้วมันจะทำให้เกิดปัญหาขณะ deserializing