JAVA 特殊操作流 对象序列化 Properties
标准输入输出流
System类中有两个静态的成员变量:
- public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
- public static final PrintStream out:标准输出流。通常该流对应于显示输出或主机环境或用户指定的另一个输出目标
自己实现键盘录入数据:
- BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
写起来太麻烦,Java就提供了一个类实现键盘录入
- Scanner sc=new Scanner(System.in);
标准输入流的用法:
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.util.Scanner; 7 8 /* 9 public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源 10 */ 11 public class SystemInDemo { 12 public static void main(String[] args) throws IOException { 13 //public static final InputStream in:标准输入流 14 // InputStream is = System.in; 15 16 // int by; 17 // while((by=is.read())!=-1) { 18 // System.out.print((char)by); 19 // } 20 /* 21 a 22 a 23 b 24 b 25 中 26 ?? 27 */ 28 29 //如何把字节流转换为字符流?用转换流 30 // InputStreamReader isr=; 31 //使用字符流能不能够实现一次读取一行数据呢?可以 32 //但是,一次读取一行数据的方法时字符缓冲输入流的特有方法 33 // BufferedReader br=new BufferedReader(isr); 34 35 //用一步来实现 36 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 37 38 System.out.println("请输入一个字符串"); 39 String line = br.readLine(); 40 System.out.println("你输入的字符串是:" + line); 41 42 System.out.println("请输入一个整数:"); 43 int i = Integer.parseInt(br.readLine()); //要得到什么类型的字符串,就要用它对应的包装类的方法转换 44 System.out.println("你输入的整数是:" + i); 45 46 //自己实现键盘录入数据太麻烦了,所以Java就提供了一个类供我们使用 47 // Scanner sc = new Scanner(System.in); 48 49 } 50 }
输出语句的本质:是一个标准的输出流
- PrintStream ps = System.out;
- PrintStream类有的方法,System.out都可以使用
1 import java.io.PrintStream; 2 3 /* 4 public static final PrintStream out:标准输出流。通常该流对应于显示输出或主机环境或用户指定的另一个输出目标 5 */ 6 public class SystemOutDemo { 7 public static void main(String[] args) { 8 // public static final PrintStream out:标准输出流 9 PrintStream ps = System.out; 10 11 // 能够方便地打印各种数据值 12 // ps.print("hello"); 13 // ps.print(100); 14 15 // ps.println("hello"); 16 // ps.println(100); 17 18 // System.out的本质是一个字节输出流 19 System.out.println("hello"); 20 System.out.println(100); 21 22 System.out.println(); 23 // System.out.print();//报错 24 25 } 26 }
打印流
打印流分类:
- 字节打印流:PrintStream
- 字符打印流:PrintWriter
打印流特点:
- 只负责输出数据,不负责读取数据
- 有自己的特有方法
字节打印流
- PrintStream(String fileName):使用指定的文件名创建新的打印流
- 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
字节打印流用法:
1 import java.io.IOException; 2 import java.io.PrintStream; 3 4 /* 5 打印流特点: 6 只负责输出数据,不负责读取数据 7 有自己的特有方法 8 9 字节打印流 10 PrintStream(String fileName):使用指定的文件名创建新的打印流 11 */ 12 13 public class PrintStreamDemo { 14 public static void main(String[] args) throws IOException { 15 // PrintStream(String fileName):使用指定的文件名创建新的打印流 16 PrintStream ps = new PrintStream("..\\hello java\\ps.txt"); 17 18 // 写数据 19 // 字节输出流有的方法 20 // ps.write(97);//a 21 22 // 使用特有方法 23 // ps.print(97);//97 24 // ps.println();//换行 25 // ps.print(98);//98 26 27 ps.println(97); 28 ps.println(98); 29 30 // 释放资源 31 ps.close(); 32 } 33 }
字符打印流PrintWriter的构造方法:
1 import java.io.FileWriter; 2 import java.io.IOException; 3 import java.io.PrintWriter; 4 5 /* 6 字符打印流PrintWriter的构造方法: 7 8 PrintWriter (String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新 9 10 PrintWriter(Writer out,boolean autoFlush)创建一个新的PrintWriter 11 1.out:字符输出流 12 2.antoFlush:一个布尔值,如果为真,则println,printf,或format方法将刷新输出缓冲区 13 */ 14 public class PrintWriterDemo { 15 public static void main(String[] args) throws IOException { 16 // PrintWriter (String fileName)使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新 17 // PrintWriter pw=new PrintWriter("..\\hello java\\pw.txt"); 18 19 // pw.write("hello"); 20 // pw.write("\r\n");//加换行符 21 // pw.flush();//字符流,需要刷新,否则不出来 22 // 23 // pw.write("world"); 24 // pw.write("\r\n"); 25 // pw.flush(); 26 27 // pw.println("hello"); 28 /*相当于: 29 pw.write("hello"); 30 pw.write("\r\n"); 31 */ 32 // pw.flush();//还是需要刷新,比较麻烦 33 // pw.println("world"); 34 // pw.flush(); 35 36 // PrintWriter(Writer out,boolean autoFlush)创建一个新的PrintWriter 37 PrintWriter pw = new PrintWriter(new FileWriter("..\\hello java\\pw.txt"), true);// 实现自动刷新 38 // PrintWriter pw=new PrintWriter(new FileWriter("..\\hello java\\pw.txt"),false); 39 40 pw.println("hello"); 41 /*相当于: 42 pw.write("hello"); 43 pw.write("\r\n"); 44 pw.flush(); 45 */ 46 pw.println("world"); 47 48 pw.close(); 49 50 } 51 }
案例:复制Java文件(打印流改进版)
需求:把模块目录下的PrintStreamDemo.java复制到模块目录下的Copy.java
思路:
- 根据数据源创建字符输入流对象
- 根据目的地创建字符输出流对象
- 读写数据,复值文件
- 释放资源
1 import java.io.BufferedReader; 2 import java.io.BufferedWriter; 3 import java.io.FileReader; 4 import java.io.FileWriter; 5 import java.io.IOException; 6 import java.io.PrintWriter; 7 8 /* 9 案例:复制Java文件(打印流改进版) 10 11 需求:把模块目录下的PrintStreamDemo.java复制到模块目录下的Copy.java 12 13 思路: 14 1. 根据数据源创建字符输入流对象 15 2. 根据目的地创建字符输出流对象 16 3. 读写数据,复值文件 17 4. 释放资源 18 */ 19 public class CopyJavaDemo { 20 public static void main(String[] args) throws IOException { 21 /*//1. 根据数据源创建字符输入流对象 22 BufferedReader br=new BufferedReader(new FileReader("..\\hello java\\PrintStreamDemo.java")); 23 //2. 根据目的地创建字符输出流对象 24 BufferedWriter bw=new BufferedWriter(new FileWriter("..\\hello java\\Copy.java")); 25 //3. 读写数据,复值文件 26 String line; 27 while((line=br.readLine())!=null) { 28 bw.write(line); 29 bw.newLine(); 30 bw.flush(); 31 } 32 //4. 释放资源 33 br.close(); 34 bw.close();*/ 35 36 // 1. 根据数据源创建字符输入流对象 37 BufferedReader br = new BufferedReader(new FileReader("..\\hello java\\PrintStreamDemo.java")); 38 // 2. 根据目的地创建字符输出流对象 39 PrintWriter pw = new PrintWriter(new FileWriter("..\\hello java\\Copy.java"), true); 40 41 String line; 42 while ((line = br.readLine()) != null) { 43 pw.println(line); 44 } 45 // 4. 释放资源 46 br.close(); 47 pw.close(); 48 49 } 50 }
对象序列化流
对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:
- 对象序列化流:ObjectOutputStream
- 对象反序列化流:ObjectInputStream
对象序列化流
对象序列化流:ObjectOutputStream
- 将Java对象的原始数据类型和图形写入OutputStream。可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
构造方法:
- ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
序列化对象的方法:
- void writeObject(Object obj):将指定的对象写入ObjectOutputStream
注意:
- 一个对象要想被序列化,该对象所属的类必须必须实现Serializable接口
- Serializable是一个标记接口,实现该类接口,不需要重写任何方法
对象序列化的用法:
1 import java.io.Serializable; 2 3 public class Student implements Serializable { 4 private String name; 5 private int age; 6 7 public String getName() { 8 return name; 9 } 10 11 public void setName(String name) { 12 this.name = name; 13 } 14 15 public int getAge() { 16 return age; 17 } 18 19 public void setAge(int age) { 20 this.age = age; 21 } 22 23 public Student(String name, int age) { 24 super(); 25 this.name = name; 26 this.age = age; 27 } 28 29 public Student() { 30 super(); 31 } 32 33 }
1 import java.io.FileOutputStream; 2 import java.io.IOException; 3 import java.io.ObjectOutputStream; 4 5 /* 6 对象序列化流 7 构造方法: 8 9 - ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream 10 11 序列化对象的方法: 12 13 - void writeObject(Object obj):将指定的对象写入ObjectOutputStream 14 15 NotSerializableException:抛出一个实例需要一个Serializable接口。序列化运行时或实例的类可能会抛出此异常 16 类的序列化由实现java.io.Serializable接口的类启用。不实现此接口的类将不会使用任何状态序列化或反序列化 17 18 */ 19 public class ObjectOutputStreamDemo { 20 public static void main(String[] args) throws IOException { 21 // ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream 22 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\hello java\\oos.txt")); 23 24 // 创建对象 25 Student s = new Student("小白", 12); 26 27 // void writeObject(Object obj):将指定的对象写入ObjectOutputStream 28 oos.writeObject(s); 29 30 oos.close(); 31 } 32 }
对象反序列化流:ObjectInputStream
- ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
构造方法:
- ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
反序列化对象的方法:
- Object readObject():从ObjectInputStream读取一个对象
对象反序列化的用法:
1 import java.io.FileInputStream; 2 import java.io.IOException; 3 import java.io.ObjectInputStream; 4 5 /* 6 对象反序列化流:ObjectInputStream 7 8 - ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象 9 10 构造方法: 11 12 - ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream 13 14 反序列化对象的方法: 15 16 - Object readObject():从ObjectInputStream读取一个对象 17 */ 18 public class ObjectInputStreamDemo { 19 public static void main(String[] args) throws IOException, ClassNotFoundException { 20 // ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream 21 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\hello java\\oos.txt")); 22 23 // Object readObject():从ObjectInputStream读取一个对象 24 Object obj = ois.readObject();// 抛出异常 25 26 Student s = (Student) obj;// 向下转型 27 System.out.println(s.getName() + "," + s.getAge());// 小白,12 28 29 ois.close(); 30 } 31 }
对象系列化流中的三个问题
用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
- 会出问题,抛出InvalidClassException异常
如果出问题了,如何解决呢?
- 给对象所属的类加一个seriaLVersionUID
private static final long seriaLVersionUID=42L;
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
- 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
1 import java.io.Serializable; 2 3 public class Student implements Serializable { 4 private static final long serialVersionUID = 42L; 5 private String name; 6 // private int age; 7 private transient int age;// 被transient关键字修饰的成员变量,不参与序列化过程 8 9 public String getName() { 10 return name; 11 } 12 13 public void setName(String name) { 14 this.name = name; 15 } 16 17 public int getAge() { 18 return age; 19 } 20 21 public void setAge(int age) { 22 this.age = age; 23 } 24 25 public Student(String name, int age) { 26 super(); 27 this.name = name; 28 this.age = age; 29 } 30 31 public Student() { 32 super(); 33 } 34 35 // 修改了类文件 36 @Override 37 public String toString() { 38 return "Student [name=" + name + ", age=" + age + "]"; 39 } 40 41 }
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 import java.io.ObjectInputStream; 5 import java.io.ObjectOutputStream; 6 7 /* 8 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢? 9 java.io.InvalidClassException: 10 当序列化运行时检测到类中的以下问题之一时抛出。 11 类的串行版本与从流中读取的类描述符的类型不匹配 12 该类包含未知的数据类型 13 该类没有课访问的无参数构造函数 14 15 Contents2.Student; local class incompatible: 16 stream classdesc serialVersionUID = -7792934128464322290, 17 local class serialVersionUID = -394614500484104815 18 序列化版本号不同 19 20 如果出问题了,如何解决呢? 21 给对象所属的类加一个值:private static final long seriaLVersionUID=42L; 22 23 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢? 24 private transient int age; 25 26 */ 27 28 public class ObjectStreamDemo { 29 public static void main(String[] args) throws IOException, ClassNotFoundException { 30 // write(); 31 read(); 32 33 } 34 35 // 反序列化 36 private static void read() throws IOException, ClassNotFoundException { 37 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("..\\hello java\\oos.txt")); 38 Object obj = ois.readObject(); 39 Student s = (Student) obj; 40 System.out.println(s.getName() + "," + s.getAge()); 41 ois.close(); 42 43 } 44 45 // 序列化 46 private static void write() throws IOException { 47 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("..\\hello java\\oos.txt")); 48 Student s = new Student("小白", 12); 49 oos.writeObject(s); 50 oos.close(); 51 52 } 53 54 }
Properties
Properties概述:
- 是一个Map体系的集合类
- Properties可以保存到流中或从流中加载
练习:Properties作为Map集合的使用
1 import java.util.Properties; 2 import java.util.Set; 3 4 /* 5 Properties概述: 6 7 - 是一个Map体系的集合类 8 - Properties可以保存到流中或从流中加载 9 10 练习:Properties作为Map集合的使用 11 12 */ 13 public class PorpertiesDemo { 14 public static void main(String[] args) { 15 // 创建集合对象 16 // Properties<String,String> prop=new Properties<String,String>();//错误写法 17 Properties prop = new Properties(); 18 19 // 存储元素 20 prop.put("hello1", "小白"); 21 prop.put("hello2", "小黑"); 22 prop.put("hello3", "小红"); 23 24 // 遍历集合 25 Set<Object> keySet = prop.keySet(); 26 for (Object key : keySet) { 27 Object value = prop.get(key); 28 System.out.println(key + "," + value); 29 } 30 31 } 32 }
Properties作为集合的特有方法:
1 import java.util.Properties; 2 import java.util.Set; 3 4 /* 5 Properties作为集合的特有方法: 6 Object setProperty(String key,String value) 7 设置集合的键和值,都是String类型,底层调用Hashtable方法put 8 9 String getProperty(String key) 10 使用此属性列表中指定的键搜索属性 11 12 Set< String > stringPropertyNames() 13 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 14 */ 15 public class PorpertiesDemo2 { 16 public static void main(String[] args) { 17 // 创建集合对象 18 Properties prop = new Properties(); 19 20 // Object setProperty(String key,String value) 21 // 设置集合的键和值,都是String类型,底层调用Hashtable方法put 22 prop.setProperty("hello1", "小白"); 23 prop.setProperty("hello2", "小黑"); 24 prop.setProperty("hello3", "小红"); 25 26 // String getProperty(String key)使用此属性列表中指定的键搜索属性 27 // System.out.println(prop.getProperty("hello1"));//小白 28 // System.out.println(prop.getProperty("hello11"));//null 29 30 // System.out.println(prop); 31 32 // Set< String > stringPropertyNames()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 33 Set<String> names = prop.stringPropertyNames(); 34 for (String key : names) { 35 // System.out.println(key); 36 String value = prop.getProperty(key); 37 System.out.println(key + "," + value); 38 } 39 40 } 41 }
Properties和IO流结合的方法:
1 import java.io.FileReader; 2 import java.io.FileWriter; 3 import java.io.IOException; 4 import java.util.Properties; 5 6 /* 7 Properties和IO流结合的方法: 8 9 void Load(Reader reader) 10 从输入字符流读取属性列表(键和元素对) 11 12 void store(Writer writer,String comments) 13 将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式写入输出字符流 14 */ 15 public class PorpertiesDemo3 { 16 public static void main(String[] args) throws IOException { 17 // 把集合中的数据保存到文件 18 myStore(); 19 20 // 把文件中的数据加载到集合 21 myLoad(); 22 23 } 24 25 private static void myLoad() throws IOException { 26 Properties prop = new Properties(); 27 28 // void Load(Reader reader) 29 FileReader fr = new FileReader("..\\hello java\\fw.txt"); 30 prop.load(fr); 31 fr.close(); 32 33 System.out.println(prop); 34 35 } 36 37 private static void myStore() throws IOException { 38 Properties prop = new Properties(); 39 40 prop.setProperty("hello1", "小白"); 41 prop.setProperty("hello2", "小黑"); 42 prop.setProperty("hello3", "小红"); 43 44 // void store(Writer writer,String comments) 45 FileWriter fw = new FileWriter("..\\hello java\\fw.txt"); 46 prop.store(fw, null); 47 fw.close(); 48 49 } 50 51 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY