1 文件的编码
1.1 文件的编码
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = "慕课ABC";
/**
* 转换成字节序列利用的是项目默认的编码,
* eclipse查看项目默认编码的方式:点击项目->右击Properties->Resource->Text file encoding
* 项目编码也可以显示的指定:byte[] bytes = s.getBytes("gbk");
*/
byte[] bytes1 = s.getBytes();
for(byte b:bytes1) {
// 把字节转换为int,以16进制的方式显示
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
System.out.println();
try {
byte[] bytes2 = s.getBytes("gbk");
/**
* gbk编码中文占2个字节,英文占1个字节
*/
for(byte b:bytes2) {
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println();
try {
byte[] bytes3 = s.getBytes("utf-8");
/**
* 在utf-8编码中,中文占用3个字节,英文占用1个字节
*/
for(byte b:bytes3) {
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println();
byte[] bytes4 = null;
try {
/**
* 在utf-16be中,中文和英文都占用2个字节
*/
bytes4 = s.getBytes("utf-16be");
for(byte b:bytes4) {
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println();
/**
* 字节序列转化为字符串时,当你的字节序列的编码方式与项目默认编码方式不同时,
* 这个时候需要手动添加编码方式进行转换,
* 否则会出现乱码
*
*/
String str1 = new String(bytes4);
System.out.println(str1);
try {
String str2 = new String(bytes4,"utf-16be");
System.out.println(str2);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* eclipse中什么编码的项目只认识什么编码的文件,
* 将一个项目的文件拷贝到另一个编码方式不同的项目中,就会出现乱码,
* 这就是直接拷贝别人项目文件出现乱码的原因
*/
/**
* 文本文件 就是字节序列
* 可以是任意编码的字节序列
* 如果我们在中文机器上直接创建文本文件,那么该文本文件只认识ansi编码
*/
}
2 File 类的使用
2.1 File 类常用 API 介绍
java.io.File 类用于表示文件(目录)
File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问
public static void main(String[] args) {
// TODO Auto-generated method stub
/**
* eclipse中用 Alt+/ 来查看File的构造函数,
* 文件分割符可以用 \\ 或者 / 或者 File.separator,
* File.separator不论win系统还是linux系统,都表示分割符
*/
File file = new File("D:\\javaio");
System.out.println(file.exists()); // 判断文件是否存在
if(!file.exists()) {
file.mkdir(); // 创建一级目录
file.mkdirs(); // 如果文件不存在,创建多级目录
}else {
file.delete(); // 如果文件存在,删除目录
}
/**
* 判断是否是一个目录 ,
* 如果是目录返回true,如果不是目录或者不存在返回false
*/
System.out.println(file.isDirectory());
// 判断是否是一个文件
System.out.println(file.isFile());
/**
* 创建文件
*/
File file2 = new File("d:\\javaio\\日记1.txt");
File file3 = new File("d:\\javaio","日记2.txt");
if(!file2.exists()) {
try {
file2.createNewFile(); // 文件不存在,创建这个文件
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
file2.delete(); // 文件存在删除文件
}
// 常用的File对象的API
System.out.println(file); // 打印file.toString()的内容
System.out.println(file.getAbsolutePath()); // 打印路径
System.out.println(file.getName()); // 打印目录名
System.out.println(file2.getName()); // 打印文件名
System.out.println(file.getParent()); // 返回父目录路径
System.out.println(file2.getParent()); // 返回父目录路径
System.out.println(file.getParentFile().getAbsolutePath()); // 返回父目录路径
}
2.2 遍历目录
package com.amoscxy;
import java.io.File;
import java.io.IOException;
/**
* 列出File的一些常用操作比如过滤、遍历等操作
* @author BG235144
*
*/
public class FileUtils {
/**
* 列出指定目录下(包括其子目录)的所有文件
* @param dir
* @throws IOException
*/
public static void listDirectory(File dir) throws IOException{
if(!dir.exists()) {
throw new IllegalArgumentException("目录:"+dir+"不存在");
}
if(!dir.isDirectory()) {
throw new IllegalArgumentException(dir+"不是目录");
}
/**
* 返回的是字符串数组,
* 不包含子目录下的内容
*/
// String[] filenames = dir.list();
// for(String filename:filenames) {
// System.out.println(dir+"\\"+filename);
// }
/**
* 如果要遍历子目录下的内容就要构造成File对象做递归操作,
* File提供了直接返回File对象的api,
* 返回的是直接子目录(文件)的对象
*/
File[] files = dir.listFiles();
// for(File file:files) {
// System.out.println(file);
// }
if(files!=null && files.length>0) {
for(File file:files) {
if(file.isDirectory()) {
/**
* 递归
*/
listDirectory(file);
}else {
System.out.println(file);
}
}
}
}
}
3 RandomAccessFile类的使用
3.1 RandomAccessFile基本操作
RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,可以访问文件的任意位置
RandomAccessFile 读写过程:
1. Java文件模型:
在硬盘上的文件是byte byte byte存储,是数据的集合
2. 打开文件:
有两种模式”rw”(读写)”r”(只读)
RandomAccessFile raf = new RandomAccessFile(file,”rw”);
文件指针,pointer = raf.getFilePointer(),
打开文件时指针在开头 pointer = 0;
3. 写方法:
raf.write(int)—>只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
4. 读方法:
文件读写完成以后一定要关闭(oracle官方说明)
public static void main(String[] args) throws IOException{
File demo = new File("D:\\javaio");
if(!demo.exists()) {
demo.mkdir();
}
File file = new File(demo,"raf.dat");
if(!file.exists()) {
file.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(file,"rw");
// 指针位置
System.out.println(raf.getFilePointer());
/**
* java中char是2个字节,
* 只写最后边一个字节进去
*/
raf.write('A');
System.out.println(raf.getFilePointer());
raf.write('B');
/**
* 用write方法每次只能写一个字节,
* 如果要把i写进去就得写4次
*/
int i = 0x7fffffff;
raf.write(i>>>24); // 高8位
raf.write(i>>>16);
raf.write(i>>>8);
raf.write(i);
System.out.println(raf.getFilePointer());
// 可以直接写一个int
raf.writeInt(i);
/**
* 可以直接写一个中文汉子,
*/
String s = "中";
byte[] gbk = s.getBytes("gbk");
/**
* 可以写入字节数组
*/
raf.write(gbk);
System.out.println(raf.length());
/**
* 读文件,必须把指针移到头部
*/
raf.seek(0);
/**
* 一次性读取,把文件中的内容都读到字节数组中
*/
byte[] buf = new byte[(int)raf.length()];
raf.read(buf);
System.out.println(Arrays.toString(buf));
String s1 = new String(buf,"gbk");
System.out.println(s1);
/**
* 以16进制方式输出
*/
for(byte b:buf) {
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
/**
* 关闭
*/
raf.close();
}
输出
0
1
6
12
[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
AB������中
41 42 7f ff ff ff 7f ff ff ff d6 d0
4 字节流
4.1 字节流之文件输入流FileInputStream-1
public class IOUtil {
/**
* 读取指定文件内容,按照16进制输出到控制台,
* 并且每输出10个byte换行
* @param fileName
*/
public static void printHex(String fileName) throws IOException{
/**
* 把文件作为字节流进行读操作
*/
FileInputStream in = new FileInputStream(fileName);
int b;
int i = 1;
/**
* 文件读,
* 判断文件读结束
*/
while((b = in.read())!=-1) {
if(b<=0xf) {
// 单位数前面补0
System.out.println("0");
}
// 将整数b转换为16进制表示的字符串
System.out.print(Integer.toHexString(b) + " ");
if(i++%10 == 0) {
System.out.println();
}
}
in.close();
}
}
4.2 字节流之文件输入流FileInputStream-2
/**
* 从int中批量读取字节,放入到buf这个字节数组中,
* 从第0个位置开始放,最多放buf.length个,
* 返回的是读到的字节个数
*/
public static void printHexByByteArray(String fileName) throws IOException{
FileInputStream in = new FileInputStream(fileName);
/**
* 适宜大小,直到读取全部文件为止
*/
byte[] buf = new byte[8*1024];
int bytes = 0;
int j = 1;
while((bytes = in.read(buf,0,buf.length))!=-1) {
for(int i = 0; i < bytes; i ++) {
if((buf[i] & 0xff) <= 0xf) {
System.out.print("0");
}
/**
* byte类型8位,int类型32位,
* 为避免数据转换错误,通过&0xff将高位24位请零
*/
System.out.print(Integer.toHexString(buf[i] & 0xff)+" ");
if(j++%10 == 0) {
System.out.println();
}
}
}
}
4.3 字节流之文件输出流FileOutputStream
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
/**
* 参数一:文件
* 参数二:是否在文本后面追加
*/
FileOutputStream out = new FileOutputStream("D:\\javaio\\out.dat",true);
out.write('A'); // 写出了'A'的低8位
out.write('B'); // 写出了'B'的低8位
int a = 10; // write 只能写低8位,那么写一个int需要写4次
out.write(a>>>24); // 写入高8位
out.write(a>>>16);
out.write(a>>>16);
out.write(a);
byte[] gbk = "中国".getBytes("gbk");
out.write(gbk); // 可以写出字符数组
out.close();
}
/**
* 拷贝文件
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFile(File srcFile,File destFile) throws IOException {
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
if(!destFile.exists()) {
destFile.createNewFile();
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
/**
* 适当的大小,
* 一次一次中转文件,
* 知道文件全部拷贝为止
*/
byte[] buf = new byte[8*1024];
int b;
while((b = in.read(buf, 0, buf.length))!=-1) {
out.write(buf, 0, b);
out.flush(); // 最好加上
}
in.close();
out.close();
}
4.4 字节流之数据输入输出流
DataOutputStream/DataInputStream
对“流”功能的扩展,可以更加方便的读取int,long,字符等类型数据 DataOutputStream
writeInt()/writeDouble()/writeUTF()
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
String file = "D:\\javaio\\dos.dat";
/**
* FileOutputStream 包装成 DataOutputStream 目的就是为了用它的 write 方法,
* 写出基本数据类型的时候更加方便
*/
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10l);
dos.writeDouble(10.5);
// 采用 utf-8 编码写出
dos.writeUTF("中国");
// 采用 utf-16be 编码写出
dos.writeChars("中国");
dos.close();
/**
* FileInputStream 包装成 DataInputStream 目的就是为了用 read 方法,
* 读取基本数据类型的时候更加方便
*/
DataInputStream dis = new DataInputStream(new FileInputStream(file));
int i = dis.readInt();
System.out.println(i);
i = dis.readInt();
System.out.println(i);
long j = dis.readLong();
System.out.println(j);
double h = dis.readDouble();
System.out.println(h);
String k = dis.readUTF();
System.out.println(k);
dis.close();
}
4.5 字节缓冲流
8) BufferedInputStream & BufferedOutputStream 这两个流类为 IO 提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了 IO 的性能,从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
FileOutputStream —> write() 方法相当于一滴一滴地把水“转移”过去,
DataOutputStream—>writeXxx() 方法会方便一些,相当于一瓢一瓢把水“转移”过去,
BufferedOutputStream—>write()方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入缸中
FileInputStream/FileOutputStream(需要时间:20多万ms)
单字节,不带缓冲,进行文件拷贝
/**
* 单字节,不带缓冲,进行文件拷贝
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByByte(File srcFile, File destFile) throws IOException{
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
int c;
while((c = in.read())!=-1) {
out.write(c);
out.flush();
}
in.close();
out.close();
}
文件拷贝,字节批量读取(需要时间:7ms,拷贝文件速度最快)
/**
* 文件拷贝,字节批量读取
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileBybuf(File srcFile,File destFile) throws IOException {
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(destFile);
/**
* 适当的大小,
* 开辟内存,批量读取
* 直到文件全部拷贝为止
*/
byte[] buf = new byte[8*1024];
int b;
while((b = in.read(buf, 0, buf.length))!=-1) {
out.write(buf, 0, b);
out.flush(); // 最好加上
}
in.close();
out.close();
}
DataInputStream/DataOutputStream
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
String file = "D:\\javaio\\dos.dat";
/**
* FileOutputStream 包装成 DataOutputStream 目的就是为了用它的 write 方法,
* 写出基本数据类型的时候更加方便
*/
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10l);
dos.writeDouble(10.5);
// 采用 utf-8 编码写出
dos.writeUTF("中国");
// 采用 utf-16be 编码写出
dos.writeChars("中国");
dos.close();
/**
* FileInputStream 包装成 DataInputStream 目的就是为了用 read 方法,
* 读取基本数据类型的时候更加方便
*/
DataInputStream dis = new DataInputStream(new FileInputStream(file));
int i = dis.readInt();
System.out.println(i);
i = dis.readInt();
System.out.println(i);
long j = dis.readLong();
System.out.println(j);
double h = dis.readDouble();
System.out.println(h);
String k = dis.readUTF();
System.out.println(k);
dis.close();
}
BufferedInputStream/BufferedOutputStream(需要时间10万多ms)
进行文件的拷贝,利用带缓冲的字节流
/**
* 进行文件的拷贝,利用带缓冲的字节流
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByBuffer(File srcFile, File destFile) throws IOException{
if(!srcFile.exists()) {
throw new IllegalArgumentException("文件" + srcFile + "不存在");
}
if(!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile + "不是文件");
}
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
int c;
while((c = bis.read())!=-1) {
bos.write(c);
/**
* 带缓冲,必须刷新缓冲区
*/
bos.flush();
}
bis.close();
bos.close();
}
5 字符流
5.1 字节字符转换流
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流,按照编码处理
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
/**
* 义字符为单位,批量拷贝,
* 有编码的问题,不写为项目默认编码,
* 编码要与文件本身的编码相同,否则会出现乱码问题
*
*/
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:\\javaio\\imooc.txt"),"gbk");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:\\javaio\\imoocgbk"),"gbk");
// int c;
// while((c = isr.read())!=-1) {
// System.out.print((char)c);
// }
char[] buf = new char[8*1024];
int c;
/**
* 批量读取,放入buffer这个字符数组,从第0个位置开始,最多放buf。length个,
* 返回的是读到的字符个数
*/
while((c = isr.read(buf,0,buf.length))!=-1) {
String s = new String(buf,0,c);
System.out.println(s);
osw.write(buf,0,c);
osw.flush();
}
isr.close();
osw.close();
}
5.2 字符流之文件读写流
FileReader/FileWriter
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
/**
* 不能进行编码设置,此时:
* 1. 项目编码与文件编码相同
* 2. 回去用InputStreamReader/OutputStreamWriter,这只编码
*/
FileReader fr = new FileReader("D:\\javaio\\imooc.txt");
/**
* 参数二:true,在文件末尾追加
*/
FileWriter fw = new FileWriter("D:\\javaio\\imooc2.txt",true);
char[] buf = new char[8*1024];
int c;
while((c = fr.read(buf,0,buf.length))!=-1) {
fw.write(buf,0,c);
fw.flush();
}
fr.close();
fw.close();
}
5.3 字符流的过滤器
BufferedReader —> readLine 一次读一行
BufferedWriter/PrintWriter —> 写一行
使用BufferedReader/BufferedWriter
public static void main(String[] args) throws IOException {
// 对文件进行读操作
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\javaio\\imooc.txt"),"gbk"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\javaio\\imooc3.txt"),"gbk"));
String line;
while((line = br.readLine())!=null) {
/**
* 一次读一行,并不能识别换行符
*/
System.out.println(line);
/**
* 一次写入一行,不识别换行
*/
bw.write(line);
/**
* BufferedWriter的换行
*/
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
使用BufferedReader/PrinterWriter
public static void main(String[] args) throws IOException {
// 对文件进行读操作
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\javaio\\imooc.txt"),"gbk"));
PrintWriter pw = new PrintWriter("D:\\javaio\\imooc4.txt","gbk");
/**
* 参数二:自动刷新
*/
// PrintWriter pw2 = new PrintWriter(new FileOutputStream("D:\\javaio\\imooc5.txt"),true);
String line;
while((line = br.readLine())!=null) {
/**
* 一次读一行,并不能识别换行符
*/
System.out.println(line);
/**
* 识别换行符用println
*/
pw.println(line);
pw.flush();
}
br.close();
pw.close();
}
6 对象的序列化和反序列化
6.1 序列化基本操作
对象的序列化、反序列化
1)对象的序列化:将Object转换成byte序列,反之叫对象的反序列化
2)序列化流(ObjectOutputStream),是过滤流,
反序列化流(ObjectInputStream)—> readObject
3)序列化接口(Serializable)
对象必须实现序列化接口,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准
序列化、反序列化
public static void main(String[] args) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
String file = "D:\\javaio\\obj.dat";
/**
* 序列化
*/
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
/**
* 反序列化
*/
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Student stu = new Student("10001","张三",20);
Student stu2;
/**
* 可以写出任意序列化数据
* 文件保存和在网络中传输都要变成字节,都需要序列化,
* Student如果不序列化,就会出现bug,
* Exception in thread "main" java.io.NotSerializableException,没有实现序列化接口
*/
oos.writeObject(stu);
oos.flush();
/**
* 读入任意序列化数据
*/
stu2 = (Student) ois.readObject();
System.out.println(stu2);
oos.close();
}
Student
package com.amoscxy;
import java.io.Serializable;
/**
* 实现了序列化接口
*/
public class Student implements Serializable {
private String stuno;
private String stuname;
private int stuage;
public Student(String stuno, String stuname, int stuage) {
super();
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
}
6.2 transient及ArrayList源码分析
transient修饰的元素,不会进行jvm默认的序列化
/**
* transient修饰元素,
* 该元素不会进行jvm默认的序列化,
* 可以自己完成这个元素的序列化
*/
private transient int stuage;
自己完成transient修饰元素的序列化
/**
* 自己完成序列化写出
*/
private void writeObject(ObjectOutputStream s) throws IOException{
}
/**
* 自己完成序列化读入
*/
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
}
public class Student implements Serializable {
private String stuno;
private String stuname;
/**
* transient修饰元素,
* 该元素不会进行jvm默认的序列化,
* 但可以自己完成这个元素的序列化
*/
private transient int stuage;
public Student() {
}
public Student(String stuno, String stuname, int stuage) {
super();
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
@Override
public String toString() {
return "Student [stuno=" + stuno + ", stuname=" + stuname + ", stuage=" + stuage + "]";
}
private void writeObject(ObjectOutputStream s) throws IOException{
/**
* 把jvm虚拟机能默认序列化的元素进行序列化
*/
s.defaultWriteObject();
/**
* 自己完成stuage的序列化
*/
s.writeInt(stuage);
}
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
/**
* 把jvm虚拟机能默认反序列化的元素进行反序列化操作
*/
s.defaultReadObject();
/**
* 自己完成stuage的反序列化操作
*/
this.stuage = s.readInt();
}
}
分析 ArrayList 源码中序列化和反序列化的问题
/**
* transient修饰元素,
* 不能用jvm虚拟机自动进行序列化,
* 可以自己进行序列化
*/
transient Object[] elementData;
序列化写出
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
/**
* 对数组的有效元素进行序列化,
* 无效元素不管,
* 提高性能
*/
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
序列化读入
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
/**
* 对数组有效部分反序列化,
* 无效部分不管
*/
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
可以用自己序列化做一些序列化的优化工作
6.3 序列化中子父类构造函数问题
5)序列化中子类和父类构造函数的调用问题
public class objectSeriaDemo2 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
/**
* 序列化,
* 递归调用父类的构造函数
*/
System.out.println("Foo2序列化:");
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Volumes/D/javaio/obj1.dat"));
Foo2 foo2 = new Foo2();
oos.writeObject(foo2);
oos.flush();
oos.close();
System.out.println();
/**
* 对子类对象进行反序列化时,
* 如果其父类的构造函数实现了序列化接口,
* 那么其父类的构造函数不会被调用
*/
System.out.println("Foo2反序列化:");
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("/Volumes/D/javaio/obj1.dat"));
Foo2 foo22 = (Foo2)ois.readObject();
System.out.println(foo22);
ois.close();
System.out.println();
/**
* 序列化,
* 递归调用父类的构造函数
*/
System.out.println("Bar2序列化:");
ObjectOutputStream oos2 = new ObjectOutputStream(
new FileOutputStream("/Volumes/D/javaio/obj1.dat"));
Bar2 bar2 = new Bar2();
oos2.writeObject(bar2);
oos2.flush();
oos2.close();
System.out.println();
/**
* 对子类对象进行反序列化时,
* 如果其父类的构造函数没有实现序列化接口,
* 那么其父类的构造函数会被调用
*/
System.out.println("Bar2反序列化:");
ObjectInputStream ois2 = new ObjectInputStream(
new FileInputStream("/Volumes/D/javaio/obj1.dat"));
Bar2 bar22 = (Bar2)ois2.readObject();
System.out.println(bar22);
ois2.close();
}
}
/**
* 一个类实现了序列化接口,那么其子类都可以进行序列化
* @author amoscxy
*
*/
class Foo implements Serializable{
public Foo() {
System.out.println("foo...");
}
}
class Foo1 extends Foo{
public Foo1() {
System.out.println("foo1...");
}
}
class Foo2 extends Foo1{
public Foo2() {
System.out.println("foo2...");
}
}
class Bar{
public Bar() {
System.out.println("bar...");
}
}
class Bar1 extends Bar implements Serializable{
public Bar1() {
System.out.println("bar1...");
}
}
class Bar2 extends Bar1{
public Bar2() {
System.out.println("bar2...");
}
}