Java中的类Serializable
究竟是什么意思?或者一般来说,就此而言......
答案 0 :(得分:118)
Serialization将一个对象从内存持久化到一系列位,例如用于保存到磁盘上。反序列化是相反的 - 从磁盘读取数据以水合/创建对象。
在你的问题的上下文中,它是一个接口,如果在类中实现,该类可以由不同的序列化器自动序列化和反序列化。
答案 1 :(得分:36)
虽然大多数用户已经给出了答案,但我想为那些需要它的人添加一个例子来解释这个想法:
我们假设您有一个类似以下人员的人:
public class Person implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public String firstName;
public String lastName;
public int age;
public String address;
public void play() {
System.out.println(String.format(
"If I win, send me the trophy to this address: %s", address));
}
@Override
public String toString() {
return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
}
}
然后你创建一个像这样的对象:
Person william = new Person();
william.firstName = "William";
william.lastName = "Kinaan";
william.age = 26;
william.address = "Lisbon, Portugal";
您可以将该对象序列化为多个流。我会这样做两个流:
序列化为标准输出:
public static void serializeToStandardOutput(Person person)
throws IOException {
OutputStream outStream = System.out;
ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
stdObjectOut.writeObject(person);
stdObjectOut.close();
outStream.close();
}
序列化为文件:
public static void serializeToFile(Person person) throws IOException {
OutputStream outStream = new FileOutputStream("person.ser");
ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
fileObjectOut.writeObject(person);
fileObjectOut.close();
outStream.close();
}
然后:
从文件反序列化:
public static void deserializeFromFile() throws IOException,
ClassNotFoundException {
InputStream inStream = new FileInputStream("person.ser");
ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
Person person = (Person) fileObjectIn.readObject();
System.out.println(person);
fileObjectIn.close();
inStream.close();
}
答案 2 :(得分:35)
这意味着可以将类的实例转换为字节流(例如,保存到文件中),然后再将其转换回类。这种重新加载可能发生在程序的不同实例中,甚至可能发生在不同的机器上。序列化(使用任何语言)涉及各种问题,尤其是当您在可序列化的文档中引用其他对象时。
答案 3 :(得分:11)
Here is a detailed explanation of the Serialization :(我自己的博客)
<强>序列化强>
序列化是序列化对象状态的过程,以字节序列的形式表示和存储。这可以存储在文件中。从文件中读取对象状态并恢复它的过程称为反序列化。
序列化有什么需要?
在现代架构中,总是需要存储对象状态然后检索它。例如在Hibernate中,要存储对象,我们应该使类Serializable。它的作用是,一旦对象状态以字节的形式保存,它就可以转移到另一个系统,然后该系统可以从状态读取并检索该类。对象状态可以来自数据库或不同的jvm,也可以来自单独的组件。在Serialization的帮助下,我们可以检索Object状态。
代码示例及说明:
首先让我们看一下Item Class:
public class Item implements Serializable{
/**
* This is the Serializable class
*/
private static final long serialVersionUID = 475918891428093041L;
private Long itemId;
private String itemName;
private transient Double itemCostPrice;
public Item(Long itemId, String itemName, Double itemCostPrice) {
super();
this.itemId = itemId;
this.itemName = itemName;
this.itemCostPrice = itemCostPrice;
}
public Long getItemId() {
return itemId;
}
@Override
public String toString() {
return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Double getItemCostPrice() {
return itemCostPrice;
}
public void setItemCostPrice(Double itemCostPrice) {
this.itemCostPrice = itemCostPrice;
}
}
在上面的代码中可以看出 Item 类实现了 Serializable 。
这是使类可序列化的接口。
现在我们可以看到一个名为 serialVersionUID 的变量被初始化为Long变量。此编号由编译器根据类的状态和类属性计算。这是一个有助于jvm在从文件中读取对象状态时识别对象状态的数字。
为此,我们可以查看官方Oracle文档:
序列化运行时与每个可序列化的类a关联 版本号,称为serialVersionUID,在此期间使用 反序列化以验证序列化的发送方和接收方 object已加载与该对象兼容的类 尊重序列化。如果接收器已加载了一个类 具有与其不同的serialVersionUID的对象 相应的发件人的类,然后反序列化将导致 InvalidClassException。可序列化的类可以声明它自己的类 serialVersionUID通过声明一个名为的字段显式地显示 &#34;的serialVersionUID&#34;必须是static,final和long类型: ANY-ACCESS-MODIFIER静态最终长serialVersionUID = 42L;如果一个 serializable类没有显式声明serialVersionUID, 然后序列化运行时将计算默认值 该类的serialVersionUID值基于该方面的各个方面 class,如Java(TM)对象序列化中所述 规格。但是,强烈建议所有人 可序列化类显式声明serialVersionUID值,因为 默认的serialVersionUID计算对类非常敏感 细节可能因编译器实现而异,并且可以 因此导致意外的InvalidClassExceptions期间 反序列化。因此,要保证一致的serialVersionUID 不同java编译器实现的值,可序列化 class必须声明一个显式的serialVersionUID值。也是 强烈建议显式serialVersionUID声明使用 尽可能使用私有修饰符,因为此类声明仅适用于 立即声明的类 - serialVersionUID字段不是 作为继承成员有用。
如果您注意到我们使用的另一个关键字 transient 。
如果字段不可序列化,则必须将其标记为瞬态。在这里,我们将 itemCostPrice 标记为瞬态,并且不希望将其写入文件
现在让我们看看如何在文件中写入对象的状态,然后从那里读取它。
public class SerializationExample {
public static void main(String[] args){
serialize();
deserialize();
}
public static void serialize(){
Item item = new Item(1L,"Pen", 12.55);
System.out.println("Before Serialization" + item);
FileOutputStream fileOut;
try {
fileOut = new FileOutputStream("/tmp/item.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(item);
out.close();
fileOut.close();
System.out.println("Serialized data is saved in /tmp/item.ser");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deserialize(){
Item item;
try {
FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
item = (Item) in.readObject();
System.out.println("Serialized data is read from /tmp/item.ser");
System.out.println("After Deserialization" + item);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在上面我们可以看到一个对象的序列化和反序列化的例子。
为此,我们使用了两个类。为了序列化对象,我们使用了ObjectOutputStream。我们使用writeObject方法在文件中写入对象。
对于反序列化,我们使用了ObjectInputStream,它从文件中读取对象。它使用readObject从文件中读取对象数据。
上述代码的输出如下:
Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]
请注意,反序列化对象中的 itemCostPrice 是 null ,因为它没有被写入。
答案 4 :(得分:10)
序列化涉及将对象的当前状态保存到流,并从该流中恢复等效对象。流充当对象的容器
答案 5 :(得分:5)
Serializable像接口一样被调用,但它更像是编译器的标志。它说这个对象可以保存。
将保存除无可序列化对象和标记易失性外的所有Objects实例变量。想象一下,您的应用程序可以更改颜色作为选项,而不必将该设置保持在外部,您每次运行时都需要更改颜色。
答案 6 :(得分:4)
序列化是一种将对象和数据存储或写入文件的技术。使用ObjectOutputStream
和FileOutputStream
类。这些类具有持久化对象的特定方法。比如writeObject();
用数字清楚解释。 See Here for more info
答案 7 :(得分:2)
从另一个角度出发。序列化是一种称为“标记接口”的接口。标记接口是一个不包含方法声明的接口,但是 仅指定(或“标记”)实现接口的类 一些财产。如果您了解多态性,这将非常有意义。对于Serializable标记接口,如果ObjectOutputStream.write(Object)方法的参数未实现接口,则该方法将失败。这是java中的潜在错误,它可能是ObjectOutputStream.write(Serializable)
强烈推荐:阅读Joshua Bloch的 Effective Java 中的第37项以了解更多信息。
答案 8 :(得分:2)
序列化:将对象状态写入文件/网络或任何地方。 (支持文件格式或网络支持表单的平均Java对象支持表单)
反序列化:从文件/网络或任何地方读取对象的状态。 (支持Java对象的表单的平均文件/网络支持表单)
答案 9 :(得分:0)
只是为了增加其他答案和一般性。序列化有时称为归档,例如在Objective-C中。
答案 10 :(得分:0)
序列化对象意味着将其状态转换为字节流,以便将字节流恢复为对象的副本。如果 Java 对象的类或其任何超类实现了 java.io.Serializable 接口或其子接口 java.io.Externalizable,则该对象是可序列化的。反序列化是将对象的序列化形式转换回对象副本的过程
点击 here 查看更多。