这篇文章主要介绍了java 对象序列化 nio nio2详细介绍及解析的相关资料,序列化机制可以使对象可以脱离程序的运行而对立存在,需要的朋友可以参考下
java 对象序列化 nio nio2详细介绍及解析
概要:
对象序列化
对象序列化机制允许把内存中的java对象转换成与平台无关的二进制流,从而可以保存到磁盘或者进行网络传输,其它程序获得这个二进制流后可以将其恢复成原来的java对象。 序列化机制可以使对象可以脱离程序的运行而对立存在
序列化的含义和意义
序列化
序列化机制可以使对象可以脱离程序的运行而对立存在
序列化(serialize)指将一个java对象写入io流中,与此对应的是,对象的反序列化(deserialize)则指从io流中恢复该java对象
如果需要让某个对象可以支持序列化机制,必须让它的类是可序列化(serializable),为了让某个类可序列化的,必须实现如下两个接口之一:
serializable:标记接口,实现该接口无须实现任何方法,只是表明该类的实例是可序列化的
externalizable
所有在网络上传输的对象都应该是可序列化的,否则将会出现异常;所有需要保存到磁盘里的对象的类都必须可序列化;程序创建的每个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详细介绍及解析的内容。