16.对象流

news/2025/4/2 9:08:10/文章来源:https://www.cnblogs.com/icui4cu/p/18802764

本章目标

  • 对象流
  • 递归(掌握)

本章内容

一、对象流

如果想在JVM停止后,把这些对象保存到磁盘或者通过网络传输到另一远程机器,怎么办呢?

1、什么是对象流

所谓对象流也就是将对象的内容进行流化,能够输入输出对象的流称为对象流。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间

特点:在java.io包中对象的持续性,能够纪录自己的状态以便将来再生的能力

2、序列化

无论是何种类型的数据,都会以二进制序列形式在网络上传送,发送方需要把这个java对象转换为字节序列,才能在网络上传送,同时接收方则需要把字节序列再恢复为对象。

2.1、序列化分为:

序列化和反序列化。

  • 序列化:就是将对象的内容分解成字节流,以便存储在文件中或在网络上传输。
  • 反序列化:就是打开并读取字节流,且从该流中恢复该对象

2.2、为什么要序列化

如果想在JVM停止后,把这些对象保存到磁盘或者通过网络传输到另一远程机器,磁盘的硬件和网络等是不能认识Java对象,它们只认识二进制这些机器语言,所以我们就要把这些对象转化为字节数组,这个过程就是序列化。

2.3、如何实现序列化

只有实现java.io.Serializable接口的类才可以启用序列化功能。未实现此接口的类将无法启用任何状态的序列化和反序列化.

  • 如果某个类能够被序列化,其子类也可以被序列化。
  • static修饰的字段是不会被序列化的,序列化保存的是对象的状态而非类的状态,static静态域被忽略
  • transient修饰符修饰的字段不会被序列化。在序列化某个类的对象时,不希望某个字段被序列化(比如这个字段存放的是隐私值,如:密码等),那这时就可以用transient修饰符来修饰该字段

3、对象流:

3.1、对象输入流(ObjectInputStream):

 ObjectInputStream in = new  ObjectInputStream(输入流对象);
 in.readObject();

将需要被序列化的类实现Serializable接口,然后使用一个输出流(如:FileOutputStream等)来构造一个对象输出流ObjectOutputStream对象,使用该对象的writeObject(Object obj)方法,就可以将指定的对象obj写入到文件或传输于网络

3.2、对象输出流(ObjectOutputStream):

 ObjectOutputStream out = new ObjectOutputStream(输出流对象);//对象创建成功便会往文件中写入八个字节的内容
 out.writeObject(Object obj)

将需要被序列化的类实现Serializable接口,然后使用一个输入流(如:FileInputStream等)来构造一个对象输入流ObjectIntputStream对象,使用该对象的readObject()方法,获得对象输入流中的对象

4、示例

  • 构造一个被序列的类

    import java.io.Serializable;
     
     public class Student implements Serializable {
         private int id=1;
         private String name=“lecky”;
         private int age=27;
        ……
     }
    
  • 将对象写在硬盘

    public class StudentTest {
      public static void main(String[] args) {
      Student student = new Student();
      ObjectOutputStream o = null;
      try {
      try {
      o = new ObjectOutputStream(new FileOutputStream(“date.ser”));
      o.writeObject(student);
      } finally {
      o.close();
      }
      } catch (Exception e) {
      System.out.println(e);
      }
      }
     }
    
  • 将对象还原

    package com.it;
     
     import java.io.FileInputStream;
     import java.io.ObjectInputStream;
     
     public class ObjectRecov {
      public static void main(String args[]) {
      try {
      FileInputStream fi = new FileInputStream(“date.ser”);
      ObjectInputStream si = new ObjectInputStream(fi);
      Student stu = (Student) si.readObject();
      si.close();
      fi.close();
      System.out.println(stu.getAge());
      } catch (Exception e) {
      System.out.println(e);
      }
      }
     }
     
    

二、递归(补充)

折成两个字来理解:递和归

1、递归简介

一个方法在它的方法体内调用它自身的情况称为递归调用,这是一种特殊的嵌套调用,称之为递归方法

1.1、递归应用场景

  • 各种数学问题如:8皇后问题﹐汉诺塔,阶乘问题,迷宫问题,球和篮子的问题(google编程大赛)
  • 各种算法中也会使用到递归,比如快排,归并排序,二分查找,分治算法等
  • 将用栈解决的问题

1.2、遵守的重要规则:

  • 递归一定要有结束条件,且向退出递归的条件靠近,否则就是无限递归,出现StackOverflowError(栈内存溢出)
  • 虽然递归有结束条件,但是递归次数太多,也会发生栈内存溢出。
  • 构造方法,禁止递归(直接编译报错,因为如果允许无限new对象,会导致堆内存溢出。)

1.3、栈帧(了解)

栈帧(stack frame)是在程序执行过程中,用来存储局部变量、函数参数、返回地址和其他与函数执行相关的信息的一种数据结构。栈帧通常与函数调用有关,每当函数被调用时,就会创建一个新的栈帧。

一个栈帧通常包含以下几个重要的组成部分:

  1. 局部变量:存储函数中定义的局部变量的值。
  2. 函数参数:存储函数调用时传递的参数值。
  3. 返回地址:存储函数执行完后需要返回的下一个指令的地址。
  4. 调用者保存的寄存器:保存调用者函数在调用当前函数之前需要使用的寄存器的值。
  5. 栈指针:指向当前栈帧的顶部。

当函数执行结束后,栈帧会被销毁,栈指针会回到上一个栈帧的位置,程序继续执行上一个函数的指令。栈帧的创建和销毁过程遵循先进后出的原则,类似于堆栈(stack)数据结构的操作。

1.4、递归执行原理:

  • 执行一个方法时,就创建一个新的受保护的独立空间(栈空间)
  • 方法的局部变量是独立的,不会相互影响,比如n变量
  • 如果方法中使用的是引用类型变量(比如数组),就会共享该引用类型的数据
  • 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕
  • 递归函数在实现的过程中,是一个调用栈的过程。函数在调用另一个函数时,当前函数会处于暂定、未完成的状态,暂停函数的所有变量的值仍然会保存在内存中,直到函数执行完毕,所占内存会被弹出栈

2、递归求解1~n的和

2.1、分析

  • 根方法中调用时传入的参数是最大的那个值
  • 首先我们要找到递归的结束条件是n是否等于1,如果等于1,则返回1
  • 其次我们要找到递归的条件是如果n不等于1,返回n加上调用sum(n-1)的结果

2.2、代码实现

 public class Main {
 
     public static void main(String[] args) {
         int n = 3;
         int total = sum(n);
         System.out.println(total);
     }
 
     public static int sum(int n) {
         if (n == 1) {
             return 1;
         } else {
             return n + sum(n - 1);
         }
     }
 }

2.3、总结

1.每次递归的时候,这个方法只执行了一部分,就去执行另一部分了

2.归的时候,会把当前方法剩余部分执行完毕

3.递的次数和归的次数是一样的

4.从栈帧的角度来看:递是进栈,归是出栈

3、计算n的阶乘

n!可用下述公式递归表示:

n! = 1 (n = 0,1)

n! = n × (n-1)! (n>1)

3.1、分析

  • 根方法中调用时传入的参数是最大的那个值
  • 首先我们要找到递归的结束条件是n是否等于1,如果等于1,则返回1,或者如果等于0,也直接返回1
  • 其次我们要找到递归的条件是如果n不等于1,返回n加上调用factorial(n-1)的结果

3.2、代码

 public class Main {
 
     public static void main(String[] args) {
         int n = 5;
         int total = factorial(n);
         System.out.println(total);
     }
 
     public static int factorial(int n) {
         if (n == 1 || n == 0) {
             return 1;
         } else {
             return n*factorial(n - 1);
         }
     }
 }

3.3、总结

4、案例(贯穿项目相关)

读取目录下所有文件

4.1、分析

  • File 类的对象来表示一个文件或目录。我们可以调用 File 类的 listFiles() 方法获取一个目录下的所有文件和目录,
  • 递归结束的条件是判断它是文件还是目录(file.isDirectory()),如果是文件,则将其加入到结果List中。
  • 递归的条件是,如果是目录,则需要再次递归调用该函数,
  • 在递归时使用绝对路径file2.getAbsolutePath()

4.2、代码

 public class Main {
 
     public static void main(String[] args) {
         List<String> fileList = new ArrayList<String>();
         String dirPath = ".";
         getAllFiles(dirPath, fileList);
         for (String string : fileList) {
             System.out.println(string);
         }
     }
 
     public static void getAllFiles(String dirPath, List<String> fileList) {
         File file = new File(dirPath);
         File[] listFiles = file.listFiles();
         for (File file2 : listFiles) {
             if (file2.isDirectory()) {
                 getAllFiles(file2.getAbsolutePath(), fileList);
             } else {
                 fileList.add(file2.getName());
             }
         }
 
     }
 }

思维导图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908742.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可视化图解算法: 二叉树的中序遍历

对于二叉树的相关算法,我们总结了一套【可视化+图解】方法,依据此方法来解决相关问题,算法变得易于理解,写出来的代码可读性高也不容易出错。1. 题目 描述 给定一个二叉树的根节点root,返回它的中序遍历结果。 数据范围:树上节点数满足 0≤n≤1000,树上每个节点的值满足…

CH58x/CH59x不同类型广播使用

前言:在日常使用的时候我们用到的广播基本就是普通从机广播,在有特殊使用场景的时候我们可能会用到定向广播和拓展广播。本次对使用对定向广播和拓展广播。 一:定向广播 定向广播类型是为了尽可能快的连接,俗称回连包,这种报文包含两个地址:广播者的地址和发起者的地址。…

k 近邻算法

什么是 k 近邻? k 近邻(K-NearestNeighbor,简称 KNN)算法应该是机器学习中最简单的一个算法了,不过它虽然简单,但也有很多优点,比如:思想极度简单; 使用的数学知识很少(近乎为 0) 对于一些特定的数据集有非常好的效果; 可以解释机器学习算法使用过程中的很多细节问…

个性化配色方案

配置配色方案在app主页点击存储选择内部在根目录下找到 config 目录, 如果没有的话就创建进入 config 目录, 找到 ColorScheme 目录, 如果没有就创建进入 ColorScheme 目录, 可以创建 light.json 和 dark.json 两个文件, 一个用于在亮色模式下显示的配色方案, 一个用于暗色模式…

编辑器插件

开发编辑器插件步骤如下:在 build.gradle.kts 文件中添加 m8test sdk 依赖 , 为了减小插件apk大小, 如果是 M8Test Version Catalog 中存在的依赖库请使用 compileOnly 来依赖项目import com.m8test.util.VersionUtilsplugins {alias(m8test.plugins.android.application)alias…

基于分数Talbot效应的阵列光学涡旋产生matlab模拟与仿真

1.程序功能描述 基于分数Talbot效应的阵列光学涡旋产生matlab模拟与仿真,分别测试正方形,旋转正方形以及六边形三种阵列形状下的光学涡旋。 2.测试软件版本以及运行结果展示MATLAB2013b版本运行 测试正方形: 测试旋转正方形: 测试六边形: (完整程序运行后无水印…

组件插件

开发组件插件步骤如下:在 build.gradle.kts 文件中添加 m8test sdk 依赖 , 为了减小插件apk大小, 如果是 M8Test Version Catalog 中存在的依赖库请使用 compileOnly 来依赖项目import com.m8test.util.VersionUtilsplugins {alias(m8test.plugins.android.application)alias(m…

python-cv2读取图片位置+设置图片上文字的位置、字体、颜色等参数

import cv2 # cv2读取图片位置,图片位置必须存在桌面,与cv2的路径一样,并且图片格式和名称必须一致img = cv2.imread(face1.jpg) # POS-10-50指字的上下左右位置, font指字体,color的255指字颜色绿色pos= (10,50) font = cv2.FONT_HERSHEY_SIMPLEX color = (255,255,0) #设…

语言插件

开发语言插件步骤如下:在 build.gradle.kts 文件中添加 m8test sdk 依赖 , 为了减小插件apk大小, 如果是 M8Test Version Catalog 中存在的依赖库请使用 compileOnly 来依赖项目import com.m8test.util.VersionUtilsplugins {alias(m8test.plugins.android.application)alias(m…

通用插件

开发通用插件步骤如下:在 build.gradle.kts 文件中添加 m8test sdk 依赖 , 为了减小插件apk大小, 如果是 M8Test Version Catalog 中存在的依赖库请使用 compileOnly 来依赖项目import com.m8test.util.VersionUtilsplugins {alias(m8test.plugins.android.application)alias(m…

阿里云服务器的网站被提示该内容禁止访问的解决办法

当阿里云提示“该内容禁止访问”时,通常是因为网站被检测到存在违法或不良信息,导致URL被屏蔽。以下是解决该问题的详细步骤和防护建议:一、问题描述现象:网站无法访问,提示“该内容禁止访问”。 阿里云发送短信或邮件通知,明确违规URL和具体违规内容。原因:网站存在漏洞…

通义灵码 Rules 来了:个性化代码生成,对抗模型幻觉

通义灵码又上新外挂啦,Project Rules来了。当模型生成代码不精准,试下通义灵码 Rules,对抗模型幻觉,硬控 AI 根据你的代码风格和偏好生成代码和回复。分享你的Rules规则,赢取通义灵码头号玩家活动奖品, 立即参与 通义灵码又上新外挂啦,Project Rules来了。当模型生成代码…