Java- IO 及其相关面试题(下)

简介: Java- IO 及其相关面试题(下)

六、 序列化和反序列化

6.1. Serializable接口

    Serializable接口是Java中的一个标记接口,它告诉Java虚拟机(JVM)这个类是可以被序列化的。序列化是将对象转换为字节流的过程,而反序列化则是将字节流转换回对象。   Serializable接口没有任何方法,因此它只是一个标记接口,表示可以被序列化和反序列化。当一个类实现Serializable接口时,JVM会自动处理该类的序列化和反序列化过程。

6.2 ObjectOutputStream和ObjectInputStream

    ObjectOutputStream类将Java对象序列化到文件或网络流中。而ObjectInputStream类则用于从文件或网络流中反序列化Java对象。

下面是一个将对象序列化到文件中的示例代码:

try {
    FileOutputStream fileOut = new FileOutputStream("output.ser");
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    out.writeObject(new Person("John", 30));
    out.close();
    fileOut.close();
} catch (IOException e) {
    e.printStackTrace();
}

这个示例代码创建了一个ObjectOutputStream对象,将一个Person对象序列化到名为"output.ser"的文件中。

下面是一个从文件中反序列化Java对象的示例代码:

try {
    FileInputStream fileIn = new FileInputStream("output.ser");
    ObjectInputStream in = new ObjectInputStream(fileIn);
    Person person = (Person) in.readObject();
    in.close();
    fileIn.close();
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

这个示例代码从名为"output.ser"的文件中读取一个Person对象,并将其反序列化为一个Java对象。

6.3 Externalizable接口

   Externalizable接口是Serializable接口的子接口,它提供了更多的序列化和反序列化方法。Externalizable接口定义了writeExternal和readExternal方法,用于将对象序列化和反序列化到字节流中。


下面是一个使用Externalizable接口序列化和反序列化Java对象的示例代码:

try {
    Person person = new Person("John", 30);
    DataOutputStream out = new DataOutputStream(new FileOutputStream("output.ser"));
    person.writeExternal(out);
    out.close();
    FileInputStream in = new FileInputStream("output.ser");
    Person newPerson = new Person();
    newPerson.readExternal(in);
    in.close();
} catch (IOException e) {
    e.printStackTrace();
}

  这个示例代码使用DataOutputStream将Person对象序列化到名为"output.ser"的文件中,然后使用DataInputStream从文件中反序列化Person对象。

七、异常处理和资源管理

7.1 异常处理

    常见的IO异常包括FileNotFoundException、IOException和EOFException。在处理IO异常时,应该捕获IOException并处理它,因为它是所有IO异常的父类。

下面是一个处理IO异常的示例代码:

try {
    // 执行 IO 操作
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

7.2 资源管理

    在处理IO流时,应该正确地关闭流和释放资源,以避免资源泄漏。可以使用try-with-resources语句来自动关闭流,例如:

try (FileInputStream fileIn = new FileInputStream("output.ser");
     ObjectInputStream in = new ObjectInputStream(fileIn)) {
    // 读取对象
} catch (IOException e) {
    e.printStackTrace();
}

  这个示例代码使用try-with-resources语句创建了一个FileInputStream和一个ObjectInputStream对象,并在try块结束时自动关闭它们。这样可以确保资源被正确地释放,避免资源泄漏。

八、NIO、BIO、AIO

8.1 什么是NIO、BIO、AIO?

    NIO、BIO、AIO是 Java 中不同类型的 I/O 操作。
   NIO (Non-blocking I/O) 是非阻塞 I/O,它不会阻塞线程,而是在读写操作完成之后通知线程。


   BIO (Blocking I/O) 是阻塞 I/O,它会在读写操作完成之前阻塞线程,等待数据读写完成。


   AIO (Asynchronous I/O) 是异步 I/O,它不会阻塞线程,而是使用回调函数通知线程读写操作已完成。

维度 BIO NIO AIO
IO模型 同步阻塞IO 同步非阻塞IO 异步非阻塞IO
编程模型 基于流(Stream) 基于缓冲区(Buffer) 基于事件(Event)
代码复杂度 简单 较复杂 最复杂
并发性能 较好 最好
可扩展性 较好 最好
资源消耗
对网络连接数 单线程处理多个连接 单线程处理多个连接 多线程处理多个连接
对操作系统支持 全面支持 仅支持较新版本 仅支持Linux和Windows
应用场景 对并发性能要求不高的小型应用 对并发性能要求较高的中小型应用 对并发性能要求最高的大型应用
IO模型 同步阻塞IO 同步非阻塞IO 异步非阻塞IO
编程模型 基于流(Stream) 基于缓冲区(Buffer) 基于事件(Event)
代码复杂度 简单 较复杂 最复杂
并发性能 较好 最好
可扩展性 较好 最好
资源消耗
对网络连接数 单线程处理多个连接 单线程处理多个连接 多线程处理多个连接
对操作系统支持 全面支持 仅支持较新版本 仅支持Linux和Windows
应用场景 对并发性能要求不高的小型应用 对并发性能要求较高的中小型应用 对并发性能要求最高的大型应用
IO模型 同步阻塞IO 同步非阻塞IO 异步非阻塞IO
编程模型 基于流(Stream) 基于缓冲区(Buffer) 基于事件(Event)
代码复杂度 简单 较复杂 最复杂
并发性能 较好 最好
可扩展性 较好 最好
资源消耗
对网络连接数 单线程处理多个连接 单线程处理多个连接 多线程处理多个连接
对操作系统支持 全面支持 仅支持较新版本 仅支持Linux和Windows
应用场景 对并发性能要求不高的小型应用 对并发性能要求较高的中小型应用 对并发性能要求最高的大型应用

8.2 Buffer和Channel

    Buffer是一个对象,可以存储特定类型的数据。与之相对的是Channel,它是数据的源或目标,可以与Buffer进行交互。在NIO中,数据通过Buffer在Channel之间传输。

在Java NIO中,常用的Buffer类有以下几种:ByteBuffer: 存储字节数据

CharBuffer: 存储字符数据

ShortBuffer: 存储短整数数据

IntBuffer: 存储整数数据

LongBuffer: 存储长整数数据

FloatBuffer: 存储浮点数数据

DoubleBuffer: 存储双精度浮点数数据


Channel是与数据源或目标进行通信的对象。常用的Channel类型有:
FileChannel: 用于文件的读写操作


SocketChannel: 用于通过TCP进行网络通信

DatagramChannel:用于通过UDP进行网络通信

ServerSocketChannel: 用于监听TCP连接请求


下面是一个使用Buffer和Channel进行文件读写的示例代码:

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class FileReadWriteExample {
    public static void main(String[] args) {
        try {
            // 打开文件输入流和输出流
            FileInputStream fis = new FileInputStream("input.txt");
            FileOutputStream fos = new FileOutputStream("output.txt");
            // 获取文件输入流和输出流对应的通道
            FileChannel inputChannel = fis.getChannel();
            FileChannel outputChannel = fos.getChannel();
            // 创建缓冲区
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            // 从输入通道读取数据到缓冲区
            int bytesRead = inputChannel.read(buffer);
            while (bytesRead != -1) {
                // 切换为读模式
                buffer.flip();
                // 从缓冲区写入数据到输出通道
                outputChannel.write(buffer);
                // 清空缓冲区,准备下一次读取
                buffer.clear();
                // 继续从输入通道读取数据
                bytesRead = inputChannel.read(buffer);
            }
            // 关闭通道和流
            inputChannel.close();
            outputChannel.close();
            fis.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

以下是关于Java IO的常用类的表格:

九、相关面试题

什么是缓冲流?为什么要使用它?

    缓冲流(Buffered Stream)是一种性能优化的流,它使用缓冲区来减少对底层资源(如磁盘或网络)的访问次数,从而提高读写效率。
什么是序列化?如何实现Java对象的序列化?

    序列化是将对象转换为字节流的过程,以便可以将其存储在文件中或通过网络传输。要实现Java对象的序列化,需要实现Serializable接口,并定义一个特殊的serialVersionUID字段。如何使用Java IO进行网络编程?

    可以使用Socket类和ServerSocket类来实现基于TCP/IP的网络编程。Socket类用于创建客户端套接字,ServerSocket类用于创建服务器套接字。通过这些类,可以在网络上发送和接收数据。

相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
9天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
14天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
10天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
34 4
|
11天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
51 4
|
1月前
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
83 1
Java面试题之Java集合面试题 50道(带答案)
|
1月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
67 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
23天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
51 5
|
22天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
18 1
|
1月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
28 3