专栏首页Java学习网深入了解Java对象序列化

深入了解Java对象序列化

序列化字面上指的是安排在一个序列。它是一个过程Java在对象的状态转换为比特流。转换维护一个序列按照提供的元数据,比如一个POJO。也许,这是由于这种转变从抽象到一个原始序列的比特被称为序列化的词源。本文以序列化和其相关的概念,并试图描绘它的一些角落和缝隙,及其实现的Java API。

概述

序列化使任何POJO可持久化转换成字节流。字节流,然后可以存储在一个文件,内存或数据库。

因此,序列化背后的关键思想是一个字节流的概念。一个字节流在Java是0和1的原子集合在一个预定义的序列。原子意味着他们没有进一步的推导而来。原始比特非常灵活,可以转化成任何东西:字符,数字,Java对象,等等。位独立并不意味着什么,除非他们生产和消耗的一些有意义的抽象的定义。在序列化,这意思是源自一个预定义的数据结构类和实例化都叫到一个活跃的实称为Java对象。原始比特流然后存储在一个存储库,如一个文件在文件系统中,数组在内存的字节数,或者存储在数据库中。在稍后的时间,这个位流可以恢复回原来的Java对象的逆过程。这个反向过程称为反序列化。

图2:序列化

对象序列化和反序列化过程设计递归地工作。这意味着,当任何对象序列化一个继承层次结构的顶部,继承的对象被序列化。引用对象位于递归和序列化。在恢复期间,反向过程应用和自底向上的方式是反序列化的对象。

序列化接口

序列化一个对象必须实现一个io。Serializable接口。这个接口不包含成员和用于指定一个类为可序列化的。如前所述,所有继承子类也默认序列化。指定类的成员变量都坚持除了成员声明为瞬态和静态;他们不坚持。在下面的例子中,A类实现了Serializable。B类继承类;也因此,B是可序列化的。B类包含一个引用类C . C类也必须实现Serializable接口;否则,io。NotSerializableException会在运行时抛出。

包org.mano.example;

进口java.io.Serializable;

公共类实现了Serializable {
私有静态最终长serialVersionUID l = 1;
公共字符串;   公共静态intSTATIC_VAL = 0;
公共瞬态int TRANSIENT_VAL = 0;

/ /……getter和setter

}

包org.mano.example;

进口java.io.Serializable;

公共类C实现Serializable {
私有静态最终长serialVersionUID l = 1;
私人c字符串;
/ /……getter和setter
}


包org.mano.example;

进口. io . *;

公共B类扩展了{

私有静态最终长serialVersionUID l = 1;
私人字符串b;

私人C refC;

/ /……getter和setter

公共静态void main(String[]args)
抛出IOException,ClassNotFoundException {

字符串filePath =“/ home /测试/ testfile.sz”;
B B = new();

b。刚毛(“A”);
b。setB(B类);

b.getRefC()。国家经贸委(C类);

b.setTRANSIENT_VAL(100);
A.setSTATIC_VAL(400);
B.setSTATIC_VAL(200);

FileOutputStream fileOut =
新FileOutputStream(filePath);
ObjectOutputStream objOut =
新ObjectOutputStream(fileOut);
objOut.writeObject(b);

objOut.flush();
fileOut.close();


FileInputStream fileIn =
新FileInputStream(filePath);
ObjectInputStream objIn =
新ObjectInputStream(fileIn);
b2 B =(B)objIn.readObject();

objIn.close();
fileIn.close();

system . out。println(" = " + b2.getA());
system . out。println(" B = " + b2.getB());

system . out。println(C = +
.getC b2.getRefC()());

system . out。println(“静态val = " +
A.getSTATIC_VAL());
system . out。println(“静态val = " +
B.getSTATIC_VAL());
system . out。println(“瞬态val = " +
b2.getTRANSIENT_VAL());

   }
}

输出:

A=Class A
B=Class B
C=Class C
Static val=200
Static val=200
Transient val=0

如果您想使用一个对象从一个流中读或写,用readUnshared和writeUnshared方法代替readObject writeObject,分别。

观察到的任何变化的静态和瞬态变量不存储在这个过程。有许多问题与序列化过程。正如我们所看到的,如果一个超类声明可序列化的,所有的子也会序列化的类。这意味着,如果一个继承B继承了C继承D…将序列化的对象!使这些类non-serializable领域的一个方法是使用瞬时修饰符。说,如果我们有50个字段,我们不想坚持吗?我们必须将这50字段声明为瞬态!在反序列化过程中可能出现类似的问题。如果我们想反序列化只有五个字段而不是恢复所有10个字段序列化之前和存储?

有一个特定的方式停止序列化的继承类。出路是编写自己的readObject writeObject方法如下。

import java.io.*;

public class NonSerializedBook implements Serializable{

   private void readObject(ObjectInputStream in)
   throws IOException, ClassNotFoundException{
      // ...
   }
   private void writeObject(ObjectOutputStream out)
   throws IOException{
      // ...
   }
   // ...
}

一个可序列化的类建议宣布一个唯一的变量,称为serialVersionUID,识别数据持久化。如果这个可选变量是不提供的,JVM创建一个由内部逻辑。这是浪费时间。

注意:JDK bin目录包含一个serialver工具。这个工具可以用来serialVersionUID生成一个适当的值。尽管Java使用特定逻辑来生成这个数,它实际上是相当武断的和可以是任何号码。使用serialveras如下: import java.io.*; public class Book implements Serializable{ public static void main(String[] args){ System.out.println("Hello"); } }

编译创建类文件:

$ javac Book.java
$ serialver Book

的输出将类似于图3所示。

图3:编译后的类文件的结果

简而言之,一个序列化接口需要一些改变和更好地控制序列化和反序列化过程。

外部化接口提供了一些改进。但是,记住,序列化过程的自动实现Serializable接口在大多数情况下是好的。外部化是一个互补的接口,以减轻它的许多问题,更好的控制序列化/反序列化。

外部化接口

序列化和反序列化的过程很简单,最错综复杂的存储和恢复的对象都是自动处理的。有时,可能是程序员需要一些控制持久性过程;说,对象存储需要压缩或加密存储之前,同样的,解压和解密需要在恢复过程中发生。这就是你需要实现外部化接口。外部化接口扩展了Serializable接口提供了两个成员函数覆盖的实现类。

  • 空白readExternal(ObjectInput)
  • 空白writeExternal(ObjectOutput)

readExternal方法读取字节流从ObjectInput writeStream写道ObjectOutput。ObjectInput和ObjectOutput接口扩展DataInput DataOutput接口,分别。多态的读写方法被称为序列化一个对象。

包org.mano.example;

进口. io . *;
进口java.util.Random;

公共类的书实现外部化{
私人int bookId;
私人isbn的字符串;
私人字符串标题;
私人字符串出版商;
私人字符串作者;
/ /……构造函数和getter和setter

@Override
公共空间writeExternal(ObjectOutput)
抛出IOException {
out.writeInt(getBookId());
out.writeObject(getIsbn());
out.writeObject(getTitle());
out.writeObject(getPublisher());
out.writeObject(getAuthor());
   }

@Override
公共空间readExternal(ObjectInput)
抛出IOException,ClassNotFoundException {
setBookId(in.readInt());
.toString setIsbn(in.readObject()());
.toString setTitle(in.readObject()());
.toString setPublisher(in.readObject()());
.toString setAuthor(in.readObject()());
   }




@Override
公共字符串toString(){
返回“书(bookId = " + bookId +”,isbn = "
+ isbn +”,标题= " +标题+”,出版商= "
+出版商+”,作者= " +作者+“]”;
    }

公共静态最终字符串FILE_PATH =
“/ home /测试/ mylib.sz”;

公共静态void main(String[]args)
抛出IOException,ClassNotFoundException {
随机兰德= new随机();

书b1 =新书(rand.nextInt(100),
“123-456-789”,“图论”、“φ”,“和”);
FileOutputStream fileOut =
新FileOutputStream(FILE_PATH);
ObjectOutputStream objOut =
新ObjectOutputStream(fileOut);
b1.writeExternal(objOut);

objOut.flush();
fileOut.close();

FileInputStream fileIn =
新FileInputStream(FILE_PATH);
ObjectInputStream objIn =
新ObjectInputStream(fileIn);
书b2 = new();
b2.readExternal(objIn);
objIn.close();

System.out.println(b2);
   }
}

输出:

Book [bookId=6, isbn=123-456-789, title=Graph Theory,
   publisher=PHI, author=ND]

注意:任何字段声明为瞬态对外化没有影响。(不像Serializable接口,存储与外化。)

外化的序列化和反序列化过程更加灵活和给你更好的控制。但是,有几点要记住当使用外部化接口:

  • 实现外部化接口的类必须有一个默认的无参数构造函数。
  • 你必须覆盖并实现readExternal和writeExternal方法,明确。
  • 每个序列化代码中定义在readExternal writeExternal方法和反序列化代码。

根据前面的属性,任何非静态内部类不是外部化。原因是JVM修改内部类的构造函数通过添加一个引用父类的编译。因此,有一个无参数的构造函数的概念是不适用的非静态内部类。因为我们可以控制领域坚持什么,不借助readExternal和writeExternal方法,使与瞬态场non-persistable修饰符也是无关紧要的。

结论

序列化和外部化是一个标记接口来指定一个类的持久性。这些类的实例可能被转换并存储在存储字节流。存储磁盘上的文件或数据库,甚至通过网络传播。序列化过程和Java I / O流是分不开的。他们共同努力,把对象持久化的本质。

本文分享自微信公众号 - Java学习网(javalearns),作者:javalearns

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-08-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android中App安装位置详解

    Android中App安装位置详解 Android应用可以安装在本机自带存储,同时也可以安装到外部存储(SD卡)。自从API 8后也就是Android2.2后...

    用户1289394
  • 程序员需要多个显示器来提高工作效率

    程序员需要多个显示器来提高工作效率 我发现了一篇很有意思的关于研究多个显示器与生产力的博客文章。去年一些开发人员,包括我自己,开始使用多个显示器设置。基于我的经...

    用户1289394
  • Java面试专题之六:设计模式学习,详细分析抽象工厂模式

    所谓抽象工厂模式就是提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。

    用户1289394
  • Java入门 - 高级教程 - 04.序列化

    原文地址:http://www.work100.net/training/java-serialization.html

    光束云
  • JAVA中序列化和反序列化中的静态成员问题

    关于这个标题的内容是面试笔试中比较常见的考题,大家跟随我的博客一起来学习下这个过程。

    Spark学习技巧
  • 【Java基本功】深入浅出Java中的序列化与反序列化

    本文介绍了Java序列化的基本概念,序列化和反序列化的使用方法,以及实现原理等,比较全面地总结序列化相关知识点,并且使用具体例子来加以佐证。

    Java技术江湖
  • 佛曰:大道至简,序列化之

    我的思想被神经元序列化成一句句要表达的语言,进而推动我的双手将其序列化成在蓝牙键盘上有节奏的敲击出的字符流。

    tyrchen
  • Dubbo的多种序列化算法

    RPC 框架需要通过网络通信实现跨 JVM 的调用。既然需要网络通信,那就必然会使用到序列化与反序列化的相关技术,Dubbo 也不例外。

    JavaEdge
  • 别再和面试官说你不精通序列化与反序列化了

    TCP连接传输数据的基本形式二进制流。一般编程语言或网络框架提供的API中,传输数据的基本形式是字节。二进制流和字节流本质上其实是一样的。

    JavaEdge
  • Java序列化,看这篇就够了

    Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程:

    说故事的五公子

扫码关注云+社区

领取腾讯云代金券