(四)IO流——对象流、打印流
对象流:
使用对象流之前,很明显需要一个自定义的对象
可是普通的自定义类创建的对象并不能被对象流序列化
我们要让这个自定义类实现一个Serializable接口(Serializable是一个标志性接口,接口中无任何内容)
例:(省略了构造方法、get/set方法、toString方法)
public class Person implements Serializable{
private String name;
private int age;
}
ObjectOutputStream(对象输出流):
对象序列化,将对象以流的形式保存到文件夹的过程
public ObjectOutputStream(OutputStream out) 创建指定字节输出流的对象输出流对象
File f = new File("a.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
void writeObject(Object obj) 保存对象到流关联的文件中
File f = new File("b.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("jack",22);
oos.writeObject(p);
oos.close();
这样就完成了对象的序列化到b.txt:
ObjectOutputStream对象输出流输出的对象文件就是乱码,只能用对象流查看文件内容
ObjectInputStream(对象输入流):
对象反序列化,将文件中对象以流的形式读取出来的过程
public ObjectInputStream(InputStream in) 创建指定字节输入流对象的对象输入流对象
File f = new File("b.txt");
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
public final Object readObject () 读取一个对象
File f = new File("b.txt");
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
System.out.println(obj); //输出:Person{name='jack', age=22}
fis.close();
当保存好对象后,若对类的内容作了修改,且没有重新使用对象输出流输出一次关联文件
则readObject()方法读取到的关联文件时就会出现InvalidClassException异常
因为每次修改类内容(无论是,包括修饰符、成员变量、成员方法)都会改变类中的一个serialVersionUID值
然后再次读取该对象文件时,就会出现序列化不同的异常
若不想因为对类内容作了一些微小修改,而导致源文件不能被读取的问题
可以在类中固定好serialVersionUID值,且设置为私有final静态的!
public class Person implements Serializable{
private String name;
private int age;
private static final long serialVersionUID = 12345L; //固定serialVersionUID为任意一个值
}
若对象序列化时,部分成员变量中的信息,不想被writeObject写进文件中
1.可以将成员变量设置为static静态成员变量
这样改成员变量就保存在类中,创建对象时不会被对象序列化输出到文件中
public class Person implements Serializable{
private String name;
private int age1;
private static final long serialVersionUID = 12345L;
private static double high ;
}
弊端:设置为静态后,反序列化该对象文件确实不会显示此成员变量
可是所有Person类对象的high属性都是固定的,这样很不灵活、很不实用
2.使用transient关键字
使用该关键字修饰的成员变量,能保证成员变量的值不被序列化到文件中,只会短暂保存在内存中
public class Person implements Serializable{
private String name;
private int age1;
private static final long serialVersionUID = 12345L;
private transient int high ; //transient修饰了high属性
}
做个测试:使用ObjectOutputStream输出带有transient关键字修饰的成员变量
File f = new File("a.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Person p = new Person("jack",20,22); //写入被transient关键字修饰的high属性为22
oos.writeObject(p);
oos.close();
然后再用ObjectInputStream查看该对象是否包含该成员变量的信息
File f = new File("a.txt");
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
Person p = (Person)obj; //将Object对象强转为Person对象
System.out.println(p.getHigh()); //输出:0
fis.close();
打印流:
PrintStream类:
public PrintStream(File file) 使用指定的File对象创建打印流对象
File f = new File("b.txt");
PrintStream ps = new PrintStream(f);
public PrintStream(String fileName) 使用指定的文件名字符串创建打印流对象
PrintStream ps = new PrintStream("b.txt");
PrintStream类的print()和println()方法中可以输出基本数据类型
其实常用System.out.println输出语句就是一个打印流的println方法
只是创建了PrintStream对象时,指定了File对象,调用print方法时输出的对象变成了文本文件
PrintStream consolePs = System.out; //用PrintStream对象接受系统输出
PrintStream ps = new PrintStream("b.txt");
System.setOut(ps); //设置系统输出流为ps
System.out.println("你好"); //这个"你好" 会打印在b.txt文本内
System.setOut(consolePs); //设置系统输出流为consolePs
System.out.println("你好"); //这个"你好" 会打印在控制台