Java 对象序列化 NIO NIO2详细介绍及解析

概要:
对象序列化
对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而可以保存到磁盘或者进行网络传输,其它程序获得这个二进制流后可以将其恢复成原来的Java对象。 序列化机制可以使对象可以脱离程序的运行而对立存在
序列化的含义和意义
序列化
序列化机制可以使对象可以脱离程序的运行而对立存在
序列化(Serialize)指将一个java对象写入IO流中,与此对应的是,对象的反序列化(Deserialize)则指从IO流中恢复该java对象
如果需要让某个对象可以支持序列化机制,必须让它的类是可序列化(serializable),为了让某个类可序列化的,必须实现如下两个接口之一:
所有在网络上传输的对象都应该是可序列化的,否则将会出现异常;所有需要保存到磁盘里的对象的类都必须可序列化;程序创建的每个JavaBean类都实现Serializable;
使用对象流实现序列化
实现Serializable实现序列化的类,程序可以通过如下两个步骤来序列化该对象:
1.创建一个ObjectOutputStream,这个输出流是一个处理流,所以必须建立在其他节点流的基础之上
// 创建个ObjectOutputStream输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));
2.调用ObjectOutputStream对象的writeObject方法输出可序列化对象
// 将一个Person对象输出到输出流中 oos.writeObject(per);
定义一个NbaPlayer类,实现Serializable接口,该接口标识该类的对象是可序列化的
public class NbaPlayer implements java.io.Serializable
{
private String name;
private int number;
// 注意此处没有提供无参数的构造器!
public NbaPlayer(String name, int number)
{
System.out.println("有参数的构造器");
this.name = name;
this.number = number;
}
// name的setter和getter方法
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
// number的setter和getter方法
public void setNumber(int number)
{
this.number = number;
}
public int getNumber()
{
return this.number;
}
}
使用ObjectOutputStream将一个NbaPlayer对象写入磁盘文件
import java.io.*;
public class WriteObject
{
public static void main(String[] args)
{
try(
// 创建一个ObjectOutputStream输出流
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("object.txt")))
{
NbaPlayer player = new NbaPlayer("维斯布鲁克", 0);
// 将player对象写入输出流
oos.writeObject(player);
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
反序列化
从二进制流中恢复Java对象,则需要使用反序列化,程序可以通过如下两个步骤来序列化该对象:
1.创建一个ObjectInputStream输入流,这个输入流是一个处理流,所以必须建立在其他节点流的基础之上
// 创建个ObjectInputStream输出流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));
2.调用ObjectInputStream对象的readObject()方法读取流中的对象,该方法返回一个Object类型的Java对象,可进行强制类型转换成其真实的类型
// 从输入流中读取一个Java对象,并将其强制类型转换为Person类 Person p = (Person)ois.readObject();
从object.txt文件中读取NbaPlayer对象的步骤
import java.io.*;
public class ReadObject
{
public static void main(String[] args)
{
try(
// 创建一个ObjectInputStream输入流
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("object.txt")))
{
// 从输入流中读取一个Java对象,并将其强制类型转换为NbaPlayer类
NbaPlayer player = (NbaPlayer)ois.readObject();
System.out.println("名字为:" + player.getName()
+ "\n号码为:" + player.getNumber());
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
反序列化读取的仅仅是Java对象的数据,而不是Java类,因此采用反序列化恢复Java对象时,必须提供Java对象所属的class文件,否则会引发ClassNotFoundException异常;反序列化机制无须通过构造器来初始化Java对象
如果使用序列化机制向文件中写入了多个Java对象,使用反序列化机制恢复对象必须按照实际写入的顺序读取。当一个可序列化类有多个父类时(包括直接父类和间接父类),这些父类要么有无参的构造器,要么也是可序列化的—否则反序列化将抛出InvalidClassException异常。如果父类是不可序列化的,只是带有无参数的构造器,则该父类定义的Field值不会被序列化到二进制流中
对象引用的序列化
如果某个类的Field类型不是基本类型或者String类型,而是另一个引用类型,那么这个引用类型必须是可序列化的,否则有用该类型的Field的类也是不可序列化的
public class AllStar implements java.io.Serializable
{
private String name;
private NbaPlayer player;
public AllStar(String name, NbaPlayer player)
{
this.name = name;
this.player = player;
}
// 此处省略了name和player的setter和getter方法
// name的setter和getter方法
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name = name;
}
// player的setter和getter方法
public NbaPlayer getPlayer()
{
return player;
}
public void setPlayer(NbaPlayer player)
{
this.player = player;
}
}
Java特殊的序列化算法
import java.io.*;
public class WriteAllStar
{
public static void main(String[] args)
{
try(
// 创建一个ObjectOutputStream输出流
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("allStar.txt")))
{
NbaPlayer player = new NbaPlayer("詹姆斯哈登", 13);
AllStar allStar1 = new AllStar("西部全明星", player);
AllStar allStar2 = new AllStar("首发后卫", player);
// 依次将四个对象写入输出流
oos.writeObject(allStar1);
oos.writeObject(allStar2);
oos.writeObject(player);
oos.writeObject(allStar2);
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
}
4个写入输出流的对象,实际上只序列化了3个,而且序列的两个AllStar对象的player引用实际是同一个NbaPlayer对象。以下程序读取序列化文件中的对象
import java.io.*;
public class ReadAllStar
{
public static void main(String[] args)
{
try(
// 创建一个ObjectInputStream输出流
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("allStar.txt")))
{
// 依次读取ObjectInputStream输入流中的四个对象
AllStar star1 = (AllStar)ois.readObject();
AllStar star2 = (AllStar)ois.readObject();
NbaPlayer player = (NbaPlayer)ois.readObject();
AllStar star3 = (AllStar)ois.readObject();
// 输出true
System.out.println("star1的player引用和player是否相同:"
+ (star1.getPlayer() == player));
// 输出true
System.out.println("star2的player引用和player是否相同:"
+ (star2.getPlayer() == player));
// 输出true
System.out.println("star2和star3是否是同一个对象:"
+ (star2 == star3));
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
如果多次序列化同一个可变Java对象时,只有第一次序列化时才会把该Java对象转换成字节序列并输出
当使用Java序列化机制序列化可变对象时,只有第一次调用WriteObject()方法来输出对象时才会将对象转换成字节序列,并写入到ObjectOutputStream;即使在后面程序中,该对象的实例变量发生了改变,再次调用WriteObject()方法输出该对象时,改变后的实例变量也不会被输出
import java.io.*;
public class SerializeMutable
{
public static void main(String[] args)
{
try(
// 创建一个ObjectOutputStream输入流
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("mutable.txt"));
// 创建一个ObjectInputStream输入流
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("mutable.txt")))
{
NbaPlayer player = new NbaPlayer("斯蒂芬库里", 30);
// 系统会player对象转换字节序列并输出
oos.writeObject(player);
// 改变per对象的name实例变量
player.setName("塞斯库里");
// 系统只是输出序列化编号,所以改变后的name不会被序列化
oos.writeObject(player);
NbaPlayer player1 = (NbaPlayer)ois.readObject(); //①
NbaPlayer player2 = (NbaPlayer)ois.readObject(); //②
// 下面输出true,即反序列化后player1等于player2
System.out.println(player1 == player2);
// 下面依然看到输出"斯蒂芬库里",即改变后的实例变量没有被序列化
System.out.println(player2.getName());
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
# Java
# 对象序列化
# NIO
# NIO2
# Java序列化
# NIO2详解
# Java JDBC导致的反序列化攻击原理解析
# JAVA序列化和反序列化的底层实现原理解析
# java IO数据操作流、对象序列化、压缩流代码解析
# Java对象的XML序列化与反序列化实例解析
# Java下利用Jackson进行JSON解析和序列化示例
# 解析Java的Jackson库中对象的序列化与数据泛型绑定
# JAVA基于SnakeYAML实现解析与序列化YAML
# 序列化
# 创建一个
# 转换成
# 斯蒂芬
# 是一个
# 多个
# 库里
# 可以通过
# 转换为
# 时才
# 有无
# 基础之上
# 詹姆斯
# 的是
# 而不是
# 都有
# 将会
# 才会
# 将其
# 并将其
相关文章:
简单实现Android验证码
制作网站的公司有哪些,做一个公司网站要多少钱?
公众号网站制作网页,微信公众号怎么制作?
教程网站设计制作软件,怎么创建自己的一个网站?
制作门户网站的参考文献在哪,小说网站怎么建立?
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
企业微网站怎么做,公司网站和公众号有什么区别?
香港服务器WordPress建站指南:SEO优化与高效部署策略
如何安全更换建站之星模板并保留数据?
如何在宝塔面板中修改默认建站目录?
开心动漫网站制作软件下载,十分开心动画为何停播?
C++中引用和指针有什么区别?(代码说明)
如何通过FTP空间快速搭建安全高效网站?
网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?
阿里云网站制作公司,阿里云快速搭建网站好用吗?
建站之星导航菜单设置与功能模块配置全攻略
整人网站在线制作软件,整蛊网站退不出去必须要打我是白痴才能出去?
公司网站制作价格怎么算,公司办个官网需要多少钱?
如何打造高效商业网站?建站目的决定转化率
建站主机功能解析:服务器选择与快速搭建指南
建站ABC备案流程中有哪些关键注意事项?
洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?
学校为何禁止电信移动建设网站?
建站主机是什么?如何选择适合的建站主机?
如何配置支付宝与微信支付功能?
制作营销网站公司,淘特是干什么用的?
c++怎么实现高并发下的无锁队列_c++ std::atomic原子变量与CAS操作【详解】
一键制作网站软件下载安装,一键自动采集网页文档制作步骤?
如何高效完成独享虚拟主机建站?
如何快速上传建站程序避免常见错误?
营销式网站制作方案,销售哪个网站招聘效果最好?
实例解析angularjs的filter过滤器
三星网站视频制作教程下载,三星w23网页如何全屏?
如何通过云梦建站系统实现SEO快速优化?
如何选择最佳自助建站系统?快速指南解析优劣
建站之星安装失败:服务器环境不兼容?
黑客入侵网站服务器的常见手法有哪些?
临沂网站制作企业,临沂第三中学官方网站?
如何自定义建站之星网站的导航菜单样式?
智能起名网站制作软件有哪些,制作logo的软件?
C#怎么创建控制台应用 C# Console App项目创建方法
网站按钮制作软件,如何实现网页中按钮的自动点击?
北京企业网站设计制作公司,北京铁路集团官方网站?
PHP正则匹配日期和时间(时间戳转换)的实例代码
如何快速生成高效建站系统源代码?
西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?
我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?
,制作一个手机app网站要多少钱?
SAX解析器是什么,它与DOM在处理大型XML文件时有何不同?
专业网站设计制作公司,如何制作一个企业网站,建设网站的基本步骤有哪些?
*请认真填写需求信息,我们会在24小时内与您取得联系。