Java 为什么类需要实现可序列化的标记接口进行序列化?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20018283/
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
Why class need to implement serializable marker interface for serialization?
提问by M Sach
Techincally i know why class need to implement serializable . Reason is writeObject method of ObjectOutputStream internally checks the "instance of serializable" before writing the state of object.
从技术上讲,我知道为什么类需要实现可序列化。原因是 ObjectOutputStream 的 writeObject 方法在写入对象的状态之前在内部检查“可序列化的实例”。
But my question is what is the need of that? writeObject method can simply write the object state whether object (whose state needs to be written ) implements serializable or not?
但我的问题是,这有什么必要?writeObject 方法可以简单的写对象状态,不管对象(需要写其状态)是否实现可序列化?
As per wiki,a class implements this interface to indicate that its non-transient data members can be written to an ObjectOutputStream. But again question is why class needs to implement serializable just to determine whether field is transient or not. Even a class that does not implement serialiable should be serialized (except the fields marked as transient).
根据wiki,一个类实现了这个接口,以表明它的非瞬态数据成员可以写入 ObjectOutputStream。但同样的问题是为什么类需要实现可序列化来确定字段是否是瞬态的。即使一个没有实现可序列化的类也应该被序列化(标记为瞬态的字段除外)。
Marking an object as serializable (with an interface) doesn't magically make that object serializable, it was serializable all along, it's just that now you expressed something that the system could have found on his own, so I see no real good reason for serialization being the way it is now.
将对象标记为可序列化(带有接口)并不会神奇地使该对象可序列化,它一直是可序列化的,只是现在您表达了系统可以自己找到的东西,所以我看不出有什么好的理由序列化就是现在的样子。
Why class need to implement serializable marker interface to serialize the class?
为什么类需要实现可序列化标记接口来序列化类?
采纳答案by ljgw
By providing the marker interface, people can choose whether to make a class Serializable
. Sometimes, you might not want this! (and certainly, it would not be good to make this the default: See for example the answers to this question: Why Java needs Serializable interface?)
通过提供标记接口,人们可以选择是否创建一个类Serializable
。有时,您可能不想要这个!(当然,将其设为默认值是不好的:例如参见这个问题的答案:为什么 Java 需要 Serializable 接口?)
回答by Edwin Dalorzo
With encapsulation we pretend that nothing is revealed about the internal representation of an object, and we interact with our components only through their public interfaces; a desirable attribute that we usually exploit later when we want to change the internal representation of data in a component without breaking any code from its users.
通过封装,我们假装没有透露对象的内部表示,并且我们仅通过它们的公共接口与我们的组件交互;当我们想要更改组件中数据的内部表示而不破坏其用户的任何代码时,我们通常会利用它。
Conversely, serialization implies exposing the internal state of an object by transforming the object's state into some other format that can be stored and resurrected later. This means that, once serialized, the internal structure of an object cannot be changed without risking the success of this resurrection process.
相反,序列化意味着通过将对象的状态转换为可以在以后存储和恢复的其他格式来公开对象的内部状态。这意味着,一旦序列化,对象的内部结构就无法在不冒此复活过程成功的风险的情况下进行更改。
The problems with serialization could appear not only in the cases of open systems but also in distributed systems that somehow rely on it. For example, if we stop our application server, it may choose to serialize the objects in the current session to resurrect them later, when the server is restarted, but if we redeploy our application using new versions of our serializable objects, will they still be compatible when the server attempts to resurrect them? In a distributed system is common to use code mobility,namely, sets of classes are located in a central repository available for clients and server to share common code. In this approach, since objects are serialized to be shared between clients and servers, do we run the risk of breaking anything if we update the serializable classes in this common repository?
序列化的问题不仅会出现在开放系统的情况下,还会出现在以某种方式依赖它的分布式系统中。例如,如果我们停止我们的应用程序服务器,它可能会选择序列化当前会话中的对象以在稍后重新启动服务器时将它们复活,但是如果我们使用新版本的可序列化对象重新部署我们的应用程序,它们仍然会被当服务器尝试复活它们时兼容吗?在分布式系统中普遍使用代码移动性,即,类集位于中央存储库中,可供客户端和服务器共享公共代码。在这种方法中,由于对象被序列化以在客户端和服务器之间共享,如果我们更新这个公共存储库中的可序列化类,我们是否会冒着破坏任何东西的风险?
Consider for example that we had a class Person as follows:
例如,考虑我们有一个 Person 类,如下所示:
public class Person {
private String firstName;
private String lastName;
private boolean isMale;
private int age;
public boolean isMale() {
return this.isMale;
}
public int getAge() {
return this.age;
}
//more getters and setters
}
Let's say that we released our first version of our API with this abstraction of a Person. For the second version, though, we would like to introduce two changes: first, we discovered that it would be better if we could store the date of birth of a person, instead of the age as an integer, and second our definition of the class Person may have occurred when Java did not have enumerations but now we would like to use them to represent the gender of a person.
假设我们发布了我们的 API 的第一个版本,其中包含 Person 的这种抽象。不过,对于第二个版本,我们想引入两个变化:首先,我们发现如果我们可以存储一个人的出生日期而不是将年龄存储为整数会更好,其次我们对类 Person 可能在 Java 没有枚举时出现,但现在我们想用它们来表示一个人的性别。
Evidently, since the fields are properly encapsulated, we could change the inner workings of the class without affecting the public interface. Somewhat like this:
显然,由于字段被正确封装,我们可以在不影响公共接口的情况下更改类的内部工作方式。有点像这样:
public class Person {
private String firstName;
private String lastName;
private Gender gender;
private Date dateOfBirth;
public boolean isMale() {
return this.gender == Gender.MALE;
}
public int getAge() {
Calendar today = Calendar.getInstance();
Calendar birth = Calendar.getInstance();
birth.setTime(this.dateOfBirth);
return today.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
}
//the rest of getters and setters
}
By doing these changes as shown above we can make sure preexisting clients will not break, because even when we changed the internal representation of the state of the object, we kept the public interface unchanged.
通过如上所示进行这些更改,我们可以确保预先存在的客户端不会中断,因为即使我们更改了对象状态的内部表示,我们也保持公共接口不变。
However, consider that the class Person was serializable by default, and if our system is an open system, there could be thousands of lines of code out there relying on the fact that they will be capable of resurrecting serialized objects based on the original class, or maybe even clients who serialized extended classes based on the original version of the class as their parent. Some of these objects may have been serialized to binary form, or some other format, by the users of our API, who now, would like to to evolve to our second version of the code.
然而,考虑到 Person 类在默认情况下是可序列化的,如果我们的系统是一个开放系统,那么可能会有数千行代码依赖于它们能够基于原始类复活序列化对象的事实,或者甚至可能是基于类的原始版本序列化扩展类作为其父类的客户。其中一些对象可能已被我们 API 的用户序列化为二进制形式或某种其他格式,他们现在想要发展到我们的第二版代码。
Then if we wanted to do some changes as we did in our second example, we would immediately break some of them; all those having serialized objects based on the original version of the class who have stored objects containing a field called age of type int, containing the age of a person, and field named isMale of type boolean containing information about the gender are likely to fail during the deserialization of these objects because the new class definition uses new fields and new data types.
然后,如果我们想像在第二个示例中那样做一些更改,我们会立即破坏其中的一些;所有具有基于类的原始版本序列化对象的人,这些对象存储的对象包含一个称为 int 类型的字段的年龄,包含一个人的年龄,以及名为 isMale 的包含性别信息的布尔类型的字段,在此期间可能会失败这些对象的反序列化,因为新的类定义使用了新的字段和新的数据类型。
Clearly our problem here is that the serialization has exposed sensitive information about our objects, and now we cannot simply change anything, not even what we thought that was encapsulated because through serialization, everything has been exposed publicly.
很明显,我们这里的问题是序列化暴露了关于我们对象的敏感信息,现在我们不能简单地改变任何东西,甚至不能改变我们认为封装的东西,因为通过序列化,一切都被公开了。
Now, consider a scenario in which every single class in the JDK API were serializable by default. The designers of Java simply could not evolve the APIs of Java without risking to break many applications. They would be forced to assume that somebody out there may have a serialized version of any of the classes in the JDK.
现在,考虑一个场景,其中默认情况下 JDK API 中的每个类都是可序列化的。Java 的设计者无法在不冒破坏许多应用程序的风险的情况下发展 Java 的 API。他们将被迫假设有人可能拥有 JDK 中任何类的序列化版本。
There are ways to deal with the evolution of serializable classes, but the important point here is that, when it comes to encapsulation, we would like to keep our serializable classes as contained as possible and for those classes that we indeed need to serialize, then we may need to ponder about the implications of any possible scenario in which we may attempt to resurrect an object using an evolved version of its class.
有一些方法可以处理可序列化类的演变,但这里的重点是,当涉及到封装时,我们希望尽可能包含我们的可序列化类,并且对于那些确实需要序列化的类,那么我们可能需要考虑任何可能的场景的含义,在这些场景中,我们可能会尝试使用其类的进化版本来复活一个对象。
Despite all of this, serialization has security implications as well, as important, sensitive information about our objects could be easily exposed.
尽管如此,序列化也有安全隐患,因为有关我们对象的重要敏感信息很容易暴露。
Therefore, having the classes that are serializable marked, kind of makes it easier for the designers of APIs to deal with them.
因此,标记可序列化的类,使 API 的设计者更容易处理它们。
回答by jdev
Serializable is called marker interface like Cloneable. When you use some marker interface(no method implementation ) you want to tell jvm or compiler for adding or checking something during runtime or compile time.
Serializable 和 Cloneable 一样被称为标记接口。当您使用某些标记接口(无方法实现)时,您希望告诉 jvm 或编译器在运行时或编译时添加或检查某些内容。
Marker interface definition:
标记接口定义:
“An interface is called a marker interface when it is provided as a handle by java interpreter to mark a class so that it can provide special behaviour to it at runtime and they do not have any method declarations”.
“当一个接口被 Java 解释器作为句柄提供来标记一个类,以便它可以在运行时为其提供特殊行为并且它们没有任何方法声明时,它被称为标记接口”。
Also marker interface is a good way to classify code. You can create marker interface to logically divide your code and if you have your own tool than you can perform some pre-processing operation on those classes. Particularly useful for developing API and framework like Spring or Struts.
标记界面也是对代码进行分类的好方法。您可以创建标记接口来逻辑划分代码,如果您有自己的工具,则可以对这些类执行一些预处理操作。对于开发 API 和框架(如 Spring 或 Struts)特别有用。
Marker interface can also help code coverage or code review tool to find bugs based on specified behavior of marker interfaces.
标记接口还可以帮助代码覆盖率或代码工具根据标记接口的指定行为来查找错误。
see marker interface in wikihttp://en.wikipedia.org/wiki/Marker_Interface_pattern
在 wiki http://en.wikipedia.org/wiki/Marker_Interface_pattern 中查看标记界面