德阳市住房和城乡建设局网站windows10PHP 网站建设

当前位置: 首页 > news >正文

德阳市住房和城乡建设局网站,windows10PHP 网站建设,邯郸单位网站建设,易企秀h5怎么制作Java序列化与反序列化是什么#xff1f; Java序列化是指把Java对象转换为字节流的过程#xff0c;而Java反序列化是指把字节流恢复为Java对象的过程。 序列化#xff1a; 序列化是把对象转换成有序字节流#xff0c;以便在网络上传输或者保存在本地文件中。核心作用是对象…Java序列化与反序列化是什么 Java序列化是指把Java对象转换为字节流的过程而Java反序列化是指把字节流恢复为Java对象的过程。 序列化 序列化是把对象转换成有序字节流以便在网络上传输或者保存在本地文件中。核心作用是对象状态的保存与重建。我们都知道Java对象是保存在JVM的堆内存中的也就是说如果JVM堆不存在了那么对象也就跟着消失了。 而序列化提供了一种方案可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式如二进制流比如保存在文件中。这样当再次需要这个对象的时候从文件中读取出二进制流再从二进制流中反序列化出对象。 反序列化 客户端从文件中或网络上获得序列化后的对象字节流根据字节流中所保存的对象状态及描述信息通过反序列化重建对象。 序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。 序列化和反序列化常见应用场景 对象在进行网络传输比如远程过程调用 RPC 的时候之前需要先被序列化接收到序列化的对象之后需要再进行反序列化 将对象存储到文件之前需要进行序列化将对象从文件中读取出来需要进行反序列化 将对象存储到数据库如 Redis之前需要用到序列化将对象从缓存数据库中读取出来需要反序列化 将对象存储到内存之前需要进行序列化从内存中读取出来之后需要进行反序列化。
需要注意的是虽然将对象序列化到内存中可以减少与磁盘或者网络的交互但是仍然需要占用内存空间。如果需要处理大量的对象可能会导致内存问题因此应该根据实际情况来选择是否将对象序列化到内存中。 为什么需要序列化与反序列化 简要描述对内存中的对象进行持久化或网络传输, 这个时候都需要序列化和反序列化。 深入描述 1.对象序列化可以实现分布式对象。 主要应用例如RMI(即远程调用Remote Method Invocation)要利用对象序列化运行远程主机上的服务就像在本地机上运行对象时一样。 2.java对象序列化不仅保留一个对象的数据而且递归保存对象引用的每个对象的数据。 可以将整个对象层次写入字节流中可以保存在文件中或在网络连接上传递。利用对象序列化可以进行对象的深复制即复制对象本身及引用的对象本身。序列化一个对象可能得到整个对象序列。 3.序列化可以将内存中的类写入文件或数据库中。 比如将某个类序列化后存为文件下次读取时只需将文件中的数据反序列化就可以将原先的类还原到内存中。也可以将类序列化为流数据进行传输。 总的来说就是将一个已经实例化的类转成文件存储下次需要实例化的时候只要反序列化即可将类实例化到内存中并保留序列化时类中的所有变量和状态。 4.对象、文件、数据有许多不同的格式很难统一传输和保存。 序列化以后就都是字节流了无论原来是什么东西都能变成一样的东西就可以进行通用的格式传输或保存传输结束以后要再次使用就进行反序列化还原这样对象还是对象文件还是文件。 常见序列化协议有哪些 JDK 自带的序列化方式一般不会用 因为序列化效率低并且存在安全问题。 比较常用的序列化协议有 Hessian、Kryo、Protobuf、ProtoStuff这些都是基于二进制的序列化协议。 像 JSON 和 XML 这种属于文本类序列化方式。虽然可读性比较好但是性能较差一般不会选择。 JDK 自带的序列化方式 实现 Serializable 接口或者 Externalizable 接口。 Serializable接口 类通过实现 java.io.Serializable 接口以启用其序列化功能。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段仅用于标识可序列化的语义。 如以下例子 import java.io.Serializable;public class User implements Serializable {private static final long serialVersionUID 1905122041950251207L;private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return User{ name name };} }通过下面的代码进行序列化及反序列化 public class SerializableDemo {public static void main(String[] args) {//Initializes The ObjectUser user new User();user.setName(cosen);System.out.println(user);//Write Obj to Filetry (FileOutputStream fos new FileOutputStream(tempFile); ObjectOutputStream oos new ObjectOutputStream(fos)) {oos.writeObject(user);} catch (IOException e) {e.printStackTrace();}//Read Obj from FileFile file new File(tempFile);try (ObjectInputStream ois new ObjectInputStream(new FileInputStream(file))) {User newUser (User)ois.readObject();System.out.println(newUser);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}} }//OutPut: //User{namecosen} //User{namecosen}Externalizable接口 Externalizable继承自Serializable该接口中定义了两个抽象方法writeExternal()与readExternal()。 当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。否则所有变量的值都会变成默认值。 public class User implements Externalizable {private static final long serialVersionUID 1905122041950251207L;private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name name;}public void writeExternal(ObjectOutput out) throws IOException {out.writeObject(name);}public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {name (String) in.readObject();}Overridepublic String toString() {return User{ name name };} }通过下面的代码进行序列化及反序列化 public class ExternalizableDemo1 {public static void main(String[] args) {//Write Obj to fileUser user new User();user.setName(cosen);try(ObjectOutputStream oos new ObjectOutputStream(new FileOutputStream(tempFile))){oos.writeObject(user);} catch (IOException e) {e.printStackTrace();}//Read Obj from fileFile file new File(tempFile);try(ObjectInputStream ois new ObjectInputStream(new FileInputStream(file))){User newInstance (User) ois.readObject();//outputSystem.out.println(newInstance);} catch (IOException | ClassNotFoundException e ) {e.printStackTrace();}} }//OutPut: //User{namecosen}两种序列化的对比 实现Serializable接口实现Externalizable接口系统自动存储必要的信息程序员决定存储哪些信息Java内建支持易于实现只需要实现该接口即可无需任何代码支持必须实现接口内的两个方法性能略差性能略好 serialVersionUID 有什么作用 serialVersionUID 用来表明类的不同版本间的兼容性起版本控制的作用。 Java的序列化机制是通过在运行时判断类的 serialVersionUID 来验证版本一致性的。在进行反序列化时JVM 会把传来的字节流中的serialVersionUID 与本地相应实体类的 serialVersionUID 进行比较如果相同就认为是一致的可以进行反序列化否则就会出现序列化版本不一致的异常InvalidClassException。 为什么还要显示指定serialVersionUID的值? 如果不显示指定serialVersionUIDJVM在序列化时会根据属性自动生成一个serialVersionUID然后与属性一起序列化,再进行持久化或网络传输。在反序列化时, JVM会再根据属性自动生成一个新版serialVersionUID, 然后将这个新版serialVersionUID与序列化时生成的旧版serialVersionUID进行比较, 如果相同则反序列化成功, 否则报错. 如果显示指定了JVM在序列化和反序列化时仍然都会生成一个serialVersionUID。但值为我们显示指定的值, 这样在反序列化时新旧版本的serialVersionUID就一致了. 在实际开发中, 不显示指定serialVersionUID的情况会导致什么问题? 如果我们的类写完后不再修改, 那当然不会有问题, 但这在实际开发中是不可能的, 我们的类会不断迭代, 一旦类被修改了, 那旧对象反序列化就会报错. 所以在实际开发中, 我们都会显示指定一个serialVersionUID, 值是多少无所谓, 只要不变就行。 serialVersionUID 不是被 static 变量修饰了吗为什么还会被“序列化” static 修饰的变量是静态变量位于方法区本身是不会被序列化的。 static 变量是属于类的而不是对象。serialVersionUID 属性并没有被序列化JVM在序列化对象时会自动生成一个serialVersionUID, 然后将我们显示指定的 serialVersionUID 属性值赋给自动生成的serialVersionUID。 serialVersionUID什么时候修改 《阿里巴巴Java开发手册》中有以下规定
Java 序列化中如果有些字段不想进行序列化怎么办 对于不想进行序列化的变量使用 transient 关键字修饰。 transient 关键字的作用是控制变量的序列化在变量声明前加上该关键字可以阻止该变量被序列化到文件中在被反序列化后transient 变量的值被设为初始值如 int 型的是 0对象型的是 null。transient 只能修饰变量不能修饰类和方法。 关于 transient 还有几点注意 transient 只能修饰变量不能修饰类和方法。 transient 修饰的变量在反序列化后变量值将会被置成类型的默认值。例如如果是修饰 int 类型那么反序列后结果就是 0。 static 变量因为不属于任何对象(Object)所以无论有没有transient 关键字修饰均不会被序列化。
静态变量会被序列化吗? 不会。因为序列化是针对对象而言的, 而静态变量优先于对象存在, 随着类的加载而加载, 所以不会被序列化. 看到这个结论, 是不是有人会问, serialVersionUID也被static修饰, 为什么serialVersionUID会被序列化? 其实serialVersionUID属性并没有被序列化, JVM在序列化对象时会自动生成一个serialVersionUID, 然后将我们显示指定的serialVersionUID属性值赋给自动生成的serialVersionUID。 为什么不推荐使用 JDK 自带的序列化 我们很少或者说几乎不会直接使用 JDK 自带的序列化方式主要原因有下面这些原因 不支持跨语言调用 : 如果调用的是其他语言开发的服务的时候就不支持了。 性能差 相比于其他序列化框架性能更低主要原因是序列化之后的字节数组体积较大导致传输成本加大。 存在安全问题 序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制那么攻击者即可通过构造恶意输入让反序列化产生非预期的对象在此过程中执行构造的任意代码。
如果想要详细了解这个问题可以参考这篇文章——应用安全:JAVA反序列化漏洞之殇。