﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-和你在一起-随笔分类-Java点滴</title><link>http://www.blogjava.net/alean/category/17478.html</link><description>跬步至千里</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 02:42:45 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 02:42:45 GMT</pubDate><ttl>60</ttl><item><title>重识IO</title><link>http://www.blogjava.net/alean/archive/2006/11/25/83517.html</link><dc:creator>KeepRunning</dc:creator><author>KeepRunning</author><pubDate>Sat, 25 Nov 2006 13:26:00 GMT</pubDate><guid>http://www.blogjava.net/alean/archive/2006/11/25/83517.html</guid><wfw:comment>http://www.blogjava.net/alean/comments/83517.html</wfw:comment><comments>http://www.blogjava.net/alean/archive/2006/11/25/83517.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alean/comments/commentRss/83517.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alean/services/trackbacks/83517.html</trackback:ping><description><![CDATA[
		<p>  一直以来对IO这块的东西认识都不是很清楚。每次涉及这块的东西，一般都找点现成的代码复制粘贴一下。这可不好，于是静下心来好好弄一下。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>什么是IO？</strong>
		</p>
		<p>    
一提起IO给人的感觉就比较复杂（不过确实也挺复杂的），可能是学C的时候吓怕了，呵呵。不过，理一下思路还是比较清晰的。在Java里，IO说白了就是<font color="#ff0000"><strong>对读、写的一种抽象</strong></font>。没有什么其他的复杂的东西。至于读什么、写什么，那就看你想读什么、想写什么，由自己控制了。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>读什么？写什么？</strong>
		</p>
		<p>看看下面这个图会清楚很多（只用看InputStream就行，OutputStream一样）：</p>
		<p> </p>
		<p> </p>
		<img src="http://static.flickr.com/100/305628093_c8b341d961.jpg?v=0" />
		<p> </p>
		<p>     
大家可以看一下直接继承InputStream的几个类ByteArrayInputStream、FileInputStream、StringBufferInputStream(PipedInputSteram和SequenceInputStream一般不用)。呵呵，看看这几个类的<font color="#ff0000"><strong>构造函数</strong></font>就明了了。第一个是把byte数字作为IO源读取byte数组里的东西，第二个是把文件作为IO源读取文件里的东西，第三个是把String作为IO源读取String里面的东西。这么看这几个IO实在简单。说白了就是从byte数组、文件、String按字节读取罢了.....</p>
		<p>    一句简单的话说：IO体系第一级继承的几个类<strong>解决了从哪儿读或者写到哪儿的问题</strong>。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>怎么读？怎么写？</strong>
		</p>
		<p>    
试想一下，现在要读一个几百兆的文件，怎么读呢？是一下子把整个文件都读到内存慢慢分析呢，还是每次读只读一个字节逐个分析呢？显然两个都不好，于是我们想到了缓冲。所以IO体系上有了BufferedInputStream。再想一下，现在你想写一个“3.1415926”到文件里怎么写？总不能自己把这个数的二进制形式写出来，转成byte数组写到文件里吧。即便写进去了读的时候怎么读啊？谁知道你写进去的是数字而不是其他字符呢？</p>
		<p>    于是针对怎么读Java 
IO体系上出现了一个分支FilerInoutStream(FilterOutputStream)。继承了这个类的几个类各自对怎么读、写提供了不同的支持。Buffered提供了缓冲，LineNumber提供了对不同类型数据的读写。</p>
		<p>    还是一句话：IO体系的第二级继承<strong>解决了怎么读、怎么写</strong>。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>以不变应万变</strong>
		</p>
		<p>    
说IO不能不说他的Decorator（装饰）模式。此模式在这里的应用确实很经典！从上面两段的分析看来Java的IO就是分成两部分从哪儿读（写）和怎么读（写）。想想看，一个数据源可能需要不同的读写方式、而不同的数据源都可能需要同一直读写方式。于是这里的组合方式是一种乘积。n个数据源×n中处理方式×(n-1)处理方式（有时候可能涉及多种处理方式的叠加）＝n^3。想想看，要是一个一个写还不写死......</p>
		<p>    
从IO体系的根看，InputStream(OutputStream)提供了最根本的read（write）方法。各子类提供各自实现。而得益于Decorator，各子类还可以把自己的处理方式加到read(write)的前后，形成一种处理方式的叠加。</p>
		<p>    JDK这部分的代码比较简单。看一下就大概知道Decorator怎么实现的了。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>追根溯源</strong>
		</p>
		<p>     
我们见到的IO最大的应用一个应该是数据的持久化，FileinputStream(FileOutputStream)已经实现了。而另一个则是网络传输。之前我就很想知道IO是怎么在网络上实现传输的？还有上面说的几个IO都不存在“阻塞”问题，那么IO的阻塞实在哪儿产生的呢？</p>
		<p>     找了半天对于找到了下面一句： </p>
		<p>
				<strong>     class SocketInputStream extends FileInputStream</strong>
		</p>
		<p>
				<strong>     
</strong>再追下去就找到了一些native方法，这个就超出我能力之外了。不过可以猜想，底层的东西应该就是C的一些文件读写了。这个就不是Java的问题：）目前暂时这么认为，以后或许能发现一些新的东西。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>根深蒂固的痛——国际化</strong>
		</p>
		<p>     
编码问题不仅是Java头痛的问题，也是每一个用Java的人都头痛的问题。IO也不例外。InputStream（OutputStream）体系都是针对字节（byte）进行读写的。这样的问题是字节可能是没有意义的，只有几个字节联合转换才能得到有意义的东西。所以如果是字节还要再次进行编解码才能得到我们想要的东西。</p>
		<p>    
为了避免这个麻烦，字符体系(Read、Write)产生了。他们可以对流进行编解码，这样可以直接得到用户想要的东西。两个体系大大体上都是对应的。再多的东西我也没有深入了解了：）</p>
		<p>    还有一个要提的是，什么时候用字符、什么时候用字节呢？TIJ里有交代：<font color="#ff0000"><strong>大部分时候用字符，字符不行的时候再考虑字节</strong></font>。呵呵，挺简练的。</p>
		<p> </p>
		<p> </p>
		<p>
				<strong>日新月异</strong>
		</p>
		<p>    
nio应该是老掉牙的东西了。不过对于我这个初始IO的人来说还有待进一步了解。目前知道两点：上面的IO体系的底层都已经用nio重写了，所以速度上应该差不多。这样看来，一般情况下用上面的IO是没问题的。再一个是，nio最大的优势在于他的“非阻塞IO”，不过这个东东是用在网络编程的。一般也用不上。</p>
		<p>    再新的东西就是前两天看到的一个<a href="../../jobs/archive/2006/11/21/82409.html">blog</a>，关于aio（异步IO）的大家有兴趣可以自己看看。</p>
<img src ="http://www.blogjava.net/alean/aggbug/83517.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alean/" target="_blank">KeepRunning</a> 2006-11-25 21:26 <a href="http://www.blogjava.net/alean/archive/2006/11/25/83517.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开博第一篇</title><link>http://www.blogjava.net/alean/archive/2006/11/19/82103.html</link><dc:creator>KeepRunning</dc:creator><author>KeepRunning</author><pubDate>Sun, 19 Nov 2006 13:32:00 GMT</pubDate><guid>http://www.blogjava.net/alean/archive/2006/11/19/82103.html</guid><wfw:comment>http://www.blogjava.net/alean/comments/82103.html</wfw:comment><comments>http://www.blogjava.net/alean/archive/2006/11/19/82103.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/alean/comments/commentRss/82103.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/alean/services/trackbacks/82103.html</trackback:ping><description><![CDATA[这是我以前的<a href="http://pengjiaheng.spaces.live.com/blog/">Blog</a>，现在也还在用。因为技术方面的东西没人关注，呵呵，所以还是把技术的东西放到技术的地方，或许更能找到共同的语音：）<br /><br />顺便贴一篇，欢迎讨论～<br /><br /><span id="BlogViewId" be:sortmode="NormalWithPaging" be:sortkey="" be:firsthandle="cns!2DAA368B386E6AEA!532" be:lasthandle="cns!2DAA368B386E6AEA!446"></span><h4 style="margin-bottom: 0px;" class="TextColor1" id="subjcns!2DAA368B386E6AEA!529">重拾聚集(Collection)</h4><br /><span id="BlogViewId" be:sortmode="NormalWithPaging" be:sortkey="" be:firsthandle="cns!2DAA368B386E6AEA!532" be:lasthandle="cns!2DAA368B386E6AEA!446"><p>大家先来看段代码吧:</p><p>List list = new ArrayList();<br />list.add("exception");<br />for (Iterator iter = list.iterator(); iter.hasNext();) {<br />     String element = (String) iter.next();<br />     list.remove(element);<br />}</p><p>这段代码运行时会抛出异常，呵呵，不知道大家发现问题没？</p><p> </p><p>这段代码会抛出：<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/ConcurrentModificationException.html">java.util.ConcurrentModificationException</a>。也就是所谓的“<a href="http://www.google.com/search?hl=zh-CN&amp;newwindow=1&amp;q=Fail+Fast&amp;btnG=%E6%90%9C%E7%B4%A2&amp;lr=">Fail Fast</a>”。用了很久Java了，才发现这么一个异常，着实郁闷了一把......啥都不说了，拿起书来，重新来过。</p><p> </p><p><strong>为什么要Iterator？</strong></p><p>下面是一个Collection的总体图：</p><p> </p><p><img src="http://static.flickr.com/100/296361872_988cc45936.jpg?v=0" /></p><p> </p><p>    上面代码涉及了一个经典的涉及模式－<a href="http://www.google.com/search?hl=zh-CN&amp;newwindow=1&amp;q=Iterator%E6%A8%A1%E5%BC%8F&amp;btnG=%E6%90%9C%E7%B4%A2&amp;lr=">Iterator模式</a>。既然涉及了这个模式，就要问问为什么这里要用这个模式。查了一下书，有这么几句描述Iterator的：<font color="#0080ff">迭代逻辑没有改变，但是需要将一种聚集变换成另一种聚集。因为不同的聚集遍历接口不同，所以需要修改客户端代码</font>。这几句话没错，而且我们用Iterator都有如文章开头示例的标准方式，然而仔细想来却还有点问题。</p><p>    假设Iterator是为了实现遍历方便。可是，我们几个常用的聚集（如：ArrayList，LinkedList，Set等）都已经间接实现了Collection接口。而大家应该注意到Collection接口中有个<font color="#ff0000"><strong>size()</strong></font>方法。这样的结果是，对所有实现了Collection的聚集而言，我们都可以通过<font color="#ff0000"><strong>for (int i = 0; i &lt; list.size(); i++)</strong></font>这样的形式实现遍历。而且，JDK1.5还可以通过<font color="#ff0000"><strong>foreach</strong></font>的形式大大简化代码量。所以，这样想来Iterator为了实现遍历的方便而引入，显然不成立。</p><p>    接着找找。我们可以注意到，Set和List两个大类中一个很大的区别是：<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/List.html">List</a>提供<font color="#ff0000"><strong>get</strong></font>方法，而<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Set.html">Set</a>没有提供get方法。这样的结果是Set类只能往集合中放，却不能从集合中取（从一般的常识来说，这样做还是合理的）。呵呵，所以这里我只能猜想Iterator是不是是为了访问Set中元素而设计的了。</p><p>    仅仅猜想，不知道大家有没有什么更好的想法？</p><p> </p><p><font color="#004080" size="2"><strong>讨论：</strong></font></p><p>     跟朋友讨论了一下，<font color="#ff0000"><strong>for</strong></font><font color="#ff0000"><strong>(int i = 0; i &lt; list.size(); i++)</strong></font><font color="#000000">对应遍历LinkedList来说是致命的。对ArrayList是O(n)，而LinkedList则是O(n^2)，这样的效率是不能让人接受的。</font></p><p><font color="#ff0000"><strong>   </strong></font><font color="#000000"> 如上所说，那么foreach的引入应该是在编译层次对两种不同数据结构进行了不同处理。而且成为了Iterator的替代。</font></p><p><font color="#ff0000"><font color="#000000">    不过这里又引出了另一个问题——</font></font></p><p><font color="#ff0000"><font color="#000000">           </font><strong><font size="3">Iterator模式如何用在其他地方？作为一种设计模式Iterator应该有更广的使用价值吧～</font></strong></font></p><p> </p><p> </p><p><strong>Iterator的缺点</strong></p><ol><li>    聚集中的元素有些是有顺序的，而有些是没有顺序可言的。使用过度Iterator会产生一种元素顺序的误解。  </li><li>    Iterator给出的元素没有类型。这点很致命啊。而且也是JDK1.5一大优势。  </li><li>    Iterator使得某些同步的类在使用了Iterator后，成为不同步（不能说不同步，只是Iterator无法并发）。如<strong>Vector</strong>。</li></ol><p>    这里没有贬低Iterator的意思，只是实在看不出他有啥好处......</p><p> </p><p><strong>集合</strong></p><p>能力有限，感觉了解还是太少，也没太多好说的，只是有些区别应该注意一下。</p><ol><li>继承List的几个类中，只有Vector是同步的。当然也包括Vector的子类Stack。  </li><li>如果需要对不同步的List，Set等可以考虑使用<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html">Collections</a>类中的方法。</li></ol></span><br /><img src ="http://www.blogjava.net/alean/aggbug/82103.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/alean/" target="_blank">KeepRunning</a> 2006-11-19 21:32 <a href="http://www.blogjava.net/alean/archive/2006/11/19/82103.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>