Sự khác biệt giữa Serializable
và Externalizable
trong Java là gì?
Sự khác biệt giữa Serializable
và Externalizable
trong Java là gì?
Câu trả lời:
Để thêm vào các câu trả lời khác, bằng cách thực hiện java.io.Serializable
, bạn có được khả năng tuần tự hóa "tự động" cho các đối tượng của lớp. Không cần phải thực hiện bất kỳ logic nào khác, nó sẽ chỉ hoạt động. Thời gian chạy Java sẽ sử dụng sự phản chiếu để tìm ra cách sắp xếp và sắp xếp các đối tượng của bạn.
Trong phiên bản trước của Java, sự phản chiếu rất chậm và do đó việc sắp xếp các đồ thị đối tượng lớn (ví dụ trong các ứng dụng RMI của máy khách-máy chủ) là một vấn đề về hiệu năng. Để xử lý tình huống này, java.io.Externalizable
giao diện đã được cung cấp, giống như java.io.Serializable
nhưng với các cơ chế được viết tùy chỉnh để thực hiện các chức năng sắp xếp theo thứ tự và không sắp xếp (bạn cần thực hiện readExternal
vàwriteExternal
phương thức trên lớp của mình). Điều này cung cấp cho bạn các phương tiện để khắc phục nút thắt hiệu suất phản chiếu.
Trong các phiên bản gần đây của Java (1.3 trở đi, chắc chắn), hiệu suất phản chiếu tốt hơn rất nhiều so với trước đây và do đó, đây không phải là vấn đề. Tôi nghi ngờ bạn sẽ khó có được lợi ích có ý nghĩa từExternalizable
với một JVM hiện đại.
Ngoài ra, cơ chế tuần tự hóa Java tích hợp không phải là duy nhất, bạn có thể nhận được các thay thế của bên thứ ba, chẳng hạn như Tuần tự hóa JBoss, nhanh hơn đáng kể và là sự thay thế thả xuống cho mặc định.
Một nhược điểm lớn Externalizable
là bạn phải tự duy trì logic này - nếu bạn thêm, xóa hoặc thay đổi một trường trong lớp, bạn phải thay đổi writeExternal
/ readExternal
phương thức của mình để tính đến nó.
Tóm lại, Externalizable
là một di tích của Java 1.1 ngày. Thực sự không cần nó nữa.
Externalizable
sẽ giúp ích rất nhiều .
Externalizable
phù hợp với tôi hơn nhiều, vì tôi không muốn xuất mảng với các khoảng trống hoặc đối tượng giữ chỗ, cộng với giao diện rõ ràng bạn có thể xử lý kế thừa, có nghĩa là phụ được đồng bộ hóa của tôi -Lớp có thể dễ dàng thêm khóa xung quanh cuộc gọi đến writeExternal()
. Vì vậy, yeah, Internalizable vẫn còn rất nhiều liên quan, chắc chắn cho các đối tượng lớn hoặc phức tạp.
Tuần tự hóa cung cấp chức năng mặc định để lưu trữ và sau đó tạo lại đối tượng. Nó sử dụng định dạng dài dòng để xác định toàn bộ biểu đồ của các đối tượng sẽ được lưu trữ, giả sử bạn có một ListList được liên kết và mã của bạn như bên dưới, sau đó tuần tự hóa mặc định sẽ khám phá tất cả các đối tượng được liên kết và sẽ tuần tự hóa. Trong tuần tự hóa mặc định, đối tượng được xây dựng hoàn toàn từ các bit được lưu trữ của nó, không có lệnh gọi hàm tạo.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
Nhưng nếu bạn muốn tuần tự hóa bị hạn chế hoặc không muốn một số phần của đối tượng của bạn được tuần tự hóa thì hãy sử dụng Internalizable. Giao diện bên ngoài mở rộng giao diện Nối tiếp và thêm hai phương thức, writeExternal () và readExternal (). Chúng được tự động gọi trong khi tuần tự hóa hoặc giải tuần tự hóa. Trong khi làm việc với Internalizable, chúng ta nên nhớ rằng trình xây dựng mặc định phải được công khai nếu không thì mã sẽ ném ngoại lệ. Vui lòng làm theo mã dưới đây:
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);
}
}
}
Ở đây nếu bạn nhận xét trình xây dựng mặc định thì mã sẽ ném ngoại lệ bên dưới:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Chúng ta có thể quan sát rằng mật khẩu là thông tin nhạy cảm, vì vậy tôi không tuần tự hóa nó trong phương thức writeExternal (ObjectOutput oo) và không đặt giá trị giống nhau trong readExternal (ObjectInput oi). Đó là sự linh hoạt được cung cấp bởi Bên ngoài.
Đầu ra của mã trên là như dưới đây:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Chúng ta có thể quan sát vì chúng ta không đặt giá trị của passWord nên nó không có giá trị.
Điều tương tự cũng có thể đạt được bằng cách khai báo trường mật khẩu là tạm thời.
private transient String passWord;
Hy vọng nó giúp. Tôi xin lỗi nếu tôi có bất kỳ sai lầm. Cảm ơn.
Sự khác biệt chính giữa Serializable
vàExternalizable
Serializable
đánh dấu : là giao diện đánh dấu mà không có bất kỳ phương pháp. Externalizable
giao diện chứa hai phương thức: writeExternal()
và readExternal()
.Serializable
giao diện. Lập trình viên xác định quá trình tuần tự hóa sẽ được khởi động cho các lớp thực hiện Externalizable
giao diện.Externalizable
giao diện. Bạn có thể hỗ trợ các phiên bản khác nhau của đối tượng của bạn. Nếu bạn thực hiệnExternalizable
, bạn có trách nhiệm nối tiếp super
lớpSerializable
sử dụng sự phản chiếu để xây dựng đối tượng và không yêu cầu không có công cụ xây dựng arg. Nhưng Externalizable
đòi hỏi nhà xây dựng no-arg công khai.Tham khảo blog bằng cách Hitesh Garg
biết thêm chi tiết.
Tuần tự hóa sử dụng các hành vi mặc định nhất định để lưu trữ và sau đó tạo lại đối tượng. Bạn có thể chỉ định theo thứ tự hoặc cách xử lý các tham chiếu và cấu trúc dữ liệu phức tạp, nhưng cuối cùng, nó sử dụng hành vi mặc định cho từng trường dữ liệu nguyên thủy.
Bên ngoài được sử dụng trong các trường hợp hiếm hoi mà bạn thực sự muốn lưu trữ và xây dựng lại đối tượng của mình theo một cách hoàn toàn khác và không sử dụng các cơ chế tuần tự hóa mặc định cho các trường dữ liệu. Ví dụ, hãy tưởng tượng rằng bạn có sơ đồ nén và mã hóa độc đáo của riêng bạn.
Object serialization sử dụng các giao diện serializable và Externalizable. Một đối tượng Java chỉ được tuần tự hóa. nếu một lớp hoặc bất kỳ siêu lớp nào của nó thực hiện giao diện java.io.Serializable hoặc giao diện con của nó, java.io.Externalizable. Hầu hết các lớp java là tuần tự hóa .
NotSerializableException
: packageName.ClassName
«Để tham gia Đối tượng lớp trong quá trình tuần tự hóa, Lớp phải triển khai giao diện Nối tiếp hoặc Giao diện ngoài.Đối tượng tuần tự hóa tạo ra một luồng với thông tin về các lớp Java cho các đối tượng đang được lưu. Đối với các đối tượng tuần tự hóa, thông tin đầy đủ được lưu giữ để khôi phục các đối tượng đó ngay cả khi có phiên bản khác (nhưng tương thích) của việc triển khai lớp. Giao diện serializable được định nghĩa để xác định các lớp thực hiện giao thức tuần tự hóa:
package java.io;
public interface Serializable {};
InvalidClassException
«Trong quá trình khử lưu huỳnh , nếu giá trị serialVersionUID của lớp cục bộ khác với lớp người gửi tương ứng. sau đó dẫn đến xung đột như
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Đối với các đối tượng bên ngoài, chỉ có danh tính của lớp của đối tượng được lưu bởi container; lớp phải lưu và khôi phục nội dung. Giao diện bên ngoài được định nghĩa như sau:
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
«Các trường PHẢI ĐƯỢC ĐẶT HÀNG VÀ LOẠI CÙNG khi chúng tôi viết chúng ra. Nếu có bất kỳ loại không khớp nào từ luồng, nó sẽ ném OptionsDataException.
@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();
}
Các trường đối tượng của lớp được viết (tiếp xúc) để ObjectOutput
được tuần tự hóa.
Ví dụ « thực hiện nối tiếp
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;
}
Ví dụ « thực hiện Bên ngoài
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();
}
}
Thí dụ
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();
}
}
}
@xem
Giao diện bên ngoài không thực sự được cung cấp để tối ưu hóa hiệu suất quá trình tuần tự hóa! nhưng để cung cấp phương tiện thực hiện xử lý tùy chỉnh của riêng bạn và cung cấp quyền kiểm soát hoàn toàn định dạng và nội dung của luồng cho một đối tượng và các loại siêu của nó!
Ví dụ về điều này là việc triển khai từ xa AMF (Định dạng thông báo ActionScript) để truyền các đối tượng tập lệnh hành động gốc qua mạng.
https://docs.oracle.com/javase/8/docs/pl platform / subsialization / spec / sialialTOC.html
Tuần tự hóa mặc định có phần dài dòng và giả sử kịch bản sử dụng rộng nhất có thể của đối tượng được tuần tự hóa, và theo đó định dạng mặc định (Nối tiếp) chú thích luồng kết quả với thông tin về lớp của đối tượng được tuần tự hóa.
Việc bên ngoài cung cấp cho nhà sản xuất luồng đối tượng toàn quyền kiểm soát dữ liệu meta lớp chính xác (nếu có) ngoài việc xác định yêu cầu tối thiểu của lớp (ví dụ như tên của nó). Điều này rõ ràng là mong muốn trong một số trường hợp, chẳng hạn như môi trường kín, nơi người sản xuất luồng đối tượng và người tiêu dùng của nó (điều chỉnh lại đối tượng từ luồng) được khớp và siêu dữ liệu bổ sung về lớp không phục vụ mục đích và làm giảm hiệu suất.
Ngoài ra (như Uri chỉ ra) bên ngoài cũng cung cấp khả năng kiểm soát hoàn toàn việc mã hóa dữ liệu trong luồng tương ứng với các loại Java. Đối với ví dụ (giả định), bạn có thể muốn ghi boolean đúng là 'Y' và sai là 'N'. Bên ngoài cho phép bạn làm điều đó.
Khi xem xét các tùy chọn để cải thiện hiệu suất, đừng quên tuần tự hóa tùy chỉnh. Bạn có thể để Java làm những gì nó làm tốt, hoặc ít nhất là đủ tốt, miễn phí và cung cấp hỗ trợ tùy chỉnh cho những gì nó làm không tốt. Đây thường là mã ít hơn rất nhiều so với hỗ trợ bên ngoài đầy đủ.
Có rất nhiều sự khác biệt tồn tại giữa Nối tiếp và Có thể thay đổi nhưng khi chúng ta so sánh sự khác biệt giữa Nối tiếp tùy chỉnh (ghi đè ghi đè cung cấp một triển khai ObjectOutput có thể là lớp ObjectOutputStream hoặc nó có thể là một số khác như org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
Trong trường hợp giao diện ngoài
@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();
}
Tôi đã thêm mã mẫu để giải thích rõ hơn. vui lòng kiểm tra trường hợp đối tượng vào / ra của bên ngoài. Đây không phải là ràng buộc với bất kỳ thực hiện trực tiếp.
Trường hợp như Outflow / Instream liên kết chặt chẽ với các lớp. Chúng tôi có thể mở rộng ObjectOutputStream / ObjectInputStream nhưng sẽ hơi khó sử dụng.
Về cơ bản, Serializable
là một giao diện đánh dấu ngụ ý rằng một lớp an toàn để tuần tự hóa và JVM xác định cách nó được tuần tự hóa. Externalizable
chứa 2 phương pháp, readExternal
và writeExternal
. Externalizable
cho phép người thực hiện quyết định làm thế nào một đối tượng được tuần tự hóa, trong đó khi Serializable
tuần tự hóa các đối tượng theo cách mặc định.
Một số khác biệt:
Đối với tuần tự hóa, không cần trình xây dựng mặc định của lớp đó vì Object vì JVM xây dựng tương tự với sự trợ giúp của API Reflection. Trong trường hợp bộ điều khiển ngoại ứng không có đối số được yêu cầu, bởi vì điều khiển nằm trong tay của chương trình và sau đó gán dữ liệu được giải tuần tự hóa cho đối tượng thông qua setters.
Trong tuần tự hóa nếu người dùng muốn bỏ qua các thuộc tính nhất định sẽ được tuần tự hóa thì phải đánh dấu các thuộc tính đó là nhất thời, ngược lại là không bắt buộc đối với Bên ngoài.
Khi hỗ trợ tương thích ngược được mong đợi cho bất kỳ lớp nào thì nên đi với Internalizable. Tuần tự hóa hỗ trợ defaultObject vẫn tồn tại và nếu cấu trúc đối tượng bị phá vỡ thì nó sẽ gây ra vấn đề trong khi giải tuần tự hóa.