Serializable是什么意思?

时间:2010-08-07 09:36:09

标签: java serializable

Java中的类Serializable究竟是什么意思?或者一般来说,就此而言......

11 个答案:

答案 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)

序列化是一种将对象和数据存储或写入文件的技术。使用ObjectOutputStreamFileOutputStream类。这些类具有持久化对象的特定方法。比如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 查看更多。