java知识总结——输入输出流

说明

  本文仅仅为了博主面试时方便查阅与梳理相关知识,如果有错误与不到位的地方,欢迎大佬指点改正,谢谢!
  阅读书籍:《java程序员面试笔试宝典》

一、java IO流的实现机制

  在java语言中,输入输出都被称为抽象的流,流可以被看作一组有序的字节集合,即数据在两设备之间的传输。
  流的本质是数据传输,根据处理数据类型的不同,流可以分为两大类:字节流和字符流
  1、字节流以字节(8bit)为单位,包含两个抽象类:InputStream(输入流)和OutputStream(输出流)
  2、字符流以字符(16bit)为单位,根据码表映射字符,一次可以读多个字节,它包含两个抽象类:Reader(输入流)和Writer(输出流)
  字节流和字符流最主要的区别为:字节流在处理输入输出时不会用到缓存,而字符流用到了缓存。
  注意:java IO类在设计时采用了Decorateor(装饰者模式)

二、管理文件和目录的类

  java提供了File类来管理文件和文件夹,通过类不仅能够查看文件或目录的属性,而且还可以实现文件或目录的创建、删除和重命名操作。
  File类中常用的方法:

方法作用
File(String pathname)根据指定的路径创建一个File对象
createNewFile()若目录或文件存在,则返回false,否则创建文件或文件夹
delete()删除文件或文件夹
isFile()判断这个对象表示的是否为文件
isDirectory()判断这个对象表示的是否为文件夹
listFiles()若对象代表目录,则返回目录中所有文件的File对象
mkdir()根据当前对象指定的路径创建目录
exists()判断对象对应的文件是否存在

三、java Socket

  1、概念
  网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个Socket。
  Socket也称为套接字,可以用来实现不同虚拟机或不同计算机之间的通信。
  2、分类
  Socket可以分为两种类型:面向连接的Socket通信协议(TCP,传输控制协议)和面向无连接的Socket通信协议(UDP,用户数据报协议)
  任何一个Socket都是由IP地址和端口号唯一确定的。如下图所示:
Socket原理图
  基于TCP的通信过程如下:首先,Server(服务器)端Listen(监听)指定的某个端口(建议使用大于1024的端口)是否有连接请求;其次,Client(客户)端向Server端发出Connet(连接)请求;最后,Server端向Client端发回Accept(接受)消息。一个连接就建立起来,会话随即产生。Server端和Client端都可以通过Send、Write等方法与对方通信。
  Socket的生命周期可以分为三个阶段:打开Socket、使用Socket收发数据和关闭Socket
  在java语言中,可以使用ServerSocket来作为服务器端,Socket作为客户端来实现网络通信。

四、java NIO

  非阻塞IO出现之前,Java是通过传统的Socket来实现基本的网络通信功能的。
  Socket使用流程如图:
在这里插入图片描述
  如果客户端还没有对服务器发起连接请求,那么accept就会阻塞(阻塞指的是暂停一个线程的执行以等待某个条件发生)。如果连接成功,当数据还没有准备好时,对read的调用同样会阻塞。
  当要处理多个连接时,就需要采用多线程的方式,由于每个线程都拥有自己的栈空间,而且由于阻塞会导致大量线程进行上下文切换,使得程序的运行效率非常低下,因此使用NIO来解决问题。
  NIO非阻塞的实现通过Selector、Channel和Buffer来实现非阻塞的IO操作。
  NIO非阻塞的实现主要采用了Reactor(反应器)设计模式,该模式可以用来处理多个事件源。
  Channel可以被看作一个双向的非阻塞的通道,在通道的两边都可以进行数据的读写操作。
  Selector实现了用一个线程来管理多个通道(采用了复用与解复用的方式使得一个线程能够管理多个通道,即可以把多个流合并称为一个流,或者把一个流分成多个流的方式)。它类似于一个观察者。在实现时,把需要处理的Channel的IO事件注册给Selector。

  Selector的实现原理
  对所有注册的Channel的IO事件进行轮询访问,一旦轮询到一个Channel有注册的时间发生,它就传回Selection-Key的方式来通知开发人员对Channel进行数据的读或写操作。
  Key封装一个特定Channel和一个特定的selector之间的关系。
  这种通过轮询的方式在处理多线程请求时不需要上下文的切换,而采用多线程的实现方式在线程之间切换时需要上下文的切换,同时也需要进行压栈和弹栈操作。因此,NIO有较高的执行效率

  Buffer用来保存数据,可以用来存放从Channel读取的数据,也可以存放使用Channel进行发送的数据。
  NIO在网络编程中有着非常重要的作用,与传统的Socket方式相比,由于NIO采用了非阻塞的方式,在处理大量并发请求时,使用NIO要比使用Socket效率高出很多

五、java 序列化

  java提供了两种对象持久化的方式,分别为序列化外部序列化
  1、序列化(Serialization)
  在分布式环境下,当进行远程通信时,无论是何种类型的数据,都会以二进制序列的形式在网络上传送。序列化是一种将对象以一连串的字节描述的过程,用于解决在对对象流进行读写操作时所引发的问题。
  序列化可以将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统里,并在需要时把该流读取出来重新构造一个相同的对象。
  所有要实现序列化的类都必须实现Serializable接口,Serializable接口位于java.lang包中,它里面没有包含任何方法。
  2、序列化的两个特点
  (1)如果一个类能被序列化,那么它的子类也能够被序列化。
  (2)由于static(静态)代表类的成员,transient代表对象的临时数据,因此被声明为这两种类型的数据成员是不够被序列化的。

  transient是java语言关键字,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

  由于序列化的使用会影响系统的性能,因此如果不是必须要使用序列化,尽可能不要使用序列化。
  3、需要使用序列化的情况
  (1)需要通过网络来发送对象,或对象的状态需要被持久化到数据库或文件中。
  (2)序列化能实现深复制,即可以复制引用的对象。
  4、自定义serialVersionUID的3个优点
  (1)提高程序的运行效率。如果在类中未显式声明serialVersionUID,那么在序列化时会通过计算得到一个serialVersionUID值。通过显式声明serialVersionUID的方式省去了计算的过程,因此提高了程序效率
  (2)提高程序不同平台上的兼容性。由于各个平台的编译器在计算serialVersionUID时完全有可能采用不同的计算方式,这就会导致在一个平台上序列化的对象在另外一个平台上将无法实现反序列化的操作。通过显式声明serialVersionUID的方法完全有可能避免该问题的发生。
  (3)增强程序各个版本的可兼容性。在默认情况下,每个类都有唯一的serialVersionUID,因此,当后期对类进行修改时,类的serialVersionUID值将会发生变化,这将会导致类在修改后将无法进行反序列化操作。同样,通过显式声明serialVersionUID也会解决这个问题。
  5、外部序列化
  java语言提供了外部序列化来实现对象持久化。
  外部序列化域序列化主要的区别在于序列化是内置的API,只需要实现Serializable接口,开发人员不需要编写任何代码就可以实现对象的序列化,而使用外部序列化时,Externalizable接口中的读写方法必须由开发人员实现。因此与实现Serializable接口的方法相比,使用Externalizable接口编写程序的难度更大,但是由于把控制权交给了开发人员,在编程时有更多的灵活性,对需要持久化的那些熟悉可以进行控制,可能会提高性能。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值