开发者社区> sea-boat> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

从JDK源码看Writer

简介: 概况 Writer 是一个用于写字符流的抽象类,它将一些相通的写相关操作抽象到此类,方便各种写操作类的实现。
+关注继续查看

概况

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源码看关闭钩子

欢迎关注:

这里写图片描述
这里写图片描述

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
JDK源码分析之String、StringBuilder和StringBuffer
JDK源码分析之String、StringBuilder和StringBuffer
34 0
Check task status after 2016 Spring festival
Check task status after 2016 Spring festival
42 0
The substring() Method in JDK 6 and JDK 7
The substring() Method in JDK 6 and JDK 7   By X Wang The substring(int beginIndex, int endIndex) method in JDK 6 and JDK 7 are different.
773 0
JDK6和JDK7中String的substring()方法及其差异
翻译人员: 铁锚 翻译日期: 2013年11月2日 原文链接: The substring() Method in JDK 6 and JDK 7    在JDK6与JDK7这两个版本中,substring(int beginIndex, int endIndex)方法是不同的.
825 0
BufferedWriter的简单使用
package cn.io; import java.io.BufferedWriter; import java.io.FileWriter; import java.
939 0
Ubuntu 手动安装JDK
终于成功手动安装了JDK,在此分享一下,希望所有开始使用ubuntu的新手能够用上自己所需版本的JDK。 1.下载JD: http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.将下载的文件copy到自己指定的目录 3.打开终端(gnome-terminal),进入该目录。
617 0
Ubuntu 手动安装JDK
终于成功手动安装了JDK,在此分享一下,希望所有开始使用ubuntu的新手能够用上自己所需版本的JDK。 1.下载JD: http://www.oracle.com/technetwork/java/javase/downloads/index.html 2.将下载的文件copy到自己指定的目录 3.打开终端(gnome-terminal),进入该目录。
862 0
+关注
sea-boat
擅长篮球、跑步、游泳、羽毛球、编程、看书、写书的顾家好男人! Java深度、大数据、中间件、搜索引擎、机器学习、深度学习、Python、C++、开源! 《Tomcat内核设计剖析》作者。
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载