posts - 2,  comments - 0,  trackbacks - 0

  一直以来对IO这块的东西认识都不是很清楚。每次涉及这块的东西,一般都找点现成的代码复制粘贴一下。这可不好,于是静下心来好好弄一下。

 

 

什么是IO?

    一提起IO给人的感觉就比较复杂(不过确实也挺复杂的),可能是学C的时候吓怕了,呵呵。不过,理一下思路还是比较清晰的。在Java里,IO说白了就是对读、写的一种抽象。没有什么其他的复杂的东西。至于读什么、写什么,那就看你想读什么、想写什么,由自己控制了。

 

 

读什么?写什么?

看看下面这个图会清楚很多(只用看InputStream就行,OutputStream一样):

 

 

 

     大家可以看一下直接继承InputStream的几个类ByteArrayInputStream、FileInputStream、StringBufferInputStream(PipedInputSteram和SequenceInputStream一般不用)。呵呵,看看这几个类的构造函数就明了了。第一个是把byte数字作为IO源读取byte数组里的东西,第二个是把文件作为IO源读取文件里的东西,第三个是把String作为IO源读取String里面的东西。这么看这几个IO实在简单。说白了就是从byte数组、文件、String按字节读取罢了.....

    一句简单的话说:IO体系第一级继承的几个类解决了从哪儿读或者写到哪儿的问题

 

 

怎么读?怎么写?

    试想一下,现在要读一个几百兆的文件,怎么读呢?是一下子把整个文件都读到内存慢慢分析呢,还是每次读只读一个字节逐个分析呢?显然两个都不好,于是我们想到了缓冲。所以IO体系上有了BufferedInputStream。再想一下,现在你想写一个“3.1415926”到文件里怎么写?总不能自己把这个数的二进制形式写出来,转成byte数组写到文件里吧。即便写进去了读的时候怎么读啊?谁知道你写进去的是数字而不是其他字符呢?

    于是针对怎么读Java IO体系上出现了一个分支FilerInoutStream(FilterOutputStream)。继承了这个类的几个类各自对怎么读、写提供了不同的支持。Buffered提供了缓冲,LineNumber提供了对不同类型数据的读写。

    还是一句话:IO体系的第二级继承解决了怎么读、怎么写

 

 

以不变应万变

    说IO不能不说他的Decorator(装饰)模式。此模式在这里的应用确实很经典!从上面两段的分析看来Java的IO就是分成两部分从哪儿读(写)和怎么读(写)。想想看,一个数据源可能需要不同的读写方式、而不同的数据源都可能需要同一直读写方式。于是这里的组合方式是一种乘积。n个数据源×n中处理方式×(n-1)处理方式(有时候可能涉及多种处理方式的叠加)=n^3。想想看,要是一个一个写还不写死......

    从IO体系的根看,InputStream(OutputStream)提供了最根本的read(write)方法。各子类提供各自实现。而得益于Decorator,各子类还可以把自己的处理方式加到read(write)的前后,形成一种处理方式的叠加。

    JDK这部分的代码比较简单。看一下就大概知道Decorator怎么实现的了。

 

 

追根溯源

     我们见到的IO最大的应用一个应该是数据的持久化,FileinputStream(FileOutputStream)已经实现了。而另一个则是网络传输。之前我就很想知道IO是怎么在网络上实现传输的?还有上面说的几个IO都不存在“阻塞”问题,那么IO的阻塞实在哪儿产生的呢?

     找了半天对于找到了下面一句:

     class SocketInputStream extends FileInputStream

     再追下去就找到了一些native方法,这个就超出我能力之外了。不过可以猜想,底层的东西应该就是C的一些文件读写了。这个就不是Java的问题:)目前暂时这么认为,以后或许能发现一些新的东西。

 

 

根深蒂固的痛——国际化

     编码问题不仅是Java头痛的问题,也是每一个用Java的人都头痛的问题。IO也不例外。InputStream(OutputStream)体系都是针对字节(byte)进行读写的。这样的问题是字节可能是没有意义的,只有几个字节联合转换才能得到有意义的东西。所以如果是字节还要再次进行编解码才能得到我们想要的东西。

    为了避免这个麻烦,字符体系(Read、Write)产生了。他们可以对流进行编解码,这样可以直接得到用户想要的东西。两个体系大大体上都是对应的。再多的东西我也没有深入了解了:)

    还有一个要提的是,什么时候用字符、什么时候用字节呢?TIJ里有交代:大部分时候用字符,字符不行的时候再考虑字节。呵呵,挺简练的。

 

 

日新月异

    nio应该是老掉牙的东西了。不过对于我这个初始IO的人来说还有待进一步了解。目前知道两点:上面的IO体系的底层都已经用nio重写了,所以速度上应该差不多。这样看来,一般情况下用上面的IO是没问题的。再一个是,nio最大的优势在于他的“非阻塞IO”,不过这个东东是用在网络编程的。一般也用不上。

    再新的东西就是前两天看到的一个blog,关于aio(异步IO)的大家有兴趣可以自己看看。

posted @ 2006-11-25 21:26 KeepRunning 阅读(347) | 评论 (0)编辑 收藏
这是我以前的Blog,现在也还在用。因为技术方面的东西没人关注,呵呵,所以还是把技术的东西放到技术的地方,或许更能找到共同的语音:)

顺便贴一篇,欢迎讨论~

重拾聚集(Collection)


大家先来看段代码吧:

List list = new ArrayList();
list.add("exception");
for (Iterator iter = list.iterator(); iter.hasNext();) {
     String element = (String) iter.next();
     list.remove(element);
}

这段代码运行时会抛出异常,呵呵,不知道大家发现问题没?

 

这段代码会抛出:java.util.ConcurrentModificationException。也就是所谓的“Fail Fast”。用了很久Java了,才发现这么一个异常,着实郁闷了一把......啥都不说了,拿起书来,重新来过。

 

为什么要Iterator?

下面是一个Collection的总体图:

 

 

    上面代码涉及了一个经典的涉及模式-Iterator模式。既然涉及了这个模式,就要问问为什么这里要用这个模式。查了一下书,有这么几句描述Iterator的:迭代逻辑没有改变,但是需要将一种聚集变换成另一种聚集。因为不同的聚集遍历接口不同,所以需要修改客户端代码。这几句话没错,而且我们用Iterator都有如文章开头示例的标准方式,然而仔细想来却还有点问题。

    假设Iterator是为了实现遍历方便。可是,我们几个常用的聚集(如:ArrayList,LinkedList,Set等)都已经间接实现了Collection接口。而大家应该注意到Collection接口中有个size()方法。这样的结果是,对所有实现了Collection的聚集而言,我们都可以通过for (int i = 0; i < list.size(); i++)这样的形式实现遍历。而且,JDK1.5还可以通过foreach的形式大大简化代码量。所以,这样想来Iterator为了实现遍历的方便而引入,显然不成立。

    接着找找。我们可以注意到,Set和List两个大类中一个很大的区别是:List提供get方法,而Set没有提供get方法。这样的结果是Set类只能往集合中放,却不能从集合中取(从一般的常识来说,这样做还是合理的)。呵呵,所以这里我只能猜想Iterator是不是是为了访问Set中元素而设计的了。

    仅仅猜想,不知道大家有没有什么更好的想法?

 

讨论:

     跟朋友讨论了一下,for(int i = 0; i < list.size(); i++)对应遍历LinkedList来说是致命的。对ArrayList是O(n),而LinkedList则是O(n^2),这样的效率是不能让人接受的。

    如上所说,那么foreach的引入应该是在编译层次对两种不同数据结构进行了不同处理。而且成为了Iterator的替代。

    不过这里又引出了另一个问题——

           Iterator模式如何用在其他地方?作为一种设计模式Iterator应该有更广的使用价值吧~

 

 

Iterator的缺点

  1.     聚集中的元素有些是有顺序的,而有些是没有顺序可言的。使用过度Iterator会产生一种元素顺序的误解。
  2.     Iterator给出的元素没有类型。这点很致命啊。而且也是JDK1.5一大优势。
  3.     Iterator使得某些同步的类在使用了Iterator后,成为不同步(不能说不同步,只是Iterator无法并发)。如Vector

    这里没有贬低Iterator的意思,只是实在看不出他有啥好处......

 

集合

能力有限,感觉了解还是太少,也没太多好说的,只是有些区别应该注意一下。

  1. 继承List的几个类中,只有Vector是同步的。当然也包括Vector的子类Stack。
  2. 如果需要对不同步的List,Set等可以考虑使用Collections类中的方法。

posted @ 2006-11-19 21:32 KeepRunning 阅读(286) | 评论 (0)编辑 收藏
仅列出标题  
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜