Java 网络编程[Elliotte R.H.] 中对InputStream.markSupported()方法的误解

Elliotte 在书中(第四版35页,中译版42页)指出,InputStream.markSupported()方法的是一个设计上的失误,毕竟,java.io包中,“仅有两个类始终支持标记(BufferedInputStreamByteArrayInputStream)”。

其实他的说法也没错,就当个类而言,这不得不说是一个非常差的设计。但是,他忽略了一点,Java的IO库使用了装饰器模式,各个IO类并非独立存在,大多数可以相互串接,以添加所需特性。

举个例子,下面的代码中,两次测试同一个变量,但结果却不尽相同。如若按照Elliotte所言,使用一个单独的接口而不是超类中的公有方法,通过instanceof或反射机制,我们虽然能够得知该对象的顶层类,但却无法真正得知其底层对象是否支持标记。

import java.io.*;

/**
 * @author Jekton
 */
public class Tester {
    public static void main(String[] args) throws FileNotFoundException {

        InputStream in = new FileInputStream("E:\\myWorkspace\\in.txt");

        InputStream decorated = new DataInputStream(in);
        System.out.println("markSupported() = " + decorated.markSupported());

        // inputStream that has an additional decorator
        decorated = new DataInputStream(new BufferedInputStream(in));
        System.out.println("markSupported() = " + decorated.markSupported());


        System.out.println("decorated instanceof DataInputStream = " +
                (decorated instanceof DataInputStream));
    }
}

程序将打印:

markSupported() = false
markSupported() = true
decorated instanceof DataInputStream = true

这里,很明显,DataInputStream并不支持标记,如果使用一个独立的接口的话,我们根本无法得知中间还有个BufferedInputStream(这也是装饰器模式的优点之一)。更有甚者,此时的 decorated变量根本就没有markSupported()方法。



Java中,输入流过滤器类都继承 FilterInputStream(当然,这也包括上面提到的BufferedInputStream), FilterInputStream重写(override)了超类 InputStreammarkSupported(), 其直接调用底层输入流的 markSupported()方法

// FilterInputStream
public boolean markSupported() {
    return in.markSupported();
}

而在像BufferedInputStream这一类支持标记的类中,则直接返回l true

// BufferedInputStream
public boolean markSupported() {
    return true;
}

如此一来,不管变量的类型如何,只要“装饰器链”中存在一个支持标记的类,markSupported()都将返回true

Java 网络编程[Elliotte R.H.] 中对InputStream.markSupported()方法的误解_第1张图片
注:图片截取自[Core Java, Cay S.Horstman, Gary Cornell, 9th edition, volume 2]




后记,Elliotte 的《Java IO》一书,也同样存在此错误。笔者给他发过邮件,可惜他并没有回复。

你可能感兴趣的:(Java)