JAVA 对象序列化(二)——Externalizable

转载自   JAVA 对象序列化(二)——Externalizable

    在Java对象序列化(一)——Serializable一文中我们可以看到,Java默认的序列化机制非常简单,而且序列化后的对象不需要再次调用构造器重新生成,但是在实际中,我们可以会希望对象的某一部分不需要被序列化,或者说一个对象被还原之后,其内部的某些子对象需要重新创建,从而不必将该子对象序列化。 在这些情况下,我们可以考虑实现Externalizable接口从而代替Serializable接口来对序列化过程进行控制(后面我们会讲到一个更简单的方式,通过transient的方式)。

     Externalizable接口extends Serializable接口,而且在其基础上增加了两个方法:writeExternal()和readExternal()。这两个方法会在序列化和反序列化还原的过程中被自动调用,以便执行一些特殊的操作。

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

     下面这段代码示范了如何完整的保存和恢复一个Externalizable对象

package test.serializable;import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;public class Blip implements Externalizable {private int i ;private String s;//没有初始化public Blip() {//默认构造函数必须有,而且必须是publicSystem.out.println("Blip默认构造函数");}public Blip(String s ,int i) {//s,i只是在带参数的构造函数中进行初始化。System.out.println("Blip带参数构造函数");this.s = s;this.i = i;}public String toString() {return s  + i ;}@Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {System.out.println("调用readExternal()方法");s = (String)in.readObject();//在反序列化时,需要初始化s和i,否则只是调用默认构造函数,得不到s和i的值i = in.readInt();}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {System.out.println("调用writeExternal()方法");out.writeObject(s); //如果我们不将s和i的值写入的话,那么在反序列化的时候,就不会得到这些值。out.writeInt(i);}}
package test.serializable;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class ExternalizableTest {/*** @param args* @throws IOException * @throws ClassNotFoundException */public static void main(String[] args) throws IOException, ClassNotFoundException {System.out.println("序列化之前");Blip b = new Blip("This String is " , 47);System.out.println(b);System.out.println("序列化操作,writeObject");ByteArrayOutputStream out = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(out);oos.writeObject(b);System.out.println("反序列化之后,readObject");ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());ObjectInputStream ois = new ObjectInputStream(in);Blip bb = (Blip)ois.readObject();System.out.println(bb);     }
}

运行结果如下所示:     

序列化之前
Blip带参数构造函数
This String is 47
序列化操作,writeObject
调用writeExternal()方法
反序列化之后,readObject
Blip默认构造函数
调用readExternal()方法
This String is 47

分析结果:

     在Blip类中,字段s和i只在第二个构造器中初始化,而不是在默认的构造器其中初始化的,每次writeObject时,都会调用WriteExtenal()方法,而在WriteExtenal()方法中我们需要将当前对象的值写入到流中;而每次readObject()时,调用的是默认的构造函数,如果我们不在 readExternal()方法中初始化s和i,那么s就会为null,而i就会为0。

下面分几种情况讨论:

  1) 如果我们只修改writeExternal()方法如下:

@Overridepublic void writeExternal(ObjectOutput out) throws IOException {System.out.println("调用writeExternal()方法");
//        out.writeObject(s);
//        out.writeInt(i);}

那么运行的结果为:

序列化之前
Blip带参数构造函数
This String is 47
序列化操作,writeObject
调用writeExternal()方法
反序列化之后,readObject
Blip默认构造函数
调用readExternal()方法
Exception in thread "main" java.io.OptionalDataExceptionat java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1349)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)at test.serializable.Blip.readExternal(Blip.java:34)at java.io.ObjectInputStream.readExternalData(ObjectInputStream.java:1792)at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1751)at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)at test.serializable.ExternalizableTest.main(ExternalizableTest.java:28)

      原因是因为,我们在ObjectOutPutStream中没有writeObject,而在ObjectInputStream中readObject导致的

 2)如果我们修改writeExternal()方法如下:

@Overridepublic void writeExternal(ObjectOutput out) throws IOException {System.out.println("调用writeExternal()方法");out.writeObject("自己定义的");out.writeInt(250);}

那么运行的结果为:

序列化之前
Blip带参数构造函数
This String is 47
序列化操作,writeObject
调用writeExternal()方法
反序列化之后,readObject
Blip默认构造函数
调用readExternal()方法
自己定义的250

看见没,反序列化后得到的s和i是我们在writeExternal()中自定义的数据

  3) 如果我们只是修改readExternal()方法

    @Overridepublic void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {System.out.println("调用readExternal()方法");
//        s = (String)in.readObject();
//        i = in.readInt();}

那么运行的结果为:

序列化之前
Blip带参数构造函数
This String is 47
序列化操作,writeObject
调用writeExternal()方法
反序列化之后,readObject
Blip默认构造函数
调用readExternal()方法
null0

   看见没?最后一行打印的是null0,说明没有对s和i进行初始化。

4)如果我们删除Blip的默认构造函数,或者将其权限不设置为public

//    public Blip() {
//         //默认构造函数必须有,而且必须是public
//        System.out.println("Blip默认构造函数");
//    }
//    or
     Blip() {//默认构造函数必须有,而且必须是publicSystem.out.println("Blip默认构造函数");}

运行结果如下:

序列化之前
Blip带参数构造函数
This String is 47
序列化操作,writeObject
调用writeExternal()方法
反序列化之后,readObject
Exception in thread "main" java.io.InvalidClassException: test.serializable.Blip; test.serializable.Blip; no valid constructorat java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:713)at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1733)at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)at test.serializable.ExternalizableTest.main(ExternalizableTest.java:28)
Caused by: java.io.InvalidClassException: test.serializable.Blip; no valid constructorat java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:471)at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:310)at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1106)at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)at test.serializable.ExternalizableTest.main(ExternalizableTest.java:24)

  在反序列化时,会出现无效的构造函数这个错误,可见必须有权限为public的默认的构造器(如果有非默认的带参数的构造函数,那么必须显示的写出默认的构造函数,如果没有非默认的构造函数,那么默认构造函数可以不显示的写出来),才能使Externalizable对象产生正确的行为。

总结Externalizable对象的用法:

    与Serizable对象不同,使用Externalizabled,就意味着没有任何东西可以自动序列化, 为了正常的运行,我们需要在writeExtenal()方法中将自对象的重要信息写入,从而手动的完成序列化。对于一个Externalizabled对象,对象的默认构造函数都会被调用(包括哪些在定义时已经初始化的字段),然后调用readExternal(),在此方法中必须手动的恢复数据。


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

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

相关文章

事务的ACID原则

事务的ACID原则 原子性(Atomic) 整个事务中的所有操作&#xff0c;要么全部完成&#xff0c;要么全部不完成&#xff0c;不可能停滞在中间某个环节。事务在执行过程中发生错误&#xff0c;会被回滚&#xff08;ROLLBACK&#xff09;到事务开始前的状态&#xff0c;就像这个事务…

qt4.8 mysql 驱动_Qt-4.8.5配置mysql驱动

一、安装mysql和Qt安装mysql我们只需要他的include和lib文件夹即可二、编译mysql驱动打开qt目录D:\Qt\4.8.5\plugins\sqldrivers&#xff0c;里面包含了qt支持的数据库驱动&#xff0c;包括sqlite和odbc两种&#xff0c;默认不支持mysql的&#xff0c;为了支持mysql我们可以进入…

hibernate+oracle+servlet实现插入数据的时候,不立马显示!!

尊重原创&#xff01;&#xff01;&#xff01; 开发软件&#xff1a;myeclipse 10oracle 11g 开发项目&#xff1a;租房系统 开发人员&#xff1a;1111 出现的问题&#xff1a;在前台发布房屋信息的界面插入数据时&#xff0c;自动跳转到查询所有房屋信息的页面&#xff0c;数…

mmall工程生成dao层的插件出错了出错了 自动生成mapper 的插件出错了

mybatis.org/dtd/mybatis-generator-config_1_0.dtd标红 2019-03-31 22:18:52 qq_35598865 阅读数 1637 版权声明&#xff1a;本文为博主原创文章&#xff0c;遵循 CC 4.0 BY-SA 版权协议&#xff0c;转载请附上原文出处链接和本声明。 本文链接&#xff1a;https://blog.cs…

用JWT来保护我们的ASP.NET Core Web API

在用Middleware给ASP.NET Core Web API添加自己的授权验证 中&#xff0c;自己动手写了一个Middleware来处理API的授权验证&#xff0c;现在就采用另外一种方式来处理这个授权验证的问题&#xff0c;毕竟现在也有不少开源的东西可以用&#xff0c;今天用的是JWT。 什么是JWT呢&…

JDK 6中新增的Java Console类功能概览

转载自 JDK 6中新增的Java Console类功能概览JDK 6中提供了java.io.Console类专用来访问基于字符的控制台设备。如果你的Java程序要与Windows下的cmd或者Linux下的Terminal交互&#xff0c;就可以用这个Java Console类代劳。 TestConsole.java 代码&#xff1a;package com.si…

mysql---批量插入数据:100w条数据

DROP FUNCTION IF EXISTS mock_data; DELIMITER $$ --写函数之前必写 CREATE FUNCTION mock_data() RETURNS INT BEGIN DECLARE num INT DEFAULT 1000000; DECLARE i INT DEFAULT 0; WHILE i < num DO INSERT INTO app_user(name, email, phone, gender, password, age) VAL…

一次性加载树结构数据表 mapper加载

************************************************************* Override public List<Organization> getOrganizationTree() throws UnionException {//缓存有就从缓存拿List<Organization> redisObjectOrganizationList (List<Organization>) redisObj…

DIP原则、IoC以及DI

一、DIP原则 高层模块不应该依赖于底层模块&#xff0c;二者都应该依赖于抽象。抽象不应该依赖于细节&#xff0c;细节应该依赖于抽象。 该原则理解起来稍微有点抽象&#xff0c;我们可以将该原则通俗的理解为&#xff1a;"依赖于抽象”。 该规则告诉我们&#xff0c;程序…

Java IO最详解

转载自 Java IO最详解初学java&#xff0c;一直搞不懂java里面的io关系&#xff0c;在网上找了很多大多都是给个结构图草草描述也看的不是很懂。而且没有结合到java7 的最新技术&#xff0c;所以自己来整理一下&#xff0c;有错的话请指正&#xff0c;也希望大家提出宝贵意见…

hibernate在分层架构中修改数据(update)时遇到的问题!!

开发软件&#xff1a;Myeclipse 10.0 数据库&#xff1a;oracle 开发人员&#xff1a;1111 问题简单描述&#xff1a;修改数据的时候不能正常修改&#xff0c;要么修改不成功&#xff0c;要么报错 nice,下面就来看看怎么解决这个bug的。 首先&#xff0c;我做的是一个租房网站&…

intellij idea 如何一键清除所有断点

intellij idea 如何一键清除所有断点 2017-06-19 11:37:20 yanziit 阅读数 50429更多 分类专栏&#xff1a; idea工具 我之前写了一个百度经验,但是搜不到,现在复制一遍,自己留个记录. 注:此方法适用 intellij idea 2016.2.5版本,其他版本我没用过,暂时不知道 1.在idea左下…

整理下.net分布式系统架构的思路

最近看到有部分招聘信息&#xff0c;要求应聘者说一下分布式系统架构的思路。今天早晨正好有些时间&#xff0c;我也把我们实际在.net方面网站架构的演化路线整理一下&#xff0c;只是我自己的一些想法&#xff0c;欢迎大家批评指正。 首先说明的是.net下开源内容较少&#xff…

SQL注入问题及预防方法

SQL注入问题 sql存在漏洞&#xff0c;会被攻击导致数据泄露 SQL会被拼接 or package com.kuang.lesson02; import com.kuang.lesson02.utils.jdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; …

Java transient关键字使用小记

转载自 Java transient关键字使用小记1. transient的作用及使用方法我们都知道一个对象只要实现了Serilizable接口&#xff0c;这个对象就可以被序列化&#xff0c;java的这种序列化模式为开发者提供了很多便利&#xff0c;我们可以不必关系具体序列化的过程&#xff0c;只要…

mysql sample函数_Oracle SAMPLE 语法应用

Sample抽样函数用于支持数据挖掘。Sample 函数使得数据分析操作在样本数据上进行&#xff0c;而不是在整张表上进行。Sample抽样函数用于支持数据挖掘。Sample 函数使得数据分析操作在样本数据上进行&#xff0c;而不是在整张表上进行。选择10%的记录select * from atest sampl…

docker 买了腾讯服务器后的学习

腾讯云买了 打算用 登录成功后&#xff1a; Last login: Mon Nov 11 13:37:02 2019 from 221.12.17.87 [rootVM_0_13_centos ~]# ip addr #查看ip地址 [rootVM_0_13_centos ~]# uname -r #查看centeros内核版本 docker要求 centeros内核在3.10以上 3.10.0-862.e…

Hibernate中使用Criteria查询及注解——(Dept.java)

Dept.java: 部门表的实体类&#xff1a; package cn.bdqn.hibernate_Criteria.entity;import java.util.HashSet; import java.util.Set;/*** 部门表的实体类* author 1111**/ public class Dept implements java.io.Serializable {// Fieldsprivate Integer deptno;private St…

Connect 2016 白话脱口秀将在B站直播,我们的口号是quot; 微软大法好quot;

今年 Connect 大会的主题是 Big possibilities. Bold technology. 北京时间 11月16日 23&#xff1a;00&#xff0c;Connect();//2016 将开启在线直播&#xff0c;届时红衣主教 Scott Guthrie 和 Scott Hanselman 携众多微软技术大咖将为大家带来超级精彩的主题演讲。丰富的内容…

MySQL(笔记)

数据库总览 有时候查的数据错乱&#xff0c;可以重启MySQL 关系型数据库 ( SQL ) MySQL , Oracle , SQL Server , SQLite , DB2 , …关系型数据库通过外键关联来建立表与表之间的关系 非关系型数据库 ( NOSQL )not only Redis , MongoDB , …非关系型数据库通常指数据以对…