从JDK源码看Writer

本文详细介绍了Java中的Writer类,这是一个用于写字符流的抽象类,实现了Appendable、Closeable和Flushable接口。文章深入探讨了Writer类的主要属性、构造方法及关键方法如write、append、flush和close的实现细节。

概况

Writer 是一个用于写字符流的抽象类,它将一些相通的写相关操作抽象到此类,方便各种写操作类的实现。一般来说子类只需要实现它的 write、flush 、close 等三个方法,但如果有需要还可以重写 Writer 提供的公共方法。

JDK 在 Writer 的基础上实现了很多有用的 xxxWriter ,包括 BufferedWriter、CharArrayWriter、FilterWriter、OutputStreamWriter、FileWriter、PipedWriter、StringWriter 和 PrintWriter 等等。

继承结构

--java.lang.Object
 --java.io.Writer

类定义

public abstract class Writer implements Appendable, Closeable, Flushable

Writer 被定为 public 且 abstract 的类,实现了 Appendable、Closeable 和 Flushable接口。

Appendable 接口表示字符或字符序列可以被 append,接口定义如下:

public interface Appendable {
   Appendable append(CharSequence csq) throws IOException;
   Appendable append(CharSequence csq, int start, int end) throws IOException;
   Appendable append(char c) throws IOException;
}

Closeable 接口表示 Writer 可以被close,接口定义如下:

public interface Closeable extends AutoCloseable {
   public void close() throws IOException;
}

Flushable 接口表示 Writer 可以被flush,接口定义如下:

public interface Flushable {
   void flush() throws IOException;
}

主要属性

private char[] writeBuffer;
private static final int WRITE_BUFFER_SIZE = 1024;
protected Object lock;
  • writeBuffer 是一个 char[] 类型,表示写缓冲。

  • WRITE_BUFFER_SIZE 写缓冲的大小。

  • lock 是 Writer 的锁,用于实现同步。

构造方法

有两种构造方法,不带参数时则将自己作为锁,而如果传入了某个 Object 对象则将其作为锁。

protected Writer() {
   this.lock = this;
}
protected Writer(Object lock) {
   if (lock == null) {
           throw new NullPointerException();
   }    
   this.lock = lock;
}

主要方法

write方法

一共有五个 write 方法,其中有一个抽象的 write 方法,可以看到所有 write 方法最终都会调用这个抽象方法,提供给子类处理逻辑的实现。它传入的三个参数,字符数组cbuf、偏移量off和数组长度。

public abstract void write(char cbuf[], int off, int len) throws IOException;

写入一个 int 类型值时,先通过锁进行同步,再判断 writeBuffer 为 null 则要实例化一个对象,接着将 int 值转成char类型,最后调用抽象 write 方法执行子类逻辑。

写入 char 数组是则直接调用抽象 write 方法。

public void write(int c) throws IOException {
       synchronized (lock) {
                   if (writeBuffer == null){
                                   writeBuffer = new char[WRITE_BUFFER_SIZE];
                   }
                   writeBuffer[0] = (char) c;
                   write(writeBuffer, 0, 1);
        }
}
public void write(char cbuf[]) throws IOException {
       write(cbuf, 0, cbuf.length);
}

写入 String 类型数据也有类似的处理,同样是先加锁,再实例化一个 char 数组用于存放写入数据,这里不同的地方在于要根据 String 数据的长度处理,如果小于 WRITE_BUFFER_SIZE 则直接使用 Writer 里面的 writeBuffer 对象,而如果大于 WRITE_BUFFER_SIZE 则需要按照String数据的长度 new 一个 char 数组,但为了节约内存,这个较大的数组使用过后即会被 gc 掉,不必跟着 Writer 的生命周期一直存在。

public void write(String str) throws IOException {
       write(str, 0, str.length());
}
public void write(String str, int off, int len) throws IOException {
      synchronized (lock) {
          char cbuf[];            
          if (len <= WRITE_BUFFER_SIZE) {            
             if (writeBuffer == null) {
                   writeBuffer = new char[WRITE_BUFFER_SIZE];
             }
           cbuf = writeBuffer;
       } else {    
          cbuf = new char[len];
       }
       str.getChars(off, (off + len), cbuf, 0);
       write(cbuf, 0, len);
      }
}

append方法

一共有3个append方法,该方法是 Appendable 接口规定的方法,在实现中其实就是间接调用 write 方法进行写入操作,但不同的是它返回了 this,这样就可以方便地使用 append(“xxx”).append(“yyy”)。

public Writer append(char c) throws IOException {
       write(c);        
       return this;
}
public Writer append(CharSequence csq) throws IOException {
       write(String.valueOf(csq));        
       return this;
}
public Writer append(CharSequence csq, int start, int end) throws IOException {
       if (csq == null) csq = "null";        
       return append(csq.subSequence(start, end));
}

flush方法

它是一个抽象方法,留给子类实现。此方法用于刷新流,如果 Writer 的缓冲区包含任何字符则马上将其写入目的地。但如果目的地是另外一个流,则继续调用其 flush 方法刷新,所以调用 flush 会刷新 Writer 链的所有缓冲。

此外,如果写入目的地建立在操作系统之上,比如操作系统的文件系统,那么 flush 只保证将缓冲写入操作系统中,而不保证其写入硬盘等物理设备中。

public abstract void flush() throws IOException;

close方法

它是一个抽象方法,留给子类实现。此方法用于关闭流,关闭之前要先执行 flush 将缓冲刷入目的地。如果某个流已经关闭了还调用 write 或 flush 方法,则将抛出 IOException 。

public abstract void close() throws IOException;



以下是广告相关阅读

========广告时间========

鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定。感谢各位朋友。

为什么写《Tomcat内核设计剖析》

=========================

相关阅读:

从JDK源码角度看Object
从JDK源码角度看Long 
从JDK源码角度看Integer
从JDK源码角度看Float
volatile足以保证数据同步吗 
谈谈Java基础数据类型 
从JDK源码角度看并发锁的优化 
从JDK源码角度看线程的阻塞和唤醒 
从JDK源码角度看并发竞争的超时 
从JDK源码角度看java并发线程的中断 
从JDK源码角度看Java并发的公平性 
从JDK源码角度看java并发的原子性如何保证 
从JDK源码角度看Byte 
从JDK源码角度看Boolean 
从JDK源码角度看Short 
从JDK源码看System.exit 
从JDK源码看关闭钩子


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值