Java流

流在Java中主要是指计算机中流动的缓冲区,是一个传输数据的通道。流在读写文件和网络传输中有着非常重要的作用。这里重点介绍常用的一些流,以及同步与异步、阻塞与非阻塞等相关内容。
2.1 输入输出流
从外部设备流向中央处理器的数据流被称为“输入流”,反之被称为“输出流”。由此可见,只要涉及文件的读写或者网络数据的收发,都会涉及输入、输出流。
2.1.1 JavaIO流的实现机制
在Java语言中,输入和输出都被称为抽象的流,流可以被看做一组有序的字节集合,即数据在两个设备之间的传输。
流的本质是数据传输,根据处理数据类型的不同,流可以分为两大类:字节流和字符流。其中字节流以字节(8bit)为单位,读到一个字节就返回一个字节,包含两个抽象类:InputStream和OutputStream。而字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)时,先去查指定的编码表,将查到的字符返回,它包含两个抽象类:Reader和Writer。其中字节流和字符流最主要的区别为:字节流在处理输入输出的时候不会用到缓存,而字符流用到了缓存。
其中ByteArrayInputStream、StringBufferInputStream、FileInputStream和PipedInputStream是Java提供的最基本的对流进行处理的类,FilterInputStream为一个包装类的基类,可以对基本的IO类进行包装,通过调用这些类提供的基本的流操作方法来实现更复杂的流操作。
Java中IO的设计理念,采用了Decorator(装饰者)设计模式。
2.1.2 管理文件和目录的类
对文件或目录进行管理与操作在编程中有着非常重要的作用,Java提供了一个非常重要的类(File)来管理文件和文件夹,通过File类不仅能够查看文件或目录的属性,而且还可以实现对文件或目录的创建、删除与重命名等操作。
File(String pathname):根据指定的路径创建一个File对象;
createNewFile():如果目录或文件存在,则返回false,否则创建文件或文件夹;
delete():删除文件或文件夹;
isFile():判断这个对象表示的是否文件;
isDirectory():判断这个对象表示的是否是文件夹;
listFiles():如果对象代表目录,则返回目录中所有的文件的File对象;
mkdir():根据当前对象指定的路径创建目录;
exists():判断对象对应的文件是否存在。
2.1.3 Java Socket
网络上的两个程序通过一个双向的通信链接实现数据的交换,这个双向链路的一端称为一个Socket。Socket也称为套接字,可以用来实现不同虚拟机或不同计算机之间的通信。Socket可以分为两种类型:面向链接的Socket——TCP(传输控制协议)通信协议和面向无连接的Socket——UDP(用户数据报协议)通信协议。任何一个Socket都是由IP地址和端口号唯一确定的。
基于TCP协议的通信过程:
首先,Server端Listen(监听)指定的某个端口(建议使用大于1024的端口)是否有连接请求,然后Client端向Server端发出Connect(连接)请求,紧接着Server端向Client端发回Accept(接收)消息。一个连接就建立起来了,会话随即产生。Server端和Client端都可以通过Send、Write等方法与对方通信。
Socket的生命周期可以分为三个阶段:打开Socket、使用Socket收发数据和关闭Socket。在Java语言中,可以使用ServerSocket作为服务端,Socket作为客户端来实现网络通信。
2.1.4 Java序列化
Java提供了两种对象持久化的方式,分别为序列化和外部序列化。
(1)序列化(Serialization)
在分布式环境下,当进行远程通信时,无论是何种类型的数据,都会以二进制序列的形式在网络上传送。序列化是一种将对象以一连串字节描述的过程,用于解决在对对象进行读写操作时所引发的问题。序列化可以将对象的状态写在流里进行网络传输,或者保存到文件、数据库等系统里,并在需要的时候把该流读取出来重新构造一个相同的对象。
如何实现序列化呢?使用一个输出流来构造一个对象流对象,紧接着,使用该对象的writeObject(Object obj)方法就可以将obj对象写出(即保存其状态),要恢复的时候就可以使用其对应的输入流。
序列化有如下几个特点:
1)如果一个类能被序列化,那么它的子类也能够被序列化;
2)由于static代表类的成员,transient(Java关键字,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持)代表对象的临时数据,因此被声明为这两种类型的数据成员是不能被序列化的。
3)Java提供了多个对象序列化的接口:ObjectOutput、ObjectInput、ObjectOutputStream、ObjectInputStream。
由于序列化的使用会影响系统的性能,因此如果不是必须要使用序列化,尽可能不要使用序列化。那么在什么情况下会使用该序列化呢?
1)需要通过网络来发送对象,或对象的状态需要被持久化到数据库或文件中。
2)序列化能实现深拷贝,即可以拷贝引用的对象。
与序列化相对的是反序列化,他将流转换为对象。在序列化与反序列化的过程中,serialVersionUID起着非常重要的作用,每个类都有一个特定的serialVersionUID,在反序列化的过程中通过serialVersionUID来判定类的兼容性。如果待序列化的对象与目标对象的serialVersionUID不同,那么在反序列化的时候就会抛出InvalidClassException异常。作为一个好的编程习惯,最好在被序列化的类中显式地声明serialVersionUID(该字段必须定义为static final)。自定义serialVersionUID主要有以下三个优点:
1)提高程序的运行效率。
2)提高程序在不同平台上的兼容性。
3)增强程序各个版本的可兼容性。
(2)外部序列化
Java语言还提供了另外一种方式来实现对象持久化,即外部序列化。
外部序列化与序列化主要的区别在于序列化是内置的API,只需要实现Serializable接口,开发人员不需要编写任何代码就可以实现对象的序列化,而使用外部序列化时,Externalizable接口中的读写方法必须由开发人员来实现。因此与实现Serializable接口的方法相比,使用Externalizable编写程序的难度更大,但是由于把控制权交给了开发人员,在编程的时候有更多的灵活性,对需要持久化的那些属性进行控制,可能会提高性能。
引申:在用接口Serializable实现序列化的时候这个类中的所有属性都会被序列化。怎么控制只序列化部分属性能?
一种方法为实现Externalizable接口;另一种是使用关键字transient来控制序列化的属性。
2.2 同步与异步、阻塞与非阻塞
(1)在多线程语境下
在多线程语境下,用于描述任务的线程访问执行机制,同步和异步关注的是任务是否可以同时被调用,阻塞和非阻塞则关注的是线程的状态。
1)同步:指代码的同步执行(Synchronous Invoke),一个执行块同一时间只有一个线程可以访问;
2)异步:指代码的异步执行(Asynchronous Invoke),多个执行块可以同时被多个线程访问;
3)阻塞:线程阻塞状态(Thread Block),表示线程挂起;
4)非阻塞:线程不处于阻塞状态,表示线程没有挂起。
(2)在IO语境下
在IO语境下,用于描述IO操作,同步和异步关注的是消息发起和接收的机制,阻塞和非阻塞则是表达发起者等待结果时的状态。
1)同步:是指发起一个IO操作时,在没有得到结果之前,该操作不返回结果,只有调用结束后,才能获取返回值并继续执行后续的操作。
2)异步:是指发起一个IO操作后,不会得到返回,结果由发起者自己轮询,或者IO操作的执行者发起回调。
3)阻塞:是指发起者在发起IO操作后,不能再处理其他业务,只能等待IO操作结束。
4)非阻塞:是指发起者不会等待IO操作完成。
(3)并发与并行的区别
1)并发(Concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速地轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替地执行。
2)并行(Parallel):指在同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。
2.3 BIO
BIO是最传统的同步阻塞IO模型,服务器端的实现是一个连接只有一个线程处理,线程在发起请求后,会等待连接返回。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值