碎碎念
内容基本是尚硅谷的视频笔记和ppt内容的整理。叽几的内容只有:蓝色字体的思考分析 + 手写的一些图示。怕涉及到侵权问题,就把链接放在开头高亮!!链接:https://pan.baidu.com/s/1fJIiEhG-NCfgWhn-eyRtZA 提取码:dqvy
说实话到四点的时候真的想放弃了,还差最后一个处理流,想拖到第二天来着。后来想想算了,学完再睡心里比较爽。
一、处理流之一:缓冲流
1.缓冲流
缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为:
① BufferedInputStream 和 ② BufferedOutputStream
③ BufferedReader 和 ④ BufferedWriter
2.作用
- 作用: 提高了数据的读写速度
- 原因: 提供了8192个字节(8Kb)的缓冲区。
3.非文本文件的复制
@Test
public void BufferedStreamTest() throws FileNotFoundException {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File("爱情与友情.jpg");
File destFile = new File("爱情与友情3.jpg");
//2.造流
//2.1 造节点流
FileInputStream fis = new FileInputStream((srcFile));
FileOutputStream fos = new FileOutputStream(destFile);
//2.2 造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节:读取、写入
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
// bos.flush();//刷新缓冲区
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
// fos.close();
// fis.close();
}
}
分析:① 步骤: 总体步骤和节点流一样。造文件 → 造流 → 复制 → 资源关闭,然后再用try-catch-finally包起来。处理流是在节点流的“包装”下进行的,所以和节点流的区别只是在节点流的基础上“套”了一层流(bis = new BufferedInputStream(fis); 和 bos = new BufferedOutputStream(fos);)。
② 刷新: bos.flush();//刷新缓冲区,有自动刷新,可以不用写
③ 关闭:在关闭流的时候,要先关闭外层的流,再关闭内层的流,而同级别的两个流的关闭顺序不分先后。注意:在关闭外层流的同时,内层流也会自动的进行关闭,所以关于内层流的关闭可以省略。
4.文本文件的复制
@Test
public void testBufferedReaderBufferedWriter(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件和相应的流
br = new BufferedReader(new FileReader(new File("dbcp.txt")));
bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));
//读写操作
//方式一:使用char[]数组————char(char[] cbuf)
// char[] cbuf = new char[1024];
// int len;
// while((len = br.read(cbuf)) != -1){
// bw.write(cbuf,0,len);
// // bw.flush();
// }
//方式二:使用String————readLine()一次读一行
String data;
//为什么不等于null,就是
while((data = br.readLine()) != null){
//方法一:
// bw.write(data + "\n");//data中不包含换行符
//方法二:
bw.write(data);//data中不包含换行符
bw.newLine();//提供换行的操作
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br != null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
分析:
- ① 步骤: 总体步骤和上面非文本文件的复制一样。但是在这个程序中,在造文件和造流两步合为一体(匿名)。
- ② 读写操作: 文本文件的“char”对应着非文本文件的“byte”。但文本文件还有别的读取方法,也就是String。本来两方在循环的时候用数组char(char[] cbuf) 和 byte(byte[] cbuf),文本文件还可以用readLine(一次读取一行,是String类型的)。
- 源码中对于一行结束的判定: 要么返回当前这一行的数据不包含换行符<因为没有换行符,所以不会自动换行,要手动添加>,或者是到文件末尾返回null 所以:
- 1.循环的判定条件为 —— (data = br.readLine()) != null
- 2.要手动添加换行符
- 第一种方式:加换行符 —— + “\n”
- 第二种方式:提供换行的方法 —— bw.newLine();
- 源码中对于一行结束的判定: 要么返回当前这一行的数据不包含换行符<因为没有换行符,所以不会自动换行,要手动添加>,或者是到文件末尾返回null 所以:
5.练习
5.1对文件的加密解密
① 程序:为了观看整洁,省去了对程序的异常处理,具体处理看之前的代码。
--------------------加密--------------------
//1.创建流,流里面放需要加密的文件和目标文件
FileInputStream fis = new FileInputStream("爱情与友情.jpg");
FileOutputStream fos = new FileOutputStream("爱情与友情secret.jpg");
//2.读取数据,一边遍历读取,一边对数据进行运算从而实现加密
byte[] buffer = new byte[20];
int len;
while ((len = fis.read(buffer)) != -1) {
//字节数组进行修改
//错误的
// for(byte b : buffer){
// b = (byte) (b ^ 5);
// }
//正确的
for (int i = 0; i < len; i++) {
buffer[i] = (byte) (buffer[i] ^ 5);
}
fos.write(buffer, 0, len);
}
//3.关闭资源
fos.close();
fis.close();
--------------------解密--------------------
//因为加密时用了亦或运算,所以在解密时,只需输入输出倒换一下即可
FileInputStream fis = new FileInputStream("爱情与友情secret.jpg");
FileOutputStream fos = new FileOutputStream("爱情与友情4.jpg");
//以下步骤不变,省略
② 思路
- 加密——在循环遍历读取文件时,可以进行一些操作,比如:亦或运算,此时数据都被移位,无法正确复制,但大小是一样的。
- 解密——解密就是将加密过的文件还原,方法如下(针对加密的亦或运算来说):
- 因为加密时:是将原文件进行运算(此处用了亦或运算)得到目标文件。
- 所以解密时:只要在创建输入流和输出流文件倒换一下即可,其余步骤不变。
③ 注意点
- ① 不能使用加强for循环。因为这种循环,不会改变原有的数据,会将改动的数据赋给新的数组上。
- ② 要有byte类型的强转。因为buffer是byte型的,在和int做运算时,会自动转化成int型。而输入输出的数据应该为byte型,所以要强转。
5.2 获取每个字符出现的次数
① 程序:知识点都讲过,自己要看懂它。
public class WordCount {
@Test
public void testWordCount() {
FileReader fr = null;
BufferedWriter bw = null;
try {
//1.创建Map集合
Map<Character, Integer> map = new HashMap<Character, Integer>();
//2.遍历每一个字符,每一个字符出现的次数放到map中
fr = new FileReader("dbcp.txt");
int c = 0;
while ((c = fr.read()) != -1) {
//int 还原 char
char ch = (char) c;
// 判断char是否在map中第一次出现
if (map.get(ch) == null) {
map.put(ch, 1);
} else {
map.put(ch, map.get(ch) + 1);
}
}
//3.把map中数据存在文件count.txt
//3.1 创建Writer
bw = new BufferedWriter(new FileWriter("wordcount.txt"));
//3.2 遍历map,再写入数据
Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
for (Map.Entry<Character, Integer> entry : entrySet) {
switch (entry.getKey()) {
case ' ':
bw.write("空格=" + entry.getValue());
break;
case '\t'://\t表示tab 键字符
bw.write("tab键=" + entry.getValue());
break;
case '\r'://
bw.write("回车=" + entry.getValue());
break;
case '\n'://
bw.write("换行=" + entry.getValue());
break;
default:
bw.write(entry.getKey() + "=" + entry.getValue());
break;
}
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关流
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
② 总结: 遍历文本的每一个字符;字符及出现的次数保存在Map中;将Map中数据写入文件。
③ 说明: 如果使用单元测试,文件相对路径为当前module。如果使用main()测试,文件相对路径为当前工程。
6.说明
- 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区
- 当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。
- 向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法flush()可以强制将缓冲区的内容全部写入输出流
- 关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也会相应关闭内层节点流
- flush()方法的使用:手动将buffer中内容写入文件
- 如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷新缓冲区,关闭后不能再写出
二、处理流之二:转换流
1.概念
① 转换流: 提供了在字节流和字符流之间的转换,属于字符流
InputStreamReader: 将一个字节的输入流转换为字符的输入流(将InputStream 转换为Reader)
OutputStreamWriter: 将一个字符的输出流转换为字节的输出流( 将Writer 转换为OutputStream)
② 功能: 字节流中的数据都是字符时,转成字符流操作更高效,很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
解码: 字节、字节数组 —>字符数组、字符串
编码: 字符数组、字符串 —> 字节、字节数组
2.InputStreamReader
-
实现将字节的输入流按指定字符集转换为字符的输入流。
-
需要和InputStream“套接”。
-
构造器
- public InputStreamReader(InputStream in)←使用默认的字符集
- public InputSreamReader(InputStream in,String charsetName)
如: Reader isr = new InputStreamReader(System.in,”gbk”);←这里的gbk就是制定的字符集。
-
InputStreamReader的使用
//此时还是应该用try-catch-finally,用throws纯属因为整洁
public void test1() throws IOException {
//
FileInputStream fis = new FileInputStream("dbcp.txt");
//InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
//参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.print(str);
}
isr.close();
}
3.OutputStreamWriter
- 实现将字符的输出流按指定字符集转换为字节的输出流。
- 需要和OutputStream“套接”。
- 构造器
- public OutputStreamWriter(OutputStream out)
- public OutputSreamWriter(OutputStream out,String charsetName)
- 综合使用InputStreamReader和OutputStreamWriter
//此时还是应该用try-catch-finally,用throws纯属因为整洁
@Test
public void test2() throws Exception {
//1.造文件、造流
File file1 = new File("dbcp.txt");
File file2 = new File("dbcp_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
//2.读写过程
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}
//3.关闭资源
isr.close();
osw.close();
}
补充:字符编码
1.由来
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。
2.常见编码表
① ASCII: 美国标准信息交换码。用一个字节的7位可以表示。
② ISO8859-1: 拉丁码表。欧洲码表用一个字节的8位表示。
③ GB2312: 中国的中文编码表。最多两个字节编码所有字符
④ GBK: 中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码。
⑤ Unicode: 国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示。
⑥ UTF-8: 变长的编码方式,可用1-4个字节来表示一个字符。修正后,一个字符可用6个字节表示
注意:
GBK等双字节编码方式,用最高位是1或0表示两个字节和一个字节。
在Unicode 出现之前,所有的字符集都是和具体编码方案绑定在一起的(即字符集≈ 编码方式),都是直接将字符和最终字节流绑定死了。
3.Unicode的问题及解决
- Unicode不完美,这里就有三个问题,一个是,我们已经知道,英文字母只用一个字节表示就够了,第二个问题是如何才能区别Unicode和ASCII?计算机怎么知道两个字节表示一个符号,而不是分别表示两个符号呢?第三个,如果和GBK等双字节编码方式一样,用最高位是1或0表示两个字节和一个字节,就少了很多值无法用于表示字符,不够表示所有字符。Unicode在很长一段时间内无法推广,直到互联网的出现。
- 面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。
- Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。 推荐的Unicode编码是UTF-8和UTF-16。
4.实现方式
三、处理流之三:标准输入、输出流(了解)
1.概念
- System.in:标准的输入流,默认从键盘输入
System.out:标准的输出流,默认从控制台输出
默认输入设备是:键盘,输出设备是:显示器 - System.in的类型是InputStream
System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream 的子类 - 重定向:通过System类的setIn,setOut方法对默认设备进行改变。
- public static void setIn(InputStream in)
- public static void setOut(PrintStream out)
2.练习
2.1 键盘输入,读字符停止
① 题目: 从键盘输入字符串,要求将读取到的整行字符串转成大写输出。然后继续进行输入操作,直至当输入“e”或者“exit”时,退出程序。
② 方法:
方法一:使用Scanner实现,调用next()返回一个字符串
方法二:使用System.in实现。System.in —> 转换流 —> BufferedReader的readLine()
③ 程序:
注意:IDEA不支持在单元测试下的键盘输入
public static void main(String[] args) {
BufferedReader br = null;
try {
//1.创建转换流、缓冲流
InputStreamReader isr = new InputStreamReader(System.in);
br = new BufferedReader(isr);
while (true) {
System.out.println("请输入字符串:");
String data = br.readLine();
if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
System.out.println("程序结束");
break;
}
String upperCase = data.toUpperCase();
System.out.println(upperCase);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.2 造一个类似Scanner类
① 题目: Create a program named MyInput.java: Contain the methods for reading int,double, float, boolean, short, byte and String values from the keyboard.
② 错误方法: 不能直接将Scanner直接包成一个类这没有意义。程序如下,不要这么写。
class MyInput{
Scanner s = new Scanner(System.in);
public String readString(){
return s.next();
}
….
}
③ 正确方法: 应该要使用流来处理
import java.io.*;
public class MyInput {
// Read a string from the keyboard
public static String readString() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// Declare and initialize the string
String string = "";
// Get the string from the keyboard
try {
string = br.readLine();
} catch (IOException ex) {
System.out.println(ex);
}
// Return the string obtained from the keyboard
return string;
}
// Read an int value from the keyboard
public static int readInt() {
return Integer.parseInt(readString());
}
// Read a double value from the keyboard
public static double readDouble() {
return Double.parseDouble(readString());
}
// Read a byte value from the keyboard
public static double readByte() {
return Byte.parseByte(readString());
}
// Read a short value from the keyboard
public static double readShort() {
return Short.parseShort(readString());
}
// Read a long value from the keyboard
public static double readLong() {
return Long.parseLong(readString());
}
// Read a float value from the keyboard
public static double readFloat() {
return Float.parseFloat(readString());
}
}
四、处理流之四:打印流(了解)
1.概念
- 实现将 基本数据类型 的数据格式转化为 字符串 输出
- 打印流:PrintStream和PrintWriter
- 提供了一系列重载的print()和println()方法,用于多种数据类型的输出
- PrintStream和PrintWriter的输出不会抛出IOException异常
- PrintStream和PrintWriter有自动flush功能
- PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
- System.out返回的是PrintStream的实例
2.练习
public void test2() {
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区),这里的true是会不会自动刷新缓冲区
ps = new PrintStream(fos, true);
if (ps != null) {// 把标准输出流(控制台输出)改成文件
System.setOut(ps);
}
for (int i = 0; i <= 255; i++) { // 输出ASCII字符
System.out.print((char) i);
if (i % 50 == 0) { // 每50个数据一行
System.out.println(); // 换行
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}
}
五、处理流之五:数据流(了解)
1.概念
- ① 数据流有两个类: (用于读取和写出基本数据类型、String类的数据)
DataInputStream 和 DataOutputStream
分别“套接”在 InputStream 和 OutputStream子类的流上 - ② 作用: 用于读取或写出基本数据类型的变量或字符串
- ③ DataInputStream中的方法:
- boolean readBoolean() byte readByte()
char readChar() float readFloat()
double readDouble() short readShort()
long readLong() int readInt()
String readUTF() void readFully(byte[] b)
- boolean readBoolean() byte readByte()
- ④ DataOutputStream中的方法:
- 将上述的方法的read改为相应的write即可。
2.练习
2.1 写到文件
① 写入: 将内存中的字符串、基本数据类型的变量写出到文件中。
② 注意: 处理异常的话,仍然应该使用try-catch-finally。
@Test
public void test3() throws IOException {
//1.创建流
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
//2.写
dos.writeUTF("刘建辰");
dos.flush();//刷新操作,将内存中的数据写入文件
dos.writeInt(23);
dos.flush();
dos.writeBoolean(true);
dos.flush();
//3.关闭资源
dos.close();
}
2.2 读取文件
① 读取: 将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。
② 注意点: 读取不同类型的数据的顺序要与当初写入文件时,保存的数据的顺序一致!
@Test
public void test4() throws IOException {
//1.创建流
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
//2.读取
String name = dis.readUTF();
int age = dis.readInt();
boolean isMale = dis.readBoolean();
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("isMale = " + isMale);
//3.关闭资源
dis.close();
}
六、处理流之六:对象流
1.概念
- ObjectInputStream 和 OjbectOutputSteam
用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。 - 序列化过程: 将内存中的java对象保存到磁盘中或通过网络传输出去。使用ObjectOutputStream实现
- 反序列化: 将磁盘文件中的对象还原为内存中的一个java对象。使用ObjectInputStream来实现
- ObjectOutputStream 和 ObjectInputStream不能序列化static和transient修饰的成员变量
2.对象的序列化
2.1概念
- 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
- 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原
- 序列化是 RMI(Remote Method Invoke – 远程方法调用)过程的参数和返回值都必须实现的机制,而 RMI 是 JavaEE 的基础。因此序列化机制是JavaEE 平台的基础
- 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一。否则,会抛出NotSerializableException异常
- Serializable
- Externalizable
2.2 serialVersionUID的理解
- 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量:
- private static final long serialVersionUID;
- serialVersionUID用来表明类的不同版本间的兼容性。 简言之,其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
- 如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
- 简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)
3.序列化
- ① 步骤: 若某个类实现了 Serializable 接口,该类的对象就是可序列化的
- 创建一个 ObjectOutputStream
- 调用 ObjectOutputStream 对象的 writeObject(对象) 方法输出可序列化对象
- 注意写出一次,操作flush()一次
- ② 程序:
@Test
public void testObjectOutputStream(){
ObjectOutputStream oos = null;
try {
//1.创建流
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
//2.写入
oos.writeObject(new String("我爱北京天安门"));
oos.flush();//刷新操作
oos.writeObject(new Person("王铭",23));
oos.flush();
oos.writeObject(new Person("张学良",23,1001,new Account(5000)));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null){
//3.关闭流
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.反序列化
- ① 步骤:
- 创建一个 ObjectInputStream
- 调用 readObject() 方法读取流中的对象
- ② 程序:
public void testObjectInputStream(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String) obj;
Person p = (Person) ois.readObject();
Person p1 = (Person) ois.readObject();
System.out.println(str);
System.out.println(p);
System.out.println(p1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.自定义类实现序列化反序列化
5.1 要求
Person需要满足如下的要求,方可序列化
- ① 需要实现接口:Serializable
- ② 当前类提供一个全局常量:serialVersionUID(必须要自己给一个long类型 值)
- ③ 除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
5.2 程序
- 自定义Person类如下所示
- 具体的实现写在上面的程序中
//① 需要实现接口:Serializable
public class Person implements Serializable{
//② 当前类提供一个全局常量:serialVersionUID
public static final long serialVersionUID = 475463534532L;
private String name;
private int age;
private int id;
//③ 除了当前Person类需要实现Serializable接口之外,
//还必须保证其内部所有属性也必须是可序列化的。
//所以Accunt类也得是可序列化的
private Account acct;
//get set方法省略
public Person(String name, int age, int id, Account acct) {
this.name = name;
this.age = age;
this.id = id;
this.acct = acct;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
", acct=" + acct +
'}';
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
}
class Account implements Serializable{
public static final long serialVersionUID = 4754534532L;
private double balance;
@Override
public String toString() {
return "Account{" +
"balance=" + balance +
'}';
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public Account(double balance) {
this.balance = balance;
}
}