对象具有状态和行为两种属性。行为存在类中的方法中,想要保存状态有多种方法,这里介绍两种:
一是保存整个当前对象本身(通过序列化);一是将对象中各个状态值保存到文件中(这种方式可以给其他非JAVA程序用),如果其他程序需要用到的状态,可以通过特定的格式存储到文本中,方便其他程序解析提取数据
序列化(serialization)
只有自己写的JAVA程序用到存储的数据时,使用序列化
序列化将整个对象写入到文件中,该对象引用的实例变量、所有被引用的对象都会被序列化
创建一个可以被序列化的类
只有实现了Serializable接口的类可以被序列化(实际上Serializable没有任何方法需要实现,它的目的只是声明这个类是可以被序列化的)
实现了Serializable接口的类,它的子类也是都可以被序列化的
需要import java.io.Serializable
例如:
import java.io.Serializable;
public class Box implements Serializable{
private int width;
private int height;
transient int size;\\transient关键字,标识该实例变量不会被序列化
private Duck duck =new Duck();
public void setWidth(int w){
width=w;
}
public void setHeight(int h){
height=h;
}
}
实例变量width和height、duck的值,在序列化时值会被保存
实例变量size不会被序列化,因为用transient关键字的实例变量不进行序列化,会以null等默认值返回(有可能有些引用变量作者没有进行序列化,或者某些字段没有序列化的意义)
序列化是全有或全无的,一部分序列化失败了就不会保存:如果实例变量的引用对象duck,如果类Duck没有实现序列化的话,当前类也不能被序列化,否则会报错
序列化的步骤
第一步:创建FileOutputStream,FileOutputStream把字节写入文件
FileOutputStream fs = new FileOutputStream("foo.ser”);\\如果文件footsore不存在,会自动创建该文件
第二步:创建ObjectOutputStream,ObjectOutputStream把对象转换成可以写入串流的数据
ObjectOutputStream os = new ObjectOutputStream(fs);\\fs是一个FileOutputStream对象
第三步:写入对象,ObjectOutputStream调用writeObject方法把对象打成串流送到FileOutputStream来写入文件
os.writeObject(myBox);\\myBox必须是一个实现了Serializable接口的类,是可以序列化的
第四步:关闭ObjectOutputStream
os.close();\\关闭所关联的输出串流
反序列化【解序列化】(Deserialization):还原对象
序列化的反向操作,将对象恢复到存储时的状态,transient的变量不会恢复当时的状态,只会恢复成默认值,例如null。如果是不可序列化的类,会重新执行构造函数。序列化的类不会执行构造函数,会将新对象放到对上。
对象是从stream中读出来的,Java虚拟机通过存储信息判断要恢复的对象class的类型,如果找不到或无法加载该类,会抛出异常。
解序列化的步骤:
第一步:创建FileInputStream,读取文件字节,如果文件不存在会抛出异常
FileInputStream fileStream = new FileInputStream("foo.ser”);\\如果文件不存在,会抛出异常
第二步:创建ObjectInputStream,将自己转换成对象的stream
ObjectInputStream os=new ObjectInputStream(fileStream);
第三步:读取对象,会按照os.writeObject(xx)存储的顺序读取,与写入顺序相同
Object one=os.readObject();
Object two=os.readObject();
第四步:转换对象类型。默认返回的是Object类型,需要强转换为存储时的类型
GamecCharacter test1=(GameCharacter) one;
GamecCharacter test2=(GameCharacter) two;
第五步:关闭ObjectInputStream
serialVersionUID
用来解序列化还原时比对,是否和当前Java虚拟机上的类的UID一致,如果版本不符就会在还原过程中抛出异常。
查询类的serialVersionUID:在Java Development Kit中使用命令【serialver 类名】查询
具体步骤如下,例如java文件为Box.java,进入java文件目录,通过javac xxx.java把文件编译为.class文件,然后通过serialver xxx查询
如果完全想自己控制,可以将serialVersionUID写在class类中,但是这种就需要自己去承担类变动后,还原的对象一些实例变量可能不符的后果
使用方法如下:
public class Dog{
static final long serialVersionUID=xxxxxx;
//其他代码
}
这种情况如果后续类新增了字段或实例,反序列化时会将新增的字段初始为默认值
序列化总结的一些点
可以通过序列化来保存对象的状态
Stream是连接串流(表示源和目的地)或链接用的串流(衔接连接串流,例如从FileOutputStream到ObjectOutputStream)
只有实现了序列化接口的类才可以被序列化,所有实例都会被序列化(除非用来transient关键词会跳过)
静态变量不会被序列化,每个类共享一个静态变量
文件的输入输出
有时候需要把对象的状态存储为单纯文件,来提供给其他非JAVA得应用程序,所以这里讲了文件的输入和输出
java.io.File class
File这个类代表磁盘上的文件,但是不是文件的内容。可以把它想象成文件路径
File的简单应用
1.创建代表现存盘文件的File对象
File f = new File(“xxxx/mycode.txt”)
2.建立新的目录
File dir = new File(“chapter")
缓冲区
可以理解为购物车,为了省去磁盘操作的时间,,可以提高IO读写的效率
BufferedReader和BufferedWrite各被分配了8192个字的缓冲区
BufferedWrite:使用缓冲区来进行写操作,文件不会直接写入磁盘,而是先写入到缓冲区,当缓冲区满了时一次性写入到磁盘,减少直接操作磁盘的次数,提高效率。或者通过write.flush()来强制缓存区立即写入
用法:
只通过FileWrite写入的方法:
File fs=new File(“filename”);
FileWriter fw=new FileWriter(fs);
fs.write(“xxx”);
通过缓冲区进行写入的方法:
File fs=new File(“filename”);
FileWriter fw=new FileWriter(fs);
BufferedWrite bw=new BufferedWrite(fw);
bw.write(“xxx”);
BufferedReader:将FileReader链接到BufferedReader也会提升效率,BufferedReader会将文件读入的字节置入缓冲区。当以后使用read()等操作进行读时,会先从缓存中读取,当缓存中为空时再从文件中直接读取
用法:
File fs=new File(“filename”);
FileReader fr=new FileReader(fs);
BufferedReader br=new BufferedReader(fr);
while(br.readeLine() != null){//下面就是读取每一行的文件并打印了
System.out.println(br.readeLine() );
}
- java基础三 [深入多态,接口和多态](阅读Head First Java记录)
抽象类和抽象方法 1.抽象类的声明方法,在前面加上抽象类的关键词abstract abstract class canine extends animal{ public void roam ...
- Java基础八--构造函数
Java基础八--构造函数 一.子父类中构造函数的特点 1.1 为什么在子类构造对象时,发现,访问子类构造函数时,父类也运行了呢? 原因是:在子类的构造函数中第一行有一个默认的隐式语句. super( ...
- qemu:///system 没有连接驱动器可用;读取数据时进入文件终点: 输入/输出错误
原因 1. KVM的相关包 装少了 2KVM的相关包 重新安装 3 May 31 15:22:55 localhost libvirtd: 2019-05-31 07:22:55.554+0000: ...
- Java基础--对象的序列化
所有分布式应用常常需要跨平台,跨网络,因此要求所有传的参数.返回值都必须实现序列化. 比如常见的Dubbo分布式平台,里面的对象实体类必须实现序列化才能在网络间传递 一.定义 序列化:把Java对象转 ...
- java基础十一[远程部署的RMI](阅读Head First Java记录)
方法的调用都是发生在相同堆上的两个对象之间(同一台机器的Java虚拟机),如果想要调用另一台机器上的对象,可以通过Socket进行输入/输出. 远程过程调用需要创建出4种东西:服务器.客户端.服务器辅 ...
- Java基础知识:序列化和反序列化
一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存 ...
- Java基础(八)--String(源码)、StringBuffer、StringBuilder
String源码:基于jdk1.8 public final class String implements Serializable, Comparable<String>, CharS ...
- Java基础(八)
IO流 概述与分类 Java中的IO流技术主要用于传输数据.典型的应用场景有:读写本地文件,上传下载文件等.按照数据传输的方向可以分为两种: l 输入流(Input):既让数据进入应用程序中. l ...
- Java基础之使用Scanner类获取用户输入
创建 Scanner 对象的基本语法: Scanner s = new Scanner(System.in); Scanner 类的 next() 方法 import java.util.Scanne ...
随机推荐
- DHCP服务器安装及配置
一.什么是DHCP? DHCP (Dynamic Host Configuration protocol)动态主机设置协议,基于UDP(发送很小的数据报文,且对时效性要求较高)协议通信. 它是C/S架 ...
- .NET垃圾回收:非托管资源,IDispose和析构函数的结合
http://blog.jobbole.com/85436/ 原文出处: 田小计划 欢迎分享原创到伯乐头条 前面一篇文章介绍了垃圾回收的基本工作原理,垃圾回收器并不是可以管理内存中的所有资源.对于 ...
- 设计模式-UML类图的各符号含义(转)
UML类图的各符号含义 类图基本符号可拆分为虚线,箭头,实线,空心右三角,实心右三角,空心菱形和实心菱形.由这些基本的图形进行组合构成了类图的基本符号.这里要注意这几个符号的顺序,代表了类与类之间关系 ...
- linux IO调度
I/O 调度算法再各个进程竞争磁盘I/O的时候担当了裁判的角色.他要求请求的次序和时机做最优化的处理,以求得尽可能最好的整体I/O性能.在linux下面列出4种调度算法CFQ (Completely ...
- ACM_ICPC hdu-2111(简单贪心算法)
一道非常简单的贪心算法,但是要注意输入的价值是单位体积的价值,并不是这个物品的总价值!#include <iostream> #include <stdio.h> #inclu ...
- pandas入门
[原]十分钟搞定pandas 本文是对pandas官方网站上<10 Minutes to pandas>的一个简单的翻译,原文在这里.这篇文章是对pandas的一个简单的介绍,详细的介 ...
- 计算机视觉:关于视觉算法源码中常出现的imageLib库的使用指南
1.ReadImage(CImage &im, char* path)/ WriteImage(CImage &im, char* path) (1)将im强制转换为CByteImag ...
- 在excel 中某一单元格添加指定字符的示例
="select TestSurveyID,'http://www.findoout.cn/survey/viewsurvey.aspx?tid='+CONVERT(varchar(10), ...
- 【VB.NET】文本框快捷键支持
我们知道VB.NET中的文本框是不支持Ctrl+A的快捷键的. 如果让它支持呢? Private Sub txtSQL_KeyDown(ByVal sender As Object, ByVal e ...
- 转载自@机智的新手:使用Auto Layout中的VFL(Visual format language)--代码实现自动布局
本文将通过简单的UI来说明如何用VFL来实现自动布局.在自动布局的时候避免不了使用代码来加以优化以及根据内容来实现不同的UI. 一:API介绍 NSLayoutConstraint API 1 2 3 ...