Java中的Serializable接口transient关键字,及字节、字符、对象IO
1、什么是序列化和反序列化
Serialization是一种将对象转为为字节流的过程;deserialization是将字节流恢复为对象的过程。
2、什么情况下需要序列化
a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
3、如何实现序列化
将需要序列化的类实现Serializable接口就可以了,Serializable接口和Cloneable接口一样,不含任何方法,是个标记接口。
4、代码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | package com.tonyluis; import java.io.*; public class Solution { public static void main(String args[]) { ObjectOutputStream objectos = null ; SerializableTest myTest = new SerializableTest( "str" , 12 , 1 , "123456" , 8 ); try { objectos = new ObjectOutputStream( new FileOutputStream( "test.dat" )); objectos.writeObject(myTest); objectos.flush(); objectos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } ObjectInputStream objectin; SerializableTest mts = null ; try { objectin = new ObjectInputStream( new FileInputStream( "test.dat" )); mts = (SerializableTest) objectin.readObject(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(mts); // 注意,没有覆盖equals()方法,Object类的equals()默认是地址的比较 System.out.println(mts.equals(myTest)); } } class SerializableTest implements Serializable { // 序列化 ID 在 Eclipse 下提供了两种生成策略 // 一个是固定的 1L,一个是随机生成一个不重复的 long 类型数据(实际上是使用 JDK 工具生成) // 如果没有特殊需求,就是用默认的 1L 就可以 static final long serialVersionUID = 1L; String name; int num; static int staticNum; //transient关键字是不能被虚拟机默认序列化的,如果想序列化需要重写private void writeObject(ObjectOutputStream s)和private void readObject(ObjectInputStream s) transient String pwd; transient int num0; SerializableTest(String name, int num, int staticNum, String pwd, int num0) { this .name = name; this .num = num; this .staticNum = staticNum; this .pwd = pwd; this .num0 = num0; } public String toString() { return "name=" + name + ",num=" + num + ",staticNum=" + staticNum + ",pwd=" + pwd + ",num0=" + num0; } } |
输出结果:
name=str,num=12,staticNum=1,pwd=null,num0=0
false
5.序列化前和序列化后的对象的关系
反序列化还原后的对象地址与原来的的地址不同,序列化前后对象的地址不同了,但是内容是一样的,而且对象中包含的引用也相同。换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的”深度复制(deep copy)"——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。
java.io.File类用于表示文件(目录)
File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问
RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,可以访问文件的任意位置
(1)java文件模型
在硬盘上的文件是byte byte byte(字节)存储的,是数据的集合,一个byte是8个bit,对于int就是int的后8位,对于字符(char),一个char可以理解为一个byte,但是char有ASCII编码,byte没有。
(2)打开文件
有两种模式"rw"(读写) "r"(只读)
RandomAccessFile raf = new RandomeAccessFile(file,"rw")
文件指针,打开文件时指针在开头 pointer = 0;
(3) 写方法
raf.write(int)--->只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
(4)读方法
int b = raf.read()--->读一个字节
(5)文件读写完成以后一定要关闭(Oracle官方说明)
序列化与基本类型序列化
1)将类型int 转换成4byte或将其他数据类型转换成byte的过程叫序列化
数据---->n byte
2)反序列化
将n个byte 转换成一个数据的过程
nbyte ---> 数据
3)RandomAccessFile提供基本类型的读写方法,可以将基本类型数据
序列化到文件或者将文件内容反序列化为数据
IO流(输入流、输出流)
字节流、字符流
1.字节流
1)InputStream、OutputStream
InputStream抽象了应用程序读取数据的方式
OutputStream抽象了应用程序写出数据的方式
2)EOF = End 读到-1就读到结尾
3)输入流基本方法
int b = in.read();读取一个字节无符号填充到int低八位.-1是 EOF
in.read(byte[] buf)
in.read(byte[] buf,int start,int size)
4)输出流基本方法
out.write(int b) 写出一个byte到流,b的低8位
out.write(byte[] buf)将buf字节数组都写入到流
out.write(byte[] buf,int start,int size)
5)FileInputStream--->具体实现了在文件上读取数据
6)FileOutputStream 实现了向文件中写出byte数据的方法
7)DataOutputStream/DataInputStream
对"流"功能的扩展,可以更加方面的读取int,long,字符等类型数据
DataOutputStream
writeInt()/writeDouble()/writeUTF()
8)BufferedInputStream&BufferedOutputStream
这两个流类位IO提供了带缓冲区的操作,一般打开文件进行写入
或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
FileOutputStream--->write()方法相当于一滴一滴地把水“转移”过去
DataOutputStream-->writeXxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
BufferedOutputStream--->write方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高了
2.字符流
1) 编码问题
2)认识文本和文本文件
java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)
文件是byte byte byte ...的数据序列
文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果
3)字符流(Reader Writer)---->操作的是文本文本文件
字符的处理,一次处理一个字符
字符的底层任然是基本的字节序列
字符流的基本实现
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理
FileReader/FileWriter
字符流的过滤器
BufferedReader ---->readLine 一次读一行
BufferedWriter/PrintWriter ---->写一行
3.对象的序列化,反序列化
1)对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化
2)序列化流(ObjectOutputStream),是过滤流----writeObject
反序列化流(ObjectInputStream)---readObject
3)序列化接口(Serializable)
对象必须实现序列化接口 ,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准
4) transient关键字
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
分析ArrayList源码中序列化和反序列化的问题
5)序列化中 子类和父类构造函数的调用问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步