jdk 1.4之前用的都是传统IO,主要是基于Stream的IO体系,是面相流的变成,java中一个流要么是输入流,要么是输出流。不能同时既是输入流又是输出流
关于io的详细说明,可以参考这篇文章https://www.cnblogs.com/ylspace/p/8128112.html
这里提及一下装饰器模式
在java.io中大量使用装饰器模式,这里介绍下装饰器模式
装饰器模式中的角色有:
1、抽象构件角色
给出一个抽象接口,以规范准备接受附加责任的对象
2、具体构件角色
定义一个将要接受附加责任的类
3、装饰角色
持有一个构建对象的实例,并定义一个与抽象构件接口一致的接口
4、具体装饰角色
负责给构建对象贴上附加的责任
举一个简单例子
1.有一批奔驰汽车,共同的特点就是豪华车
2.不同的型号的奔驰都有各自的特点,比如S级奔驰自带柏林之声音响,AMG奔驰高性能等
定义一个奔驰车子接口
public interface Benz {
public void descript();
}
定义一个奔驰通用模型
public class MecidesBenzCar implements Benz {
@Override
public void descript() {
System.out.println("奔驰豪华车");
}
}
定义一个装饰器角色,具体的工作具体装饰器去实现,这样,比如S级奔驰有柏林环绕声 AMG奔驰高性能,这两个动作就可以做到复用,装饰器角色定义为FilterBenz:
public abstract class FilterBenz implements Benz {
protected Benz benz;
}
接下去就是实现具体的
public class BenzSClass extends FilterBenz {
public BenzSClass(Benz benz) {
this.benz = benz;
}
public void descript() {
System.out.println("有柏林环绕声");
benz.descript();
}
}
public class BenzAMGClass extends FilterBenz {
public BenzSClass(Benz benz) { this.benz = benz; } public void descript() {
System.out.println("高性能车");
benz.descript();
}
如果我要得到一个S级奔驰的描述
Benz benz = new BenzSClass(new MecidesBenzCar());--------1
如果我要得到一个AMG奔驰的描述
Benz benz = new BenzAMGClass(new MecidesBenzCar());---------2
如果我要得到一个S级奔驰AMG的描述
Benz benz = new BenzSClass(new BenzAMGClass(new MecidesBenzCar()));----------3
--------------
上述代码是不是很熟悉,
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in)); 这是我们用于读取的常见动作
在java的io体系中大量使用了装饰器模式
盗用一张图
传统IO体系中有四个基础接口,类似于上述的Benz接口
以Reader接口为例:
FitlerReader对应了MecidesBenzCar
PushbackReader就是对应了BenzSClass
--------------------------------------
JDK1.4之后引入了nio,可以理解成new io也可以理解成non-blocking io。
NIO有三个核心概念
Selector,Channel,Buffer. 在Java.nio是面相块和buffer编程,buffer本身是一块内存,底层实现上是一个数组,数据的读写都是通过Buffer来实现。数据总是从Channel读取到buffer中,或者从buffer写入到channel中。
基本上,所有的 IO 在NIO 中都从一个Channel 开始。Channel 有点象流。 数据可以从Channel读到Buffer中,也可以从Buffer 写到Channel中。这里有个图示
Channel和Buffer有好几种类型。下面是JAVA NIO中的一些主要Channel的实现:
正如你所看到的,这些通道涵盖了UDP 和 TCP 网络IO,以及文件IO。
与这些类一起的有一些有趣的接口,但为简单起见,我尽量在概述中不提到它们。本教程其它章节与它们相关的地方我会进行解释。
以下是Java NIO里关键的Buffer实现:
这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double 和 char。
Java NIO 还有个 MappedByteBuffer,用于表示内存映射文件
Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。例如,在一个聊天服务器中。
这是在一个单线程中使用一个Selector处理3个Channel的图示:
Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等。
Java NIO还底层还是使用了linux的零拷贝技术,进一步增强性能,关于零拷贝,会有一篇文章专门涉及。
本节结束