什么是对象序列化?

时间:2009-01-15 18:32:55

标签: java serialization object-serialization

“对象序列化”是什么意思?你能用一些例子解释一下吗?

14 个答案:

答案 0 :(得分:380)

您可以将序列化视为将对象实例转换为字节序列的过程(可能是二进制或不依赖于实现)。

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

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

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

最后你可以覆盖默认机制,并提供自己的机制;这可能适用于某些特殊情况。为此,您可以使用hidden features in java之一。

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

这是一个非常基本的样本,附有评论以便于阅读:

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_VALUE ,我们可能会比较输出以查看差异。

这是一个截图,显示了这种差异:

alt text

你能发现差异吗? ;)

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

答案 1 :(得分:373)

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

答案 2 :(得分:85)

敢于回答6岁的问题,为刚接触Java的人添加一个非常高级别的理解

  

什么是序列化?

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

  

何时使用序列化?

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

  

真实世界的例子:

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

  

如何在java中执行序列化。

  1. 实施java.io.Serializable界面(标记界面,因此无法实施)。

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

    • writeObject(<<instance>>) - 写一个对象
    • readObject() - 阅读序列化对象
  3.   

    记住:

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

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

      

    步骤如何序列化和反序列化对象。

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

    • 首先编写序列化流魔术数据(STREAM_MAGIC =“AC ED”和STREAM_VERSION = JVM版本)。
    • 然后它写出与实例关联的类的元数据(类的长度,类的名称,serialVersionUID)。
    • 然后它递归地写出超类的元数据,直到它找到java.lang.Object
    • 然后从与实例关联的实际数据开始。
    • 最后将与实例关联的对象数据从元数据开始写入实际内容。
      

    如果您对有关Java序列化的部门信息感兴趣,请查看link

    修改:还有一个好的link可以阅读。

    这将回答几个常见问题:

    1. 如何在课堂上序列化任何字段。
      Ans:使用transient关键字

    2. 当子类被序列化时,父类是否被序列化?
      Ans:不,如果父级没有扩展Serializable接口,则parent字段不会被序列化。

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

    4. 如何避免子类被序列化?
      答案:a。覆盖writeObject和readObject方法并抛出NotSerializableException

      湾你也可以在子类中标记瞬态的所有字段。

    5. 某些系统级类(如Thread,OutputStream及其子类和Socket)不可序列化。

答案 3 :(得分:19)

序列化将内存中的“实时”对象转换为可以存储在某处的格式(例如,在内存中,在磁盘上),然后“反序列化”回到活动对象中。

答案 4 :(得分:12)

我喜欢@OscarRyz呈现的方式。虽然我在这里继续story of serialization,最初是由@amitgupta写的。

即使了解机器人类结构并具有序列化数据,地球科学家也无法对可以使机器人工作的数据进行反序列化。

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

火星的科学家正在等待全部付款。付款完成后,火星科学家与地球科学家分享serialversionUID。地球科学家将它设置为机器人类,一切都变得很好。

答案 5 :(得分:8)

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

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

例如:

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

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

答案 6 :(得分:8)

我的博客上的两分钱:

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

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

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

首先让我们从 serialversionuid开始。

serialVersionUID 用作Serializable类中的版本控件。

如果您没有显式声明serialVersionUID,JVM将根据Serializable类的各种属性自动为您执行此操作。

Java的serialversionuid计算算法(详情请点击此处)

  
      
  1. 班级名称。      
        
    1. 类修饰符写为32位整数。
    2.   
    3. 按名称排序的每个界面的名称。
    4.   
    5. 对于按字段名称排序的类的每个字段(私有静态和私有瞬态字段除外:字段的名称   字段的修饰符写为32位整数。描述符   领域的。
    6.   
    7. 如果存在类初始值设定项,请写出以下内容:方法名称。
    8.   
    9. 方法的修饰符java.lang.reflect.Modifier.STATIC,写为32位整数。
    10.   
    11. 方法的描述符,()V。
    12.   
    13. 对于按方法名称和签名排序的每个非私有构造函数:方法的名称,。的修饰语   写为32位整数的方法。方法的描述符。
    14.   
    15. 对于按方法名称和签名排序的每个非私有方法:方法的名称。该方法的修饰语写为   32位整数。方法的描述符。
    16.   
    17. SHA-1算法在DataOutputStream产生的字节流上执行,并产生五个32位值sha [0..4]。该   哈希值是从第一个和第二个32位值组合而成的   SHA-1消息摘要。如果消息摘要的结果是五个   32位字H0 H1 H2 H3 H4,是一个由五个int值组成的数组   sha,哈希值的计算方法如下:
    18.   
  2.   
    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的序列化算法

  

序列化对象的算法描述如下:
  1.它写出与实例关联的类的元数据   2.它递归地写出超类的描述,直到找到 java.lang.object
  3.一旦完成编写元数据信息,它就会从与实例关联的实际数据开始。但这一次,它   从最顶层的超类开始   它递归地写入与实例关联的数据,从最小的超类开始到最派生的类。

要记住的事情:

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

    public class A implements Serializable{
         String s;
         static String staticString = "I won't be serializable";
    }
    
  2. 如果readversionuid在读取类中不同,则会抛出InvalidClassException异常。

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

    public class A implements Serializable {....};
    
    public class B extends A{...} //also Serializable
    
  4. 如果某个类具有另一个类的引用,则所有引用必须是Serializable,否则将不会执行序列化过程。在这种情况下, NotSerializableException 在运行时抛出。

  5. 例如:

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

答案 7 :(得分:6)

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

http://en.wikipedia.org/wiki/Serialization

答案 8 :(得分:3)

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

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

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

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

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

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

实现ObjectOutput类使用ObjectOutputStream接口。构造ObjectOutputStream以序列化对象。

反序列化java中的对象

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

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

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

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

答案 9 :(得分:3)

Java Object Serialization

enter image description here

Serialization 是一种将Java对象图形转换为字节数组以进行存储(to disk file)或传输(across a network)的机制,然后通过使用反序列化,我们可以恢复对象的图形。 使用参考共享机制正确恢复对象图。 但是在存储之前,检查输入文件/网络和.class文件serialVersionUID中的serialVersionUID是否相同。如果没有,请抛出java.io.InvalidClassException

  

每个版本化的类必须标识它能够编写流并且可以从中读取的原始类版本。例如,版本化类必须声明:

     

serialVersionUID语法

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

serialVersionUID对序列化过程至关重要。但是开发人员可以选择将其添加到java源文件中。如果未包含serialVersionUID,则序列化运行时将生成serialVersionUID并将其与类关联。序列化对象将包含此serialVersionUID以及其他数据。

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

Inspecting Serializable Classes

enter image description here

  

Java对象只能序列化。如果某个类或其任何超类实现 java.io.Serializable 接口    或其子接口 java.io.Externalizable

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

      

    瞬态关键字: java.io.Serializable interface

         

    在序列化对象时,如果我们不希望序列化对象的某些数据成员,我们可以使用transient修饰符。 transient关键字将阻止该数据成员被序列化。

         
        
    • 序列化过程会忽略声明为transient或static的字段。
    •   
         
        

    TRANSIENT&amp; VOLATILE

      
    +--------------+--------+-------------------------------------+
    |  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.|
    +--------------+--------+-------------------------------------+
    
    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接口允许对象完全控制对象的序列化形式的内容和格式。调用Externalizable接口的方法writeExternal和readExternal来保存和恢复对象状态。当由类实现时,它们可以使用ObjectOutput和ObjectInput的所有方法来编写和读取它们自己的状态。对象负责处理发生的任何版本控制。

    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个流。编码每个可序列化对象的类,包括类的类名和签名,对象的字段和数组的值,以及从初始对象引用的任何其他对象的闭包。

文件的可序列化示例

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();
        }
    }
}

网络上的可序列化示例

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

/**
 * 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();
    }
}

@see

答案 10 :(得分:2)

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

this short article which explains programming part of the process quite well了解详情,然后转到Serializable javadoc。您可能还有兴趣阅读this related question

答案 11 :(得分:2)

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

#include <stdio.h>
#include <math.h>
#include <string.h>

void reverse(char* array, int numberOfChars);

int main()
{
    char string[250];
    int length;
    printf("Enter a string: ");
    gets(string);
    printf("How long is the string:");
    scanf("%d", &length);
    reverse(string, length);
    printf("Reversed string is: %s\n"), string;

    return 0;
}

void reverse(char *userArray, int numberOfChars)
{
    char temp;
    int fromEnd = 0, fromStart = 0;

    fromEnd = numberOfChars;
    while (fromStart < fromEnd)
    {
        temp = userArray[fromStart];
        userArray[fromStart] = userArray[fromEnd];
        userArray[fromEnd] = temp;
        fromStart++;
        fromEnd--;

    }
}

答案 12 :(得分:1)

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

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

| =&GT;对象序列化是将对象状态转换为字节流的过程。

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

| =&GT; Object-Deserialization是获取对象状态并将其存储到对象(java.lang.Object)的过程。

  • | - &GT;在存储其状态之前,它会检查serialVersionUID是否与输入文件/网络和.class文件serialVersionUID相同。
    如果没有抛出java.io.InvalidClassException。

| =&GT; Java对象只能是可序列化的,如果它的类或它的任何超类

  • 实现java.io.Serializable接口或
  • 其子接口,java.io.Externalizable。

| =&GT;类中的静态字段无法序列化。

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

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

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

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

| =&GT;如果类具有另一个类的引用,则所有引用必须是Serializable,否则将不执行序列化过程。在这种情况下,在运行时抛出NotSerializableException。

答案 13 :(得分:0)

我将提供一个类比,以潜在地帮助巩固对象序列化/反序列化的概念性目的/实用性。

我想象 对象序列化/反序列化 是在试图将对象移动通过雨水沟的情况下。对象实际上是被“分解”或被序列化为自身的更多模块化版本(在这种情况下为一系列字节),以便有效地被许可通过介质。从计算的意义上讲,我们可以将字节流过暴风雨的路径视为类似于通过网络行进的字节。我们正在变换对象以符合更理想的运输方式或格式。序列化的对象通常将存储在一个二进制文件中,以后可以从中读取,写入或同时读取和写入两者。

也许一旦我们的对象能够以分解后的字节序列的形式流过漏极,我们可能希望将对象的表示形式作为二进制数据存储在数据库或硬盘驱动器中。但是,主要的收获是,通过序列化/反序列化,我们可以选择让我们的对象在序列化之后保持其二进制形式,或者通过执行反序列化“检索”对象的原始形式。