Java IO 面试题

  1. Java 中有几种类型的流?JDK 为每种类型的流提供了哪些抽象类以供继承? 参考答案 基础流可以分为:字节流,字符流。字节流继承于 InputStream、OutputStream 抽象类,字符流继承于 Reader 和 Writer 抽象类。在 java.io 包中还有许多其他的流,如对象流,数据流等都是基于这两种基础流扩展实现的。

字节流示例:

import java.io.*;

public class ByteStreamExample {
    public static void main(String[] args) {
        try {
            // 创建文件输出流
            FileOutputStream fos = new FileOutputStream("example.txt");
            
            // 写入字节数据
            String message = "Hello, Byte Streams!";
            byte[] bytes = message.getBytes();
            fos.write(bytes);
            
            // 关闭输出流
            fos.close();
            
            // 创建文件输入流
            FileInputStream fis = new FileInputStream("example.txt");
            
            // 读取字节数据
            int data;
            while ((data = fis.read()) != -1) {
                System.out.print((char) data);
            }
            
            // 关闭输入流
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符流示例:

import java.io.*;

public class CharacterStreamExample {
    public static void main(String[] args) {
        try {
            // 创建文件输出字符流
            FileWriter writer = new FileWriter("example.txt");
            
            // 写入字符数据
            String message = "Hello, Character Streams!";
            writer.write(message);
            
            // 关闭字符流
            writer.close();
            
            // 创建文件输入字符流
            FileReader reader = new FileReader("example.txt");
            
            // 读取字符数据
            int data;
            while ((data = reader.read()) != -1) {
                System.out.print((char) data);
            }
            
            // 关闭字符流
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

对象流示例:

import java.io.*;

public class ObjectStreamExample {
    public static void main(String[] args) {
        try {
            // 创建对象输出流
            FileOutputStream fos = new FileOutputStream("object.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            
            // 创建对象并写入到文件
            Student student = new Student("John", 25);
            oos.writeObject(student);
            
            // 关闭对象输出流
            oos.close();
            
            // 创建对象输入流
            FileInputStream fis = new FileInputStream("object.dat");
            ObjectInputStream ois = new ObjectInputStream(fis);
            
            // 从文件读取对象
            Student loadedStudent = (Student) ois.readObject();
            System.out.println("Name: " + loadedStudent.getName() + ", Age: " + loadedStudent.getAge());
            
            // 关闭对象输入流
            ois.close();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

// 定义一个可序列化的学生类
class Student implements Serializable {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

缓冲流示例:

import java.io.*;

public class BufferedStreamExample {
    public static void main(String[] args) {
        try {
            // 创建缓冲字符输出流
            BufferedWriter writer = new BufferedWriter(new FileWriter("buffered.txt"));
            
            // 写入字符数据
            writer.write("Hello, Buffered Streams!");
            
            // 关闭缓冲字符输出流
            writer.close();
            
            // 创建缓冲字符输入流
            BufferedReader reader = new BufferedReader(new FileReader("buffered.txt"));
            
            // 读取字符数据
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            
            // 关闭缓冲字符输入流
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  1. 字节流与字符流的区别? 参考答案 1、每次读写的字节数不同。字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。 2、字符流是块读写,字节流是字节读写。字符流和字节流,一个属性范围小,一个属性范围大,字符流只能是字符这一种类型,但是字节流中可以是字符,可以是二进制文件,可以是音频,可以是各种各样的类型,只要符合字节形式存储的都可以接字节流,而字符流只能接字符。 3、字符流带有缓存,字节流没有。

// 使用字节流读写数据
InputStream inputStream = new FileInputStream("example.txt");
OutputStream outputStream = new FileOutputStream("output.txt");

// 使用字符流读写数据
Reader reader = new FileReader("example.txt");
Writer writer = new FileWriter("output.txt");
  1. 什么是 Java 序列化,如何实现 Java 序列化? 参考答案 序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问题。 序列化的实现:将需要被序列化的类实现 Serialize 接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流) 对象,再使用 ObjectOutputStream 对象的 write(Object obj) 方法就可以将参数 obj 的对象写出。

import java.io.Serializable;

public class MyObject implements Serializable {
    // 类的属性和方法
}
  1. 什么是缓冲区?有什么作用? 参考答案 缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性。 对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。

  2. BufferedReader 属于哪种流, 它主要是用来做什么的, 它里面有那些经典的方法? 参考答案 属于处理流中的缓冲流,可以将读取的内容存在内存里面,有 readLine() 方法用来读取一行字符串。

  3. 流如何关闭比较好,如果有多个流互相调用传入是怎么关闭的? 参考答案 流一旦打开就必须关闭,可以使用 close 方法将其关闭。一般关闭流的操作都放入 finally 语句块中以保证该操作一定会执行。若是多个流互相调用,那么只关闭最外层的流即可。

BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("file.txt"));
    // 读取文件内容
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if (reader != null) {
            reader.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  1. 为什么需要序列化? 参考答案 可以从两个方面来解释,一方面是为了方便数据存储,另一方面是为了方便数据的传递。序列化就是将一对象 (标志对象的类型) 及其状态转换为字节码,保存起来(可以保存在数据库,内存,文件等), 然后可以在适当的时候再将其状态恢复 (也就是反序列化)

import java.io.*;

// 创建可序列化的 Person 类
class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

public class SerializationExample {
    public static void main(String[] args) {
        // 创建一个 Person 对象
        Person person = new Person("Alice", 30);

        // 序列化 Person 对象到文件
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
            oos.writeObject(person);
            System.out.println("Person 对象已序列化到文件 person.ser");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 从文件中反序列化 Person 对象
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
            Person deserializedPerson = (Person) ois.readObject();
            System.out.println("从文件中反序列化的 Person 对象:" + deserializedPerson);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

//在此示例中,我们创建了一个 Person 类,并为其添加了 Serializable 接口。然后,我们将 Person //对象序列化到名为 person.ser 的文件中,并从该文件中反序列化了一个新的 Person 对象。
  1. 哪些属性不能被序列化? 参考答案 Java 中未直接或间接实现序列化接口的类和属性不能被序列化,被 static,transient 修饰的属性不会被序列化。

  2. 序列化 ID 作用? 参考答案 Java 的序列化机制是通过在运行时判断类的 serialVersionUID 来验证版本一致性的。在进行反序列化时,JVM 会把传来的字节流中的 serialVersionUID 与本地实体类中的 serialVersionUID 进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。

  3. transient 关键字作用? 参考答案 transient 关键字阻止该变量被序列化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

师范大学通信大怨总

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值