Java面试之文件IO

1.字符流和字节流的区别

字符流:字符数据,字符流将原始数据解释成字符的序列;依赖编码方法,文件数据存储依赖文件编码方法,字符流的输入和输出需要编码和解码,效率比较低
字节流:字节(二进制)数据:字节流会将数据解释称原始的二进制数据
可移植:与主机的编码方法是无关
效率高:二进制数据不需要编码和解码

2.JavaIO中常见类,字节流,字符流,阻塞方法

(1)Java IO中常见类
常用的一些字节流子类
文件输入输出流:FileInputStream、FileOutputStream
对象输入输出流:ObjectInputStream、ObjectOutputStream
常用的一些字符流子类
文件输入输出流:FileReader FileWriter
缓存的文件输入输出流:BufferedReader BufferedWriter
(2)阻塞方法

  • 伪异步解决,线程池
    在这里插入图片描述
  • NIO解决
    在这里插入图片描述
3.序列化的目的?

对象序列化事实上将对象保存在磁盘当中,或允许在网络中直接传输序列化的对象,对象序列化机制把内存中的对象转换为与平台无关的二进制流,可以将二进制持久地保存在磁盘中,或者通过网络传输到另外一个网络节点,其他程序一旦获得这种二进制,都可以将二进制流恢复成之前的Java对象,实现了Java对象的持久化保存,使得对象可以脱离Java程序而独立存在。

4.如何去实现序列化以及反序列化?

序列化
1)实现java.io.Serlizable接口,标记当前的类是可序列化,(标记接口,不包含任何 方法和字段,只是用于标记),使用Serliable接口去实现序列化,则会产生一个序列化ID,其是一个标识符号,它通常使用对象哈希序列化标记在对象上,可以使用序列化ID对对象实现版本控制。
2)创建一个ObjectOutputStream对象
3)通过ObjectOutputStream对象的writeObject方法可以输出可序列化的对象
反序列的步骤
1)创建ObjectInputStream对象
2)通过ObjectInputStream对象的readObject方法读取流中的对象,将对象反序列为真实的
如以下代码:

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("constritor");
    }
}

public class TestDemo2 {
    public static void main(String[] args) {
        //实现序列化
        ObjectOutputStream stream = null;

        try {
            //创建ObjectOutStream,用于实现序列化
            stream = new ObjectOutputStream(new FileOutputStream("a.txt"));
            Person p = new Person("tulun", 18);
            stream.writeObject(p);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //实现反序列化
        ObjectInputStream stream1 = null;

        try {
            stream1 = new ObjectInputStream(new FileInputStream("b.txt"));
            Person p1 = (Person)stream1.readObject();//有可能会引发ClassNotFoundException
            System.out.println(p1);//不需要通过构造器来实现
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                stream1.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
5.阻塞队列

(1)ArrayBlockingQueue
底层维护了一个定长的数组,在生产者生产数据和消费者消费消费数据,共用同一个锁对象
(2)LinkedBlockingQueue
底层维护了一个链表,当生产者线程往队列中生产数据时,消费者线程同时消费队列中的数据, 原因就是生产者和消费者采用了独立的锁来控制数据的同步。
(3)SynchrousQueue
天然实现了生产者和消费者,只作为中转者
(4)DelayQueue
其中的元素只有当指定的延迟时间到了,才能够从队列中获取元素
(5)PriorityBlockingQueue
基于优先级的阻塞队列,优先级的判断需要通过构造函数传入的Compartor对象决定,注意的是其不会阻塞生产者线程,而只会在没有数据可消费时,阻塞消费者线程。
(6)ArrayBlockingQueue和LinkedBlocking的区别

  • 队列中的锁的实现不同
    ArrayBlockingQueue中的锁是没有分离的,即生产和消费用的是同一个锁;
    LinkedBlockingQueue中的锁是分离的,即生产用的是putLock,消费是takeLock
  • 在生产或消费时操作不同
    ArrayBlockingQueue基于数组,在生产和消费的时候,是直接将枚举对象插入或移除的,不会产生或销毁任何额外的对象实例;
    LinkedBlockingQueue基于链表,在生产和消费的时候,需要把枚举对象转换为Node进行插入或移除,会生成一个额外的Node对象,这在长时间内需要高效并发地处理大批量数据的系统中,其对于GC的影响还是存在一定的区别。
  • 队列大小初始化方式不同
    ArrayBlockingQueue是有界的,必须指定队列的大小;
    LinkedBlockingQueue是无界的,可以不指定队列的大小,但是默认是Integer.MAX_VALUE。当然也可以指定队列大小,从而成为有界的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值