Java中的Serializable和Externalizable有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/817853/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between Serializable and Externalizable in Java?
提问by
What is the difference between Serializable
and Externalizable
in Java?
JavaSerializable
和Externalizable
Java 中的区别是什么?
回答by Uri
Serialization uses certain default behaviors to store and later recreate the object. You may specify in what order or how to handle references and complex data structures, but eventually it comes down to using the default behavior for each primitive data field.
序列化使用某些默认行为来存储和稍后重新创建对象。您可以指定处理引用和复杂数据结构的顺序或方式,但最终归结为对每个原始数据字段使用默认行为。
Externalization is used in the rare cases that you really want to store and rebuild your object in a completely different way and without using the default serialization mechanisms for data fields. For example, imagine that you had your own unique encoding and compression scheme.
在极少数情况下使用外部化,您确实希望以完全不同的方式存储和重建对象,并且不使用数据字段的默认序列化机制。例如,假设您有自己独特的编码和压缩方案。
回答by alphazero
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
Default serialization is somewhat verbose, and assumes the widest possible usage scenario of the serialized object, and accordingly the default format (Serializable) annotates the resultant stream with information about the class of the serialized object.
默认序列化有点冗长,并假设序列化对象的可能使用场景最广泛,因此默认格式 (Serializable) 使用有关序列化对象的类的信息来注释结果流。
Externalization give the producer of the object stream complete control over the precise class meta-data (if any) beyond the minimal required identification of the class (e.g. its name). This is clearly desirable in certain situations, such as closed environments, where producer of the object stream and its consumer (which reifies the object from the stream) are matched, and additional metadata about the class serves no purpose and degrades performance.
外部化使对象流的生产者能够完全控制精确的类元数据(如果有的话),超出类的最低要求标识(例如,它的名称)。这在某些情况下显然是可取的,例如封闭环境,其中对象流的生产者和它的消费者(从流中具体化对象)是匹配的,并且关于该类的附加元数据没有用处并且会降低性能。
Additionally (as Uri point out) externalization also provides for complete control over the encoding of the data in the stream corresponding to Java types. For (a contrived) example, you may wish to record boolean true as 'Y' and false as 'N'. Externalization allows you to do that.
此外(如 Uri 所指出的)外部化还提供了对与 Java 类型相对应的流中数据编码的完全控制。对于(人为的)示例,您可能希望将布尔值 true 记录为“Y”,将 false 记录为“N”。外化允许你这样做。
回答by skaffman
To add to the other answers, by implementating java.io.Serializable
, you get "automatic" serialization capability for objects of your class. No need to implement any other logic, it'll just work. The Java runtime will use reflection to figure out how to marshal and unmarshal your objects.
要添加到其他答案中,通过实现java.io.Serializable
,您可以获得类对象的“自动”序列化功能。无需实现任何其他逻辑,它就可以工作。Java 运行时将使用反射来确定如何编组和解组您的对象。
In earlier version of Java, reflection was very slow, and so serializaing large object graphs (e.g. in client-server RMI applications) was a bit of a performance problem. To handle this situation, the java.io.Externalizable
interface was provided, which is like java.io.Serializable
but with custom-written mechanisms to perform the marshalling and unmarshalling functions (you need to implement readExternal
and writeExternal
methods on your class). This gives you the means to get around the reflection performance bottleneck.
在 Java 的早期版本中,反射非常慢,因此序列化大对象图(例如在客户端-服务器 RMI 应用程序中)是一个性能问题。为了处理这种情况,java.io.Externalizable
提供了接口,这类似于java.io.Serializable
但具有自定义编写的机制来执行编组和解组功能(您需要在您的类上实现readExternal
和writeExternal
方法)。这为您提供了绕过反射性能瓶颈的方法。
In recent versions of Java (1.3 onwards, certainly) the performance of reflection is vastly better than it used to be, and so this is much less of a problem. I suspect you'd be hard-pressed to get a meaningful benefit from Externalizable
with a modern JVM.
在 Java 的最新版本(当然是 1.3 以后)中,反射的性能比以前好得多,因此这不是什么问题。我怀疑您很难从Externalizable
现代 JVM 中获得有意义的好处。
Also, the built-in Java serialization mechanism isn't the only one, you can get third-party replacements, such as JBoss Serialization, which is considerably quicker, and is a drop-in replacement for the default.
此外,内置的 Java 序列化机制不是唯一的,您可以获得第三方替代品,例如 JBoss Serialization,它相当快,并且是默认的替代品。
A big downside of Externalizable
is that you have to maintain this logic yourself - if you add, remove or change a field in your class, you have to change your writeExternal
/readExternal
methods to account for it.
一个很大的缺点Externalizable
是你必须自己维护这个逻辑——如果你在你的类中添加、删除或更改一个字段,你必须更改你的writeExternal
/readExternal
方法来解决它。
In summary, Externalizable
is a relic of the Java 1.1 days. There's really no need for it any more.
综上所述,Externalizable
是Java 1.1时代的遗物。真的没有必要了。
回答by Benjamin Wootton
Just for completeness, the transient
keyword also closes the gap between the two.
只是为了完整性,transient
关键字还缩小了两者之间的差距。
If you only want to serialize part of your object, just set specific fields as transient
, marking them as not to be persisted, and implement Serializable
.
如果您只想序列化对象的一部分,只需将特定字段设置为transient
,将它们标记为不持久化,然后实现Serializable
.
回答by Ed Staub
When considering options for improving performance, don't forget custom serialization. You can let Java do what it does well, or at least good enough, for free, and provide custom support for what it does badly. This is usually a lot less code than full Externalizable support.
在考虑提高性能的选项时,不要忘记自定义序列化。你可以让Java的做它好,或者至少不够好,自由,和它做什么不好提供定制的支持。这通常比完整的 Externalizable 支持少很多代码。
回答by Ali Joudeh
The Externalizable interface was not actually provided to optimize the serialization process performance! but to provide means of implementing your own custom processing and offer complete control over the format and contents of the stream for an object and its super types!
Externalizable 接口实际上并没有提供来优化序列化过程的性能!但要提供实现您自己的自定义处理的方法,并提供对对象及其超类型流的格式和内容的完全控制!
Examples of this is the implementation of AMF (ActionScript Message Format) remoting to transfer native action script objects over the network.
这方面的示例是 AMF(动作脚本消息格式)远程处理的实现,以通过网络传输本机动作脚本对象。
回答by Trying
Serialization provides default functionality to store and later recreate the object. It uses verbose format to define the whole graph of objects to be stored e.g. suppose you have a linkedList and you code like below, then the default serialization will discover all the objects which are linked and will serialize. In default serialization the object is constructed entirely from its stored bits, with no constructor calls.
序列化提供了存储和稍后重新创建对象的默认功能。它使用详细格式来定义要存储的整个对象图,例如,假设您有一个链接列表并且您的代码如下所示,那么默认序列化将发现所有链接的对象并将序列化。在默认序列化中,对象完全由其存储的位构成,没有构造函数调用。
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
But if you want restricted serialization or don't want some portion of your object to be serialized then use Externalizable. The Externalizable interface extends the Serializable interface and adds two methods, writeExternal() and readExternal(). These are automatically called while serialization or deserialization. While working with Externalizable we should remember that the default constructer should be public else the code will throw exception. Please follow the below code:
但是,如果您想要限制序列化或不想序列化对象的某些部分,请使用 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);
}
}
}
Here if you comment the default constructer then the code will throw below exception:
在这里,如果您注释默认构造函数,则代码将抛出以下异常:
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
We can observe that as password is sensitive information, so i am not serializing it in writeExternal(ObjectOutput oo) method and not setting the value of same in readExternal(ObjectInput oi). That's the flexibility that is provided by Externalizable.
我们可以观察到,由于密码是敏感信息,所以我没有在 writeExternal(ObjectOutput oo) 方法中序列化它,也没有在 readExternal(ObjectInput oi) 中设置相同的值。这就是 Externalizable 提供的灵活性。
The output of the above code is as per below:
上述代码的输出如下:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
We can observe as we are not setting the value of passWord so it's null.
我们可以观察到,因为我们没有设置 passWord 的值,所以它为空。
The same can also be achieved by declaring the password field as transient.
也可以通过将密码字段声明为临时字段来实现相同的目的。
private transient String passWord;
Hope it helps. I apologize if i made any mistakes. Thanks.
希望能帮助到你。如果我犯了任何错误,我深表歉意。谢谢。
回答by Ravindra babu
Key differences between Serializable
and Externalizable
Serializable
和之间的主要区别Externalizable
- Marker interface:
Serializable
is marker interface without any methods.Externalizable
interface contains two methods:writeExternal()
andreadExternal()
. - Serialization process: Default Serialization process will be kicked-in for classes implementing
Serializable
interface. Programmer defined Serialization process will be kicked-in for classes implementingExternalizable
interface. - Maintenance: Incompatible changesmay break serialisation.
- Backward Compatibility and Control: If you have to support multiple versions, you can have full control with
Externalizable
interface. You can support different versions of your object. If you implementExternalizable
, it's your responsibility to serializesuper
class - public No-arg constructor:
Serializable
uses reflection to construct object and does not require no arg constructor. ButExternalizable
demands public no-arg constructor.
- 标记接口:
Serializable
是没有任何方法的标记接口。Externalizable
接口包含两个方法:writeExternal()
和readExternal()
。 - 序列化过程:对于实现
Serializable
接口的类,将启动默认序列化过程。程序员定义的序列化过程将被用于实现Externalizable
接口的类。 - 维护:不兼容的更改可能会破坏序列化。
- 向后兼容性和控制:如果您必须支持多个版本,则可以完全控制
Externalizable
界面。您可以支持不同版本的对象。如果您实现Externalizable
,则您有责任序列化super
类 - public No-arg constructor:
Serializable
使用反射来构造对象,不需要没有arg构造函数。但Externalizable
需要公共无参数构造函数。
Refer to blogby Hitesh Garg
for more details.
请参阅博客通过Hitesh Garg
更多的细节。
回答by Ashish Sharma
There are so many difference exist between Serializable and Externalizable but when we compare difference between custom Serializable(overrided writeObject() & readObject()) and Externalizable then we find that custom implementation is tightly bind with ObjectOutputStream class where as in Externalizable case , we ourself provide an implementation of ObjectOutput which may be ObjectOutputStream class or it could be some other like org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
Serializable 和 Externalizable 之间存在很多差异,但是当我们比较自定义 Serializable(重写 writeObject() & readObject())和 Externalizable 之间的差异时,我们发现自定义实现与 ObjectOutputStream 类紧密绑定,而在 Externalizable 情况下,我们自己提供 ObjectOutput 的实现,它可能是 ObjectOutputStream 类,也可能是其他类似 org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream 的实现
In case of Externalizable interface
如果是外部化接口
@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();
}
I have added sample code to explain better. please check in/out object case of Externalizable. These are not bound to any implementation directly.
Where as Outstream/Instream are tightly bind to classes. We can extends ObjectOutputStream/ObjectInputStream but it will a bit difficult to use.
我添加了示例代码以更好地解释。请签入/签出 Externalizable 的对象案例。这些不直接绑定到任何实现。
Outstream/Instream 与类紧密绑定。我们可以扩展 ObjectOutputStream/ObjectInputStream 但使用起来会有点困难。
回答by Yash
Object Serialization uses the Serializable and Externalizable interfaces.A Java object is only serializable. if a class or any of its superclasses implements either the java.io.Serializable interface or its subinterface, java.io.Externalizable. Most of the java class are serializable.
对象序列化使用 Serializable 和 Externalizable 接口。Java 对象只能序列化。如果一个类或其任何超类实现了 java.io.Serializable 接口或其子接口 java.io.Externalizable。大多数 java 类都是可序列化的。
NotSerializableException
:packageName.ClassName
? To participate a Class Object in serialization process, The class must implement either Serializable or Externalizable interface.
NotSerializableException
:packageName.ClassName
?要在序列化过程中参与类对象,该类必须实现 Serializable 或 Externalizable 接口。
Object Serialization produces a stream with information about the Java classes for the objects which are being saved. For serializable objects, sufficient information is kept to restore those objects even if a different (but compatible) version of the implementation of the class is present. The Serializable interface is defined to identify classes which implement the serializable protocol:
对象序列化会生成一个流,其中包含有关正在保存的对象的 Java 类的信息。对于可序列化的对象,即使存在不同(但兼容)的类实现版本,也会保留足够的信息来恢复这些对象。Serializable 接口被定义为识别实现可序列化协议的类:
package java.io;
public interface Serializable {};
- The serialization interface has no methods or fields and serves only to identify the semantics of being serializable. For serializing/deserializing a class, either we can use default writeObject and readObject methods (or) we can overriding writeObject and readObject methods from a class.
- JVM will have complete control in serializing the object. use transient keywordto prevent the data member from being serialized.
- Here serializable objects is reconstructed directly from the stream without executing
InvalidClassException
? In deserialization process, if local class serialVersionUIDvalue is different from the corresponding sender's class. then result's in conflict asjava.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
- The values of the non-transient and non-static fields of the class get serialized.
- 序列化接口没有方法或字段,仅用于标识可序列化的语义。对于序列化/反序列化类,我们可以使用默认的 writeObject 和 readObject 方法(或)我们可以覆盖类中的 writeObject 和 readObject 方法。
- JVM 将完全控制序列化对象。使用transient关键字来防止数据成员被序列化。
- 这里可序列化的对象是直接从流中重构的,无需执行
InvalidClassException
? 在反序列化过程中,如果本地类的serialVersionUID值与对应的发送者的类不同。然后导致冲突java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
- 类的非瞬态和非静态字段的值被序列化。
For Externalizable objects, only the identity of the class of the object is saved by the container; the class must save and restore the contents. The Externalizable interface is defined as follows:
对于 Externalizable 对象,容器只保存对象的类的标识;类必须保存和恢复内容。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;
}
- The Externalizable interface has two methods, an externalizable object must implement a writeExternal and readExternal methods to save/restore the state of an object.
- Programmer has to take care of which objects to be serialized. As a programmer take care of Serialization So, here transient keyword will not restrict any object in Serialization process.
- When an Externalizable object is reconstructed, an instance is created using the public no-arg constructor, then the readExternal method called. Serializable objects are restored by reading them from an ObjectInputStream.
OptionalDataException
? The fields MUST BE IN THE SAME ORDER AND TYPEas we wrote them out. If there is any mismatch of type from the stream it throws OptionalDataException.@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(); }
The instance fields of the class which written (exposed)to
ObjectOutput
get serialized.
- Externalizable 接口有两个方法,一个可外部化的对象必须实现 writeExternal 和 readExternal 方法来保存/恢复对象的状态。
- 程序员必须处理要序列化的对象。作为程序员照顾序列化所以,这里的transient关键字不会限制序列化过程中的任何对象。
- 重构 Externalizable 对象时,将使用公共无参数构造函数创建一个实例,然后调用 readExternal 方法。可序列化对象通过从 ObjectInputStream 读取它们来恢复。
OptionalDataException
? 字段的顺序和类型必须与我们写出来的相同。如果流中存在任何类型不匹配,它会抛出 OptionalDataException。@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
进行序列化的类的实例字段。
Example ?implements 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;
}
Example ?implements 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();
}
}
Example
例子
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();
}
}
}
@see
@看