关于java:什么是对象序列化?

What is object serialization?

"对象序列化"是什么意思?你能举例说明一下吗?


可以将序列化视为将对象实例转换为字节序列(可能是二进制的,也可能不取决于实现)的过程。

当您希望通过网络传输一个对象数据时,例如从一个JVM到另一个JVM,它非常有用。

在Java中,序列化机制被内置到平台中,但是需要实现可序列化接口以使对象可序列化。

还可以通过将属性标记为瞬态来防止对象中的某些数据被序列化。

最后,您可以覆盖默认机制,并提供自己的机制;这可能适用于某些特殊情况。要做到这一点,您可以使用Java中的一个隐藏功能。

需要注意的是,被序列化的是对象或内容的"值",而不是类定义。因此,方法不序列化。

下面是一个非常基本的示例,其中包含一些注释,以便于阅读:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.io.*;
import java.util.*;

// This class implements"Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the"value" of the object.

    // These two will be serialized;
    private String aString ="The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  {

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The"ObjectOutputStream" class has the default
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream(
                               // By using"FileOutputStream" we will
                               // Write it to a File in the file system
                               // It could have been a Socket to another
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

当我们运行这个程序时,会创建文件"o.ser",我们可以看到后面发生了什么。

如果我们将:someinteger的值更改为,例如integer.max_值,我们可以比较输出,看看有什么区别。

下面是一个截图,精确地显示了这一区别:

alt text

你能找出区别吗?;)

Java序列化中有一个附加的相关字段:SerialValueUID,但我想这已经太长了,无法覆盖它。


序列化是将一个对象转换为一系列字节,以便可以轻松地将该对象保存到持久存储或通过通信链路进行流式传输。然后可以反序列化字节流-将其转换为原始对象的副本。


敢于回答6岁的问题,只为新到Java的人增加了非常高层次的理解

What is Serialization?

将对象转换为字节,将字节转换回对象(反序列化)。

when is serialization used?

当我们想要持久化对象时。当我们希望对象在JVM的生命周期之外存在时。

Real World Example:

ATM:当账户持有人试图通过ATM从服务器中取款时,账户持有人信息(如取款详细信息)将被序列化并发送到服务器,在服务器上对详细信息进行反序列化并用于执行操作。

How serialization is performed in java.

  • 实现java.io.Serializable接口(标记接口,因此没有要实现的方法)。

  • 持久化对象:使用java.io.ObjectOutputStream类,这是一个过滤器流,它是一个较低级别字节流的包装器(将对象写入文件系统或通过网络线传输扁平对象并在另一侧重建)。

    • writeObject(<>)—编写对象
    • readObject()—读取序列化对象
  • Remember:

    序列化对象时,只保存对象的状态,而不保存对象的类文件或方法。

    当您序列化一个2字节的对象时,您会看到51字节的序列化文件。

    Steps how the object is serialized and de-serialized.

    答案:它是如何转换成51字节的文件的?

    • 首先写入序列化流magic数据(stream_magic="ac ed"和stream_version=jvm版本)。
    • 然后,它写出与实例关联的类的元数据(类的长度、类的名称、serialversionID)。
    • 然后递归地写出超类的元数据,直到找到java.lang.Object
    • 然后从与实例关联的实际数据开始。
    • 最后,将与实例关联的对象的数据从元数据开始写入实际内容。

    If you are interested in more in dept information about Java Serialization please check this link.

    编辑:还有一个很好的链接要阅读。

    这将回答一些常见的问题:

  • 如何不序列化类中的任何字段。ans:使用临时关键字

  • 当子类被序列化时,父类是否被序列化?答:不,如果父级没有扩展可序列化的接口父级字段,则不会被序列化。

  • 当父类被序列化时,子类是否被序列化?答:是的,默认情况下,子类也会被序列化。

  • 如何避免子类被序列化?ans:a.重写writeObject和readObject方法,抛出NotSerializableException

    B.还可以在子类中标记所有字段为瞬态。

  • 某些系统级类(如线程、输出流及其子类和套接字)不可序列化。

  • 序列化是将一个"活动"对象存储在内存中,并将其转换为可存储在某个位置(例如存储在内存中、磁盘上)的格式,然后将其"反序列化"回活动对象。


    我喜欢@oscarryz的礼物方式。虽然我在这里继续讲述的是最初由@amitgupta撰写的序列化故事。

    尽管知道机器人的类结构,并且已经对数据进行了序列化,地球的科学家还是无法反序列化能使机器人工作的数据。

    1
    2
    3
    Exception in thread"main" java.io.InvalidClassException:
    SerializeMe; local class incompatible: stream classdesc
    :

    火星的科学家们一直在等待全额付款。一旦付款完成,火星的科学家们就与地球的科学家们分享了这一系列的成果。地球的科学家将它设置为机器人类,一切都变得很好。


    我自己博客里的两分钱:

    下面是对序列化的详细解释:(我自己的博客)

    序列化:

    序列化是持久化对象状态的过程。它以字节序列的形式表示和存储。这可以存储在一个文件中。从文件中读取对象状态并将其还原的过程称为反序列化。

    序列化的需要是什么?

    在现代建筑中,总是需要存储对象状态,然后检索它。例如,在Hibernate中,为了存储对象,我们应该使类可序列化。它所做的是,一旦对象状态以字节的形式保存,它就可以传输到另一个系统,该系统随后可以从状态中读取并检索类。对象状态可以来自数据库、不同的JVM或单独的组件。在序列化的帮助下,我们可以检索对象状态。

    代码示例和说明:

    首先,让我们看看item类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    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类实现了可序列化。

    这是使类可序列化的接口。

    现在我们可以看到一个名为serialversionuid的变量被初始化为long变量。这个数字是由编译器根据类的状态和类属性计算的。当JVM从文件中读取对象的状态时,这个数字将帮助它识别对象的状态。

    为此,我们可以查看正式的Oracle文档:

    The serialization runtime associates with each serializable class a
    version number, called a serialVersionUID, which is used during
    deserialization to verify that the sender and receiver of a serialized
    object have loaded classes for that object that are compatible with
    respect to serialization. If the receiver has loaded a class for the
    object that has a different serialVersionUID than that of the
    corresponding sender's class, then deserialization will result in an
    InvalidClassException. A serializable class can declare its own
    serialVersionUID explicitly by declaring a field named
    "serialVersionUID" that must be static, final, and of type long:
    ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L; If a
    serializable class does not explicitly declare a serialVersionUID,
    then the serialization runtime will calculate a default
    serialVersionUID value for that class based on various aspects of the
    class, as described in the Java(TM) Object Serialization
    Specification. However, it is strongly recommended that all
    serializable classes explicitly declare serialVersionUID values, since
    the default serialVersionUID computation is highly sensitive to class
    details that may vary depending on compiler implementations, and can
    thus result in unexpected InvalidClassExceptions during
    deserialization. Therefore, to guarantee a consistent serialVersionUID
    value across different java compiler implementations, a serializable
    class must declare an explicit serialVersionUID value. It is also
    strongly advised that explicit serialVersionUID declarations use the
    private modifier where possible, since such declarations apply only to
    the immediately declaring class--serialVersionUID fields are not
    useful as inherited members.

    如果您注意到有另一个关键字,我们使用它是暂时的。

    如果字段不可序列化,则必须将其标记为"瞬态"。在这里,我们将itemCostPrice标记为瞬态,不希望将其写入文件中。

    现在让我们看看如何在文件中写入对象的状态,然后从中读取它。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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。我们已经使用write object方法将对象写入文件中。

    对于反序列化,我们使用了从文件中读取对象的objectinputstream。它使用readObject从文件中读取对象数据。

    上述代码的输出如下:

    1
    2
    3
    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为空,因为它没有被写入。

    在本文的第一部分,我们已经讨论了Java序列化的基础知识。

    现在让我们深入讨论它以及它是如何工作的。

    首先,让我们从serialversionID开始。

    serialversionID用作可序列化类中的版本控制。

    如果不显式声明serialversionID,JVM将根据可序列化类的各种属性自动为您声明。

    JAVA计算SerialValueUID的算法(在这里阅读更多的细节)

  • The class name.

  • The class modifiers written as a 32-bit integer.
  • The name of each interface sorted by name.
  • For each field of the class sorted by field name (except private static and private transient fields: The name of the field. The
    modifiers of the field written as a 32-bit integer. The descriptor
    of the field.
  • If a class initializer exists, write out the following: The name of the method, .
  • The modifier of the method, java.lang.reflect.Modifier.STATIC, written as a 32-bit integer.
  • The descriptor of the method, ()V.
  • For each non-private constructor sorted by method name and signature: The name of the method, . The modifiers of the
    method written as a 32-bit integer. The descriptor of the method.
  • For each non-private method sorted by method name and signature: The name of the method. The modifiers of the method written as a
    32-bit integer. The descriptor of the method.
  • The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and produces five 32-bit values sha[0..4]. The
    hash value is assembled from the first and second 32-bit values of the
    SHA-1 message digest. If the result of the message digest, the five
    32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
    sha, the hash value would be computed as follows:
  • 1
    2
    3
    4
    5
    6
    7
    8
        long hash = ((sha[0] >>> 24) & 0xFF) |
    >            ((sha[0] >>> 16) & 0xFF) << 8 |
    >            ((sha[0] >>> 8) & 0xFF) << 16 |
    >            ((sha[0] >>> 0) & 0xFF) << 24 |
    >            ((sha[1] >>> 24) & 0xFF) << 32 |
    >            ((sha[1] >>> 16) & 0xFF) << 40 |
    >            ((sha[1] >>> 8) & 0xFF) << 48 |
    >        ((sha[1] >>> 0) & 0xFF) << 56;

    Java序列化算法

    The algorithm to serialize an object is described as below:
    1. It writes out the metadata of the class associated with an instance.
    2. It recursively writes out the description of the superclass until it finds java.lang.object.
    3. Once it finishes writing the metadata information, it then starts with the actual data associated with the instance. But this time, it
    starts from the topmost superclass.
    4. It recursively writes the data associated with the instance, starting from the least superclass to the most-derived class.

    要记住的事情:

  • 类中的静态字段无法序列化。

    1
    2
    3
    4
    public class A implements Serializable{
         String s;
         static String staticString ="I won't be serializable";
    }
  • 如果serialversionID在read类中不同,它将抛出一个InvalidClassException异常。

  • 如果一个类实现了可序列化,那么它的所有子类也将是可序列化的。

    1
    2
    3
    public class A implements Serializable {....};

    public class B extends A{...} //also Serializable

  • 如果一个类具有另一个类的引用,则所有引用都必须是可序列化的,否则将不执行序列化过程。在这种情况下,运行时将引发NotSerializableException。

  • 如:

    1
    2
    3
    4
    public class B{
         String s,
         A a; // class A needs to be serializable i.e. it must implement Serializable
    }


    序列化意味着在Java中持久化对象。如果您想保存对象的状态并想稍后重建状态(可能在另一个JVM中),可以使用序列化。

    注意,对象的属性只会被保存。如果您想再次恢复对象,您应该有类文件,因为成员变量只会被存储,而不是成员函数。

    如:

    1
    2
    3
    ObjectInputStream oos = new ObjectInputStream(                                
                                     new FileInputStream(  new File("o.ser")) ) ;
    SerializationSample SS = (SearializationSample) oos.readObject();

    Searializable是标记类可序列化的标记接口。标记接口意味着它只是一个空接口,使用该接口将通知JVM这个类可以序列化。


    序列化是将对象的状态转换为位的过程,以便将其存储在硬盘上。当反序列化同一个对象时,它稍后将保持其状态。它允许您重新创建对象,而不必手动保存对象的属性。

    http://en.wikipedia.org/wiki/serialization网站


    对象序列化

    enter image description here

    EDOCX1 0是一种将Java对象的图形转换成字节数组以存储(EDCOX1×1)或传输(EDOCX1,2)的机制,然后通过反序列化,我们可以恢复对象的图形。使用引用共享机制可以正确还原对象图。但在存储之前,请检查输入文件/网络中的serialversionID和.class文件serialversionID是否相同。如果没有,扔一个java.io.InvalidClassException

    Each versioned class must identify the original class version for which it is capable of writing streams and from which it can read. For example, a versioned class must declare:

    serialVersionUID Syntax

    1
    2
    // ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L;
    private static final long serialVersionUID = 3487495895819393L;

    serialversionID对于序列化过程是必不可少的。但是开发人员将其添加到Java源文件中是可选的。如果未包含serialversionID,则序列化运行时将生成serialversionID并将其与类关联。序列化对象将包含此serialversionID以及其他数据。

    注意-强烈建议所有可序列化类显式声明serialversionuid,since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations,从而在反序列化期间导致意外的serialversionuid冲突,导致反序列化失败。

    正在检查可序列化类

    氧化镁

    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.

    • 类必须实现java.io.serializable接口才能成功序列化其对象。serializable是一个标记接口,用于通知编译器必须添加实现它的类的可序列化行为。这里Java虚拟机(JVM)负责其自动序列化。


      transient Keyword: java.io.Serializable interface

      While serializing an object, if we don't want certain data members of the object to be serialized we can use the transient modifier. The transient keyword will prevent that data member from being serialized.

      • Fields declared as transient or static are ignored by the serialization process.

      TRANSIENT & VOLATILE

      1
      2
      3
      4
      5
      6
      7
      8
      +--------------+--------+-------------------------------------+
      |  Flag Name   |  Value | Interpretation                      |
      +--------------+--------+-------------------------------------+
      | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
      +--------------+--------+-------------------------------------+
      |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
      |              |        | read by a persistent object manager.|
      +--------------+--------+-------------------------------------+
      1
      2
      3
      4
      5
      6
      7
      8
      class Employee implements Serializable {
          private static final long serialVersionUID = 2L;
          static int id;

          int eno;
          String name;
          transient String password; // Using transient keyword means its not going to be Serialized.
      }

    • 实现外部化接口允许对象对对象的序列化表单的内容和格式进行完全控制。调用Externalizable接口的方法writeExternal和readExternal来保存和恢复对象状态。当由一个类实现时,它们可以使用ObjectOutput和ObjectInput的所有方法写入和读取自己的状态。对象负责处理发生的任何版本控制。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      class Emp implements Externalizable {
          int eno;
          String name;
          transient String password; // No use of transient, we need to take care of write and read.

          @Override
          public void writeExternal(ObjectOutput out) throws IOException {
              out.writeInt(eno);
              out.writeUTF(name);
              //out.writeUTF(password);
          }
          @Override
          public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
              this.eno = in.readInt();
              this.name = in.readUTF();
              //this.password = in.readUTF(); // java.io.EOFException
          }
      }
    • 只有支持java.io.serializable或java.io.externalizable接口的对象才能是written to/read from流。对每个可序列化对象的类进行编码,包括类的类名和签名、对象字段和数组的值以及从初始对象引用的任何其他对象的闭包。

    文件的可序列化示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    public class SerializationDemo {
        static String fileName ="D:/serializable_file.ser";

        public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
            Employee emp = new Employee( );
            Employee.id = 1; // Can not Serialize Class data.
            emp.eno = 77;
            emp.name ="Yash";
            emp.password ="confidential";
            objects_WriteRead(emp, fileName);

            Emp e = new Emp( );
            e.eno = 77;
            e.name ="Yash";
            e.password ="confidential";
            objects_WriteRead_External(e, fileName);

            /*String stubHost ="127.0.0.1";
            Integer anyFreePort = 7777;
            socketRead(anyFreePort); //Thread1
            socketWrite(emp, stubHost, anyFreePort); //Thread2*/


        }
        public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
            FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
            ObjectOutputStream objectOut = new ObjectOutputStream( fos );
            objectOut.writeObject( obj );
            objectOut.close();
            fos.close();

            System.out.println("Data Stored in to a file");

            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

                Employee emp = (Employee) readObject;
                System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

                ois.close();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        public static void objects_WriteRead_External( Emp 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.
                Emp emp = new Emp();

                FileInputStream fis = new FileInputStream(new File( serFilename ));
                ObjectInputStream ois = new ObjectInputStream( fis );

                emp.readExternal(ois);

                System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

                ois.close();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    网络上的可序列化示例

    将对象的状态分布在不同的地址空间中,或者在同一台计算机上的不同进程中,或者甚至在通过网络连接的多台计算机中,但这些计算机通过共享数据和调用方法协同工作。

    • 数据编组
    • 桩和框架
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    /**
     * Creates a stream socket and connects it to the specified port number on the named host.
     */

    public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
        try { // CLIENT - Stub[marshalling]
            Socket client = new Socket(stubHost, anyFreePort);
            ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
            out.writeObject(objectToSend);
            out.flush();
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // Creates a server socket, bound to the specified port.
    public static void socketRead(  Integer anyFreePort ) {
        try { // SERVER - Stub[unmarshalling ]
            ServerSocket serverSocket = new ServerSocket( anyFreePort );
            System.out.println("Server serves on port and waiting for a client to communicate");
                /*System.in.read();
                System.in.read();*/


            Socket socket = serverSocket.accept();
            System.out.println("Client request to communicate on port server accepts it.");

            ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
            Employee objectReceived = (Employee) in.readObject();
            System.out.println("Server Obj :"+ objectReceived.name );

            socket.close();
            serverSocket.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    参见

    • 实现可序列化与可外部化


    序列化是将对象保存在存储介质(如文件或内存缓冲区)中或通过网络连接以二进制形式传输的过程。序列化对象独立于JVM,可以由任何JVM重新序列化。在这种情况下,"内存中"Java对象状态被转换为字节流。用户无法理解此类型的文件。它是一种特殊类型的对象,即JVM(Java虚拟机)重用。将对象序列化的过程也称为取消对象的格式化或封送对象。

    要序列化的对象必须实现java.io.Serializable接口。对象的默认序列化机制写入对象的类、类签名以及所有非暂时字段和非静态字段的值。

    1
    class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

    ObjectOutput接口扩展了DataOutput接口,并添加了序列化对象和将字节写入文件的方法。ObjectOutputStream扩展java.io.OutputStream并实现ObjectOutput接口。它将对象、数组和其他值序列化到流中。因此,ObjectOutputStream的构造函数写为:

    上面的代码用于创建ObjectOutput类的实例,其中ObjectOutputStream( )构造函数将FileOuputStream实例作为参数。

    ObjectOutput接口用于实现ObjectOutputStream类。构造ObjectOutputStream是为了序列化对象。

    用Java反序列化对象

    序列化的相反操作称为反序列化,即从一系列字节中提取数据称为反序列化,也称为展开或解组。

    ObjectInputStream扩展java.io.InputStream并实现ObjectInput接口。它从输入流反序列化对象、数组和其他值。因此,ObjectInputStream的构造函数写为:

    上述程序代码创建ObjectInputStream类的实例,以反序列化由ObjectInputStream类序列化的文件。上面的代码使用FileInputStream类的实例创建实例,该实例保存指定的文件对象,由于ObjectInputStream()构造函数需要输入流,因此必须对其进行反序列化。


    将文件作为对象返回:http://www.tutorialspoint.com/java/java_serialization.htm

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
            import java.io.*;

            public class SerializeDemo
            {
               public static void main(String [] args)
               {
                  Employee e = new Employee();
                  e.name ="Reyan Ali";
                  e.address ="Phokka Kuan, Ambehta Peer";
                  e.SSN = 11122333;
                  e.number = 101;

                  try
                  {
                     FileOutputStream fileOut =
                     new FileOutputStream("/tmp/employee.ser");
                     ObjectOutputStream out = new ObjectOutputStream(fileOut);
                     out.writeObject(e);
                     out.close();
                     fileOut.close();
                     System.out.printf("Serialized data is saved in /tmp/employee.ser");
                  }catch(IOException i)
                  {
                      i.printStackTrace();
                  }
               }
            }

        import java.io.*;
        public class DeserializeDemo
        {
           public static void main(String [] args)
           {
              Employee e = null;
              try
              {
                 FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
                 ObjectInputStream in = new ObjectInputStream(fileIn);
                 e = (Employee) in.readObject();
                 in.close();
                 fileIn.close();
              }catch(IOException i)
              {
                 i.printStackTrace();
                 return;
              }catch(ClassNotFoundException c)
              {
                 System.out.println("Employee class not found");
                 c.printStackTrace();
                 return;
              }
              System.out.println("Deserialized Employee...");
              System.out.println("Name:" + e.name);
              System.out.println("Address:" + e.address);
              System.out.println("SSN:" + e.SSN);
              System.out.println("Number:" + e.number);
            }
        }


    序列化是将Java对象转换为字节数组,然后以保留状态再次返回对象的过程。适用于各种情况,如通过网络发送对象或将对象缓存到磁盘。

    从这篇很好地解释了过程编程部分的短文中阅读更多内容,然后转到可序列化的JavaDoc。你也可能对阅读这个相关的问题感兴趣。


    |*|序列化类:将对象转换为字节,将字节转换回对象(反序列化)。

    1
    2
    3
    4
    5
    class NamCls implements Serializable
    {
        int NumVar;
        String NamVar;
    }

    |=>对象序列化是将对象状态转换为字节蒸汽的过程。

    • |->当您希望对象在JVM的生命周期之外存在时实现。
    • |->序列化对象可以存储在数据库中。
    • |->人类无法读取和理解可序列化对象,因此我们可以实现安全性。

    对象反序列化是获取对象状态并将其存储到对象(java. Lang.Object)中的过程。

    • |->在存储其状态之前,它检查serialversionuid表单输入文件/网络和.class文件serialversionuid是否相同。&;nbsp;nbspif不引发java.io.InvalidClassException。

    > = Java对象仅可序列化,如果它的类或它的任何超类

    • 实现java.io.serializable接口或
    • 它的子接口java.io.externalizable。

    |=>类中的静态字段无法序列化。

    1
    2
    3
    4
    5
    class NamCls implements Serializable
    {
        int NumVar;
        static String NamVar ="I won't be serializable";;
    }

    |=>如果不想序列化类的变量,请使用transient关键字

    1
    2
    3
    4
    5
    class NamCls implements Serializable
    {
        int NumVar;
        transient String NamVar;
    }

    |=>如果一个类实现了可序列化,那么它的所有子类也将是可序列化的。

    |=>如果一个类具有另一个类的引用,则所有引用都必须是可序列化的,否则将不会执行序列化过程。在这种情况下,运行时将引发NotSerializableException。