js 序列化内置对象_内置序列化技术

js 序列化内置对象

本文是我们名为“ 高级Java ”的学院课程的一部分。

本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的旅程! 在这里查看 !

目录

1.简介 2.可序列化的接口 3.可外部化的界面 4.有关可序列化接口的更多信息 5.可序列化和远程方法调用(RMI) 6. JAXB 7. JSON-P 8.序列化成本 9.超越Java标准库和规范 10.下一步是什么 11.下载源代码

1.简介

本教程的这一部分将专门用于序列化 :将Java对象转换为可用于在同一(或其他)环境( http://en.wikipedia )中存储和稍后重构的格式的过程。 org / wiki / Serialization )。 序列化不仅允许将Java对象保存到持久性存储中或从持久性存储中加载Java对象,而且还是现代分布式系统通信中非常重要的组件。

序列化并不容易,但是有效的序列化则更加困难。 除了Java标准库之外,还有许多可用的序列化技术和框架:其中一些使用紧凑的二进制表示形式,而另一些则将可读性放在首位。 尽管我们将在此过程中提及许多替代方案,但我们的注意力将集中在Java标准库(和最新规范)中:可Serializable ,可Externalizable Serializable ,用于XML绑定的Java体系结构( JAXB , JSR-222 )和用于Java的Java API。 JSON处理( JSON-P , JSR-353 )。

2.可序列化的接口

可以说,Java中将类标记为可用于序列化的最简单方法是实现java.io.Serializable接口。 例如:

public class SerializableExample implements Serializable {
}

序列化运行时与每个可序列化的类关联一个特殊的版本号,称为序列号UID ,在反序列化 (与序列化相反的过程)中使用该序列号 ,以确保已序列化对象的加载类兼容。 如果兼容性受到损害,则将InvalidClassException

可序列化的类可以通过声明名称为serialVersionUID的字段为staticfinallong类型的字段来显式引入其自己的串行版本UID 。 例如:

public class SerializableExample implements Serializable {private static final long serialVersionUID = 8894f47504319602864L;   
}

但是,如果可序列化的类未明确声明serialVersionUID字段,则序列化运行时将为该类生成一个默认的serialVersionUID字段。 值得一提的是,所有实现Serializable类都强烈建议显式声明serialVersionUID字段,因为默认的serialVersionUID生成严重依赖于内部类的详细信息,并且可能会因Java编译器实现及其版本而有所不同。 这样,为了保证行为的一致性,可序列化的类必须始终声明一个显式的serialVersionUID字段。

一旦该类可序列化(实现Serializable并声明serialVersionUID ),就可以使用例如ObjectOutputStream / ObjectInputStream进行存储和检索:

final Path storage = new File( "object.ser" ).toPath();try( final ObjectOutputStream out = new ObjectOutputStream( Files.newOutputStream( storage ) ) ) {out.writeObject( new SerializableExample() );
}

存储后,可以通过类似的方式进行检索,例如:

try( final ObjectInputStream in = new ObjectInputStream( Files.newInputStream( storage ) ) ) {final SerializableExample instance = ( SerializableExample )in.readObject();// Some implementation here
}

如我们所见, Serializable接口没有对应该序列化什么以及如何进行序列化提供很多控制( transient关键字将字段标记为不可序列化除外)。 而且,它限制了更改内部类表示形式的灵活性,因为它可能会破坏序列化/反序列化过程。 这就是为什么引入了另一个接口Externalizable原因。

3.可外部化的界面

Serializable接口相反, Externalizable将类应如何序列化和反序列化的职责委托给该类。 它只有两种方法,这是Java标准库中的声明:

public interface Externalizable extends java.io.Serializable {void writeExternal(ObjectOutput out) throws IOException;void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

反过来,每个实现Externalizable接口的类都应提供这两种方法的实现。 让我们看一个例子:

public class ExternalizableExample implements Externalizable {private String str;private int number;private SerializableExample obj;@Overridepublic void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {setStr(in.readUTF());setNumber(in.readInt());setObj(( SerializableExample )in.readObject());}@Overridepublic void writeExternal(final ObjectOutput out) throws IOException {out.writeUTF(getStr());out.writeInt(getNumber());out.writeObject(getObj());}
}

与实现Serializable的类相似,可以使用例如ObjectOutputStream / ObjectInputStream存储和检索实现Externalizable的类:

final Path storage = new File( "extobject.ser" ).toPath();final ExternalizableExample instance = new ExternalizableExample();
instance.setStr( "Sample String" );
instance.setNumber( 10 );
instance.setObj( new SerializableExample() );try( final ObjectOutputStream out = new ObjectOutputStream( Files.newOutputStream( storage ) ) ) {out.writeObject( instance );
}try( final ObjectInputStream in = new ObjectInputStream( Files.newInputStream( storage ) ) ) {final ExternalizableExample obj = ( ExternalizableExample )in.readObject();// Some implementation here
}

当使用Serializable接口的简单方法无法正常工作时, Externalizable接口允许进行细粒度的序列化/反序列化自定义。

4.有关可序列化接口的更多信息

在上一节中,我们提到了Serializable接口并没有对应该序列化什么以及如何序列化提供很多控制。 实际上,它并不是完全正确的(至少在使用ObjectOutputStream / ObjectInputStream时)。 任何可序列化的类都可以实现一些特殊方法,以控制默认的序列化和反序列化。

private void writeObject(ObjectOutputStream out) throws IOException;

此方法负责为其特定类编写对象的状态,以便相应的readObject方法可以将其还原(可以通过调用out.defaultWriteObject调用保存对象字段的默认机制)。

private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException;

此方法负责从流中读取并还原对象的状态(可以通过调用in.defaultReadObject调用还原对象字段的默认机制)。

private void readObjectNoData() throws ObjectStreamException;

在序列化流未将给定类列出为要反序列化的对象的超类的情况下,此方法负责初始化对象的状态。

Object writeReplace() throws ObjectStreamException;

当可序列化的类需要指定将对象写入流时要使用的替代对象时,使用此方法。

Object readResolve() throws ObjectStreamException;

最后,当从流中读取可序列化的类的实例时,可序列化的类需要指定替换时,使用此方法。

一旦知道内在的实现细节和要使用的特殊方法,默认的序列化机制(使用Serializable接口)在Java中就会变得非常麻烦。 您正在编写用于支持序列化的更多代码,更有可能展示出更多的错误和漏洞。

但是,有一种方法可以通过使用名为Serialization Proxy的非常简单的模式来降低这些风险,该模式基于利用writeReplacereadResolve方法。 这种模式的基本思想是引入专用的伴随类进行序列化(通常作为private static内部类),它补充了需要序列化的类。 让我们看一下这个例子:

public class SerializationProxyExample implements Serializable {private static final long serialVersionUID = 6163321482548364831L;private String str;private int number;        public SerializationProxyExample( final String str, final int number) {this.setStr(str);this.setNumber(number);}private void readObject(ObjectInputStream stream) throws InvalidObjectException {throw new InvalidObjectException( "Serialization Proxy is expected" );}private Object writeReplace() {return new SerializationProxy( this );}// Setters and getters here
}

对此类的实例进行序列化时,类SerializationProxyExample实现将提供替换对象( SerializationProxy类的实例)。 这意味着SerializationProxyExample类的实例将永远不会直接序列化(和反序列化)。 它还说明了为什么以某种方式进行反序列化尝试时, readObject方法会引发异常。 现在,让我们看一下伴随的SerializationProxy类:

private static class SerializationProxy implements Serializable {private static final long serialVersionUID = 8368440585226546959L;private String str;private int number;public SerializationProxy( final SerializationProxyExample instance ) {this.str = instance.getStr();this.number = instance.getNumber();}private Object readResolve() {return new SerializationProxyExample(str, number); // Uses public constructor}
}

在我们的略微简化的情况下, SerializationProxy类只是复制了所有的领域SerializationProxyExample (但可能比被很多复杂)。 因此,当要反序列化此类的实例时, readResolve调用readResolve方法,并且SerializationProxy提供替换,这次的形式为SerializationProxyExample实例。 因此, SerializationProxy类可作为一个序列化代理SerializationProxyExample类。

5.可序列化和远程方法调用(RMI)

在相当长的一段时间内,Java远程方法调用( RMI )是可用于在Java平台上构建分布式应用程序的唯一机制。 RMI提供了所有繁重的工作,并且可以从同一主机或不同物理(或虚拟)主机上的其他JVM透明地调用远程Java对象的方法。 RMI的基础是对象序列化,该对象序列化用于编组(序列化)和解组(反序列化)方法参数。

如今, RMI仍在许多Java应用程序中使用,但由于它的复杂性和通信限制(大多数防火墙都阻止RMI端口),因此越来越少地选择RMI 。 要获取有关RMI的更多详细信息,请参考官方文档 。

6. JAXB

XML绑定的Java体系结构,或者仅仅是JAXB ,可能是Java开发人员可以使用的最古老的替代序列化机制。 在下面,它使用XML作为序列化格式,提供了广泛的自定义选项,并包含许多注释,这些注释使JAXB非常吸引人且易于使用(注释在本教程的第5部分中介绍了如何以及何时使用Enums和注释 )。

让我们看一下用JAXB注释注释的普通Java类(POJO)的简化示例:

import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;@XmlAccessorType( XmlAccessType.FIELD )
@XmlRootElement( name = "example" )
public class JaxbExample {@XmlElement(required = true) private String str;@XmlElement(required = true) private BigDecimal number;// Setters and getters here
}

要使用JAXB基础结构将该类的实例序列化为XML格式,唯一需要的是编组器(或序列化器)的实例,例如:

final JAXBContext context = JAXBContext.newInstance( JaxbExample.class );        
final Marshaller marshaller = context.createMarshaller();final JaxbExample example = new JaxbExample();
example.setStr( "Some string" );
example.setNumber( new BigDecimal( 12.33d, MathContext.DECIMAL64 ) );try( final StringWriter writer = new StringWriter() ) {marshaller.marshal( example, writer );
}

这是上面示例中JaxbExample类实例的XML表示形式:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<example><str>Some string</str><number>12.33000000000000</number>
</example>

按照相同的原则,可以使用解组器(或反序列化器)的实例将类的实例从XML表示反序列化回Java对象,例如:

final JAXBContext context = JAXBContext.newInstance( JaxbExample.class );final String xml = "" +"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?>" +"<example>" +"    <str>Some string</str>" +"    <number>12.33000000000000</number>" +"</example>";final Unmarshaller unmarshaller = context.createUnmarshaller();
try( final StringReader reader = new StringReader( xml ) ) {final JaxbExample example = ( JaxbExample )unmarshaller.unmarshal( reader );// Some implementaion here
}

正如我们所看到的, JAXB易于使用,并且XML格式在当今仍然很受欢迎。 但是,XML的基本陷阱之一是冗长:很多时候,必要的XML结构元素大大超过了有效的数据有效负载。

7. JSON-P

自2013年以来,借助新引入的JSON处理Java API( JSON-P ),Java开发人员可以使用JSON作为序列化格式。

到目前为止,尽管有很多讨论在即将发布的Java 9版本( http://openjdk.java.net/jeps/198 )中将原生JSON支持包括到该语言中,但JSON-P尚未成为Java标准库的一部分。 但是,它在那里,并且可以作为Java JSON处理参考实现 ( https://jsonp.java.net/ )的一部分使用。

JAXB相比 ,无需为使它适合JSON序列化而向该类添加任何内容,例如:

public class JsonExample {private String str;private BigDecimal number;// Setters and getters here
}

序列化不像JAXB那样透明,并且需要为要序列化为JSON的每个类编写一些代码,例如:

final JsonExample example = new JsonExample();
example.setStr( "Some string" );
example.setNumber( new BigDecimal( 12.33d, MathContext.DECIMAL64 ) );try( final StringWriter writer = new StringWriter() ) {Json.createWriter(writer).write( Json.createObjectBuilder().add("str", example.getStr() ).add("number", example.getNumber() ).build());
}

这是上面示例中JsonExample类实例的JSON表示形式:

{"str":"Some string","number":12.33000000000000
}

反序列化过程也是如此:

final String json = "{\\"str\\":\\"Some string\\",\\"number\\":12.33000000000000}";  try( final StringReader reader = new StringReader( json ) ) {final JsonObject obj = Json.createReader( reader ).readObject();final JsonExample example = new JsonExample();example.setStr( obj.getString( "str" ) );example.setNumber( obj.getJsonNumber( "number" ).bigDecimalValue() );
}

可以说,目前Java中的JSON支持非常基本。 尽管如此,拥有一个很棒的东西,并且Java社区正在通过引入用于JSON绑定的Java API (JSON-B, JSR-367 )来努力丰富JSON支持。 使用此API,与JSON之间的Java对象序列化和反序列化应该像JAXB一样透明。

8.序列化成本

重要的是要理解,尽管序列化/反序列化在Java中看起来很简单,但它不是免费的,并且取决于数据模型和数据访问模式可能会消耗大量的网络带宽,内存和CPU资源。 不仅如此,尽管如此,Java对可序列化类提供了某种版本支持(使用序列UID,正如我们在“可序列化接口 ”一节中所看到的),它确实使开发过程变得更加困难,因为开发人员需要自己弄清楚如何管理数据模型的演变。

另外要说明的是,Java序列化在JVM领域之外无法正常工作。 对于使用多种编程语言和运行时构建的现代分布式应用程序,这是一个重要的限制。

这就解释了为什么许多替代的序列化框架和解决方案应运而生,并成为Java生态系统中非常流行的选择。

9.超越Java标准库和规范

在本节中,我们将从Fast-serialization项目( http://ruedigermoeller.github.io/fast-serialization/ )开始,研究无痛且有效的Java序列化的替代解决方案:快速替换Java序列化。 快速序列化的用法与Java标准库提供的用法没有太大不同,但声称它更快,更有效。

另一组框架对此问题有不同的看法。 它们基于结构化数据定义(或协议),并将数据序列化为紧凑的二进制表示形式(甚至可以从定义中生成相应的数据模型)。 除此之外,这些框架远远超出了Java平台,可以用于跨语言/跨平台序列化。 该领域中最知名的Java库是Google协议缓冲区 ( https://developers.google.com/protocol-buffers/),Apache Avro ( http://avro.apache.org/ )和Apache Thrift ( https:/ /thrift.apache.org/ )。

10.下一步是什么

在本教程的这一部分中,我们讨论了Java语言及其运行时提供的内置序列化技术。 我们已经看到了当今的串行化的重要性,当时几乎所有正在构建的单个应用程序都是大型分布式系统的一部分,并且需要与其余部分(或与其他外部系统)进行通信。 在本教程的下一部分中,我们将讨论Java中的反射和动态语言支持。

11.下载源代码

您可以在这里下载本课程的源代码: advanced-java-part-10

翻译自: https://www.javacodegeeks.com/2015/09/built-in-serialization-techniques.html

js 序列化内置对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 基本的输入输出

点击蓝字关注我们C 标准库虽然提供了一组丰富的输入/输出功能&#xff0c;但是本章只讨论 C 编程中最基本和最常见的 I/O 操作。C 的 I/O 发生在流中&#xff0c;流是字节序列。如果字节流是从设备&#xff08;如键盘、磁盘驱动器、网络连接等&#xff09;流向内存&#xff0c;…

Python3有效括号问题

Python3有效括号问题原题 https://leetcode-cn.com/problems/valid-parentheses/ 给定一个只包括 ‘(’&#xff0c;’)’&#xff0c;’{’&#xff0c;’}’&#xff0c;’[’&#xff0c;’]’ 的字符串&#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左…

http 和 https_HTTPS与HTTP区别

HTTPS与HTTP的认识&#xff1a;HTTP 加密 认证 完整性保护 HTTPSHTTP的全称是 Hypertext Transfer Protocol Vertion (超文本传输协议)HTTPS&#xff1a; HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议。HTTPS和HTTP的区别&#xff1a;HTTPS协议需要到ca申…

C语言指针的自我介绍(你了解我吗?了解多少?)

点击蓝字关注我们hey! Ladies and Gentlemen.&#x1f601;欢迎大家来看望我&#xff0c;对&#xff0c;我就是指针(pointer)&#xff0c;被很多人吐槽&#x1f614;&#xff0c;也被人说好。我希望大家了解过我以后&#xff0c;能够爱上我&#x1f618;。大家在了解我之前 &am…

Python3最长连续递增序列问题

Python3最长连续递增序列问题原题 https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/ 题目&#xff1a; 给定一个未经排序的整数数组&#xff0c;找到最长且连续的的递增序列。 示例 1: 输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1…

访问nfs_通过NFS访问编年引擎

访问nfs总览 编年史引擎是数据虚拟化层。 它抽象化了访问&#xff0c;操作和订阅各种数据源的复杂性&#xff0c;因此该数据的用户无需知道实际存储数据的方式或位置。 这意味着该数据可以在系统之间迁移或以更有效的方式存储&#xff0c;但对于开发人员来说使用起来很复杂。 …

flex 解析json文件_使用 Python 处理 JSON 格式的数据 | Linux 中国

如果你不希望从头开始创造一种数据格式来存放数据&#xff0c;JSON 是一个很好的选择。如果你对 Python 有所了解&#xff0c;就更加事半功倍了。下面就来介绍一下如何使用 Python 处理 JSON 数据。-- Seth KenlonJSON 的全称是 JavaScript 对象表示法JavaScript Object Notati…

【C语言】指针进阶第一站:字符指针 typedef关键字!

点击蓝字关注我们简单回顾一下指针的概念内存会划分以字节为单位的空间&#xff0c;每一个字节都有一个编号&#xff08;地址/指针&#xff09;指针变量可以存放这个地址/指针注&#xff1a;我们日常所说的指针&#xff0c;一般是指针变量下面让我们坐上指针进阶的直通车&#…

漫反射 高光反射_如何有效地使用反射

漫反射 高光反射本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题&#xff0c;包括对象创建&#xff0c;并发&#xff0c;序列化&#xff0c;反射等。 它将指导您完成Java掌握的旅程&#xff01; 在这里查看 &#xff…

python编译helloworld_python3学习笔记--001--python HelloWorld

python默认使用UTF-8编码 一个python3版本的HelloWorld代码如下&#xff1a; #!/usr/bin/env python print (Hello World!) 如果此python脚本文件名为&#xff1a;hello.py&#xff0c;则运行此脚本文件的方法有两种&#xff1a; 1、python hello.py [laolanglocalhost python]…

漫谈 C++:良好的编程习惯与编程要点

点击蓝字关注我们以良好的方式编写C class假设现在我们要实现一个复数类complex&#xff0c;在类的实现过程中探索良好的编程习惯。① Header(头文件)中的防卫式声明complex.h: # ifndef __COMPLEX__ # define __COMPLEX__ class complex {} # endif防止头文件的内容被多次包含…

Python3只出现一次数字

Python3只出现一次数字原题 https://leetcode-cn.com/problems/single-number/ 题目&#xff1a; 给定一个非空整数数组&#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 说明&#xff1a; 你的算法应该具有线性时…

junit测试找不到数据库_将数据库日志添加到JUnit3

junit测试找不到数据库在过去的十年中&#xff0c;我们已经编写了成千上万的JUnit3测试&#xff0c;现在正尝试将结果合并到数据库中&#xff0c;而不是分散的日志文件中。 事实证明&#xff0c;扩展TestCase类非常容易做到这一点。 注意&#xff1a;这种方法并不直接适用于JUn…

python float 精度_浅谈Python里面小数点精度的控制

要求较小的精度 round()内置方法 这个是使用最多的&#xff0c;刚看了round()的使用解释&#xff0c;也不是很容易懂。round()不是简单的四舍五入的处理方式。 For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power min…

【C语言】指针进阶第二站:指针数组!

点击蓝字关注我们指针数组数组是一种类型的数的集合整型数组的元素都是int类型指针数组的元素都是指针变量int* arr1[10];//整型指针的数组char*arr2[10];//一级字符指针的数组char** arr3[5];//二级字符指针的数组参考这一份示意图示例1:定义多个字符指针在上一站的字符指针里…

Python3不用str自带lower转换位小写字母

Python3不用str自带lower转换位小写字母原题 https://leetcode-cn.com/problems/to-lower-case/ 题目&#xff1a; 不准用字符串自带的lower() API&#xff01; 实现函数 ToLowerCase()&#xff0c;该函数接收一个字符串参数 str&#xff0c;并将该字符串中的大写字母转换成小…

php 命令执行crud_使用活动记录执行CRUD

php 命令执行crud本文是我们学院课程“ jOOQ –类型安全数据库查询”的一部分 。 在SQL和特定关系数据库很重要的Java应用程序中&#xff0c;jOOQ是一个不错的选择。 当JPA / Hibernate抽象过多而JDBC过于抽象时&#xff0c;这是一种替代方法。 它显示了一种现代的领域特定语言…

python所有的父类_object代表所有类的父类吗??

作者&#xff1a;邹冲 链接&#xff1a;https://www.zhihu.com/question/19754936/answer/202650790 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 写东西的时候刚好遇到这个问题&#xff0c;回答一波…… 继承 obje…

C语言初学者常见错误 | 总结22点

点击蓝字关注我们正文一.语言使用错误在打代码的过程中&#xff0c;经常需要在中文与英文中进行转换&#xff0c;因此常出现一些符号一不小心就用错&#xff0c;用成中文。例如&#xff1a;“&#xff1b;”中文中的分号占用了两个字节&#xff0c;而英文中“;”分号只占用一个…

Python3实现队列

Python3实现队列class MyQueue:def __init__(self):self.__arr []def push(self, x: int) -> None:self.__arr.append(x)def pop(self) -> int:return self.__arr.pop(0)def peek(self) -> int:return self.__arr[0]def empty(self) -> bool:return len(self.__ar…