当前位置: 代码迷 >> 综合 >> Java基础进阶-7-序列化+解序列化+文本存储
  详细解决方案

Java基础进阶-7-序列化+解序列化+文本存储

热度:42   发布时间:2023-10-09 04:50:57.0

目录

1、内部类

2、序列化

3、serialVersionUID

4、解序列化

5、文本存储


1、内部类

  • 内部类可以使用外部类的所有方法和变量,即使是私有的。
  • 内部类的实例一定会绑在外部类的实例上。
  • 内部类的作用:让一个类(外部类)可以实现同一个接口的多次。或者让一个类可以继承父类多次。-------这样做的目的:就是为了让一个类可以保持接口的多种不同状态。

2、序列化

如果我们在一些应用中,需要保存我们某个对象到本地的话,可以使用序列化的形式来存储。

  1. 被序列化的对象保存了自身实例变量的值,因此在我们写入文件之中之后,再被取回来的时候,可以转换为我们原来的对象。
  2. 当对象被序列化时,被该对象引用的实例变量也会被序列化,所以如果它的实例变量中有类对象,那么这个类也会被序列化。
  3. Serializable接口又被称为marker或tag类的标记用接口,因为此接口并没有任何方法需要实现。它的唯一目的就是声明实现它的类可以被序列化。
  4. 如果父类可以被序列化,那么它的子类也可以被序列化(不需要明确实现Serializable接口)。
  5. 静态变量不会被序列化,因为所有的对象都会共享同一份静态变量值。
  6. 更多属性在下面的代码zho
public class Test_Serializable {static class Student implements Serializable {static final long serialVersionUID=23333;String name;int age;/*** 1、Student内所有类对象都应该可以被序列化,否则Student将序列化失败,并报错。* 2、如果两个Student对象中对Person的引用指向同一个对象,那么这个Person只会被存储*    一次,另一个Student被复原以后,会拥有该对象的指向。*/Person p = new Person();/*** 1、当然如果你不需要对该对象进行序列化的话,可以用transient标记,这样即使Teacher*    没有实现Serializable接口,Student也能序列化成功。*/transient Teacher t=new Teacher();Student(String name, int age) {this.name = name;this.age = age;}}/*** 1、因为Student持有对Person对象的引用,所以Person类也必须实现Serializable接口,否则*    Student对象将会序列化失败。*/static class Person implements Serializable{String name;}static class Teacher {String name;}/*** 1、FileOutputStream是写入字节的方法,所以我们需要先把我们的对象转换成字节,*   ObjectOutputStream就是将我们的对象转换成可以写入的串流数据。*/private static void testWrite() throws IOException {Student s = new Student("张三", 22);Student s1 = new Student("李四", 12);// 创建存取文件的FileOutputStream对象FileOutputStream fileStream = new FileOutputStream("Student.ser");// 创建写入对象的ObjectOutputStream对象ObjectOutputStream os = new ObjectOutputStream(fileStream);os.writeObject(s);os.writeObject(s1);os.close();}public static void main(String[] args) {try {testWrite();testRead();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

3、serialVersionUID

当对象被序列化的同时,该对象会被添加一个类的版本识别ID。这个ID被成为serialVersionUID,它是根据类的结构信息计算出来的。

在对象被解序列化时,如果在对象被序列化之后有了不同的serialVersionUID,则还原操作会失败。

如果你认为类会被演化(序列化存储之后,修改该类),可以把serialVersionUID放在类中,就比如上面的 Student类中。

4、解序列化

* 解序列化过程:
* 1、对象从stream流中读取出来;
* 2、Java虚拟机通过存储信息判断出对象的class类型;
* 3、Java虚拟机尝试寻找和加载对象的类。如果Java虚拟机找不到或无法加载该类,
*    则Java虚拟机会抛出异常ClassNotFoundException;
* 4、新的对象会被配置在堆上,但是构造函数不会被执行!执行会抹除我们对象的信息。
* 5、如果对象在继承树上有一个不可序列化的祖先类,则该不可序列化类以及在它之上
*    的类的构造函数(就算是可序列化也会执行)就会执行。一旦构造函数连锁启动之后
*    将无法停止。也就是说,从第一个不可序列化的父类开始,全部都会重新初始状态。
* 6、对象的实例变量会被还原成序列化之前的状态值。transient的变量会被赋予
*    默认值。
    /*** 解序列化过程:* 1、对象从stream流中读取出来;* 2、Java虚拟机通过存储信息判断出对象的class类型;* 3、Java虚拟机尝试寻找和加载对象的类。如果Java虚拟机找不到或无法加载该类,*    则Java虚拟机会抛出异常ClassNotFoundException;* 4、新的对象会被配置在堆上,但是构造函数不会被执行!执行会抹除我们对象的信息。* 5、如果对象在继承树上有一个不可序列化的祖先类,则该不可序列化类以及在它之上*    的类的构造函数(就算是可序列化也会执行)就会执行。一旦构造函数连锁启动之后*    将无法停止。也就是说,从第一个不可序列化的父类开始,全部都会重新初始状态。* 6、对象的实例变量会被还原成序列化之前的状态值。transient的变量会被赋予*    默认值。*/private static void testRead() throws IOException, ClassNotFoundException {FileInputStream fileStream=new FileInputStream("Student.ser");ObjectInputStream os=new ObjectInputStream(fileStream);// 每次调用readObject都会都会从stream流中读取下一个对象,读取顺序与写入顺序相同,次数超出会抛出异常Object o1=os.readObject();Object o2=os.readObject();os.close();Student s1= (Student) o1;Student s2= (Student) o2;System.out.println("Student1.name="+s1.name);System.out.println("Student2.name="+s2.name);}

5、文本存储

public class Test_Write_String {private static void testWrite() {String s = "我想要存储在本地my.txt文件中\n";try {// false参数可以每次清空my.txt文件内的内容,重新写入语句FileWriter writer = new FileWriter("my.txt", false);writer.write(s);writer.close();} catch (IOException e) {e.printStackTrace();}}/*** 1、BufferedWriter可以将我们要写入磁盘的文本先存储到BufferedWriter内部,缓存起来,当缓存空间占满之后,* 开始往本地磁盘写入,这样可以减少我们访问本地磁盘的次数,加快写入的效率。* 2、当然,如果我们向立即将BufferedWriter缓存内部的文本写入磁盘的话,可以使用 buffer.flush();*/private static void testBufferWrite() {String s = "我先交由BufferedWriter存储,当它存满以后,把我写入到本地磁盘\n";String s1 = "我基础写入缓存中1\n";String s2 = "我基础写入缓存中2\n";String s3 = "我基础写入缓存中3\n";try {// true 可以在不删除前面内容的情况下,继续写入内容BufferedWriter buffer = new BufferedWriter(new FileWriter("my.txt", true));buffer.write(s);buffer.write(s1);buffer.write(s2);buffer.write(s3);buffer.close();} catch (IOException e) {e.printStackTrace();}}/*** 1、利用BufferedReader可以提高我们的读取效率,它只有在读取BufferedReader的缓存没有任何内容的时候,* 才会去读取磁盘。*/private static void testReader() {try {File file = new File("my.txt");FileReader reader = new FileReader(file);BufferedReader buffer = new BufferedReader(reader);String result;while ((result = buffer.readLine()) != null) {System.out.println("\n输出:" + result);}buffer.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}/*** File对象代表磁盘上的文件,或者目录的路径名称;* 它不能读取或者代表文件中的数据。*/private static void testFile() {File dir = new File("test.txt");boolean isMk = dir.mkdir();System.out.println("mkdir=" + isMk);System.out.println("绝对目录=" + dir.getAbsolutePath());if (dir.isDirectory()) {String[] list = dir.list();for (String s : list) {System.out.println("目录:" + s);}}}public static void main(String[] args) {testWrite();testFile();testBufferWrite();testReader();}
}