Profilo di 家恒和你在一起BlogElenchiGuestbook Strumenti Guida

Blog


29 novembre

淡淡的忧伤

                                     木兰词

 

         人生若只如初见,何事秋风悲画扇。等闲变却故人心,却道故人心易变。


   骊山语罢清宵半,泪雨霖铃终不怨。何如薄幸锦衣郎,比翼连枝当日愿。

 

                                                                                   ——纳兰性德

25 novembre

母校

其他的无所谓,这个不能不顶哦~

 

 

重识IO

    一直以来对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)的大家有兴趣可以自己看看。

19 novembre

搜索时代——读《The Search》

    不错的一本关于搜索的书,大家看看这里这里就知道了。翻译的不错,几乎是口气读一下了,感觉有点像小说,扣人心弦。本书以Google为依托,介绍了Google成长的整个历程以及对未来的展望。其中有褒有贬。不过,此书更重要的是在说搜索,而不单是Google。

    Google的成功。机遇自然不必说。不过还有三个造就了Google的与众不同的因素。一个是他的PageRank算法,这是整个Google的开始。一个是AdWords,这是Google整个历程中重要的转折点,至今也依然是Google收入的重要来源。再一个就是Google的分布式系统,以廉价PC的堆叠形成了一个高性能、高可靠性、大容量的系统。

    人类意图数据库。这是书中提出的一个概念。简单说,搜索是一个人有意识的行为,而如果计算机能记录下人的搜索时的关键词加上适当的语义分析,再融合千千万万个人的类似搜索,结果将是对人类意图的一个掌控。看看Google推出的类似服务就知道了。从这里应该可以想到,Google、YaHoo等已经掌握了大量的“人类意图”。可以猜想一下,数据挖掘很有可能成为不久的将来的一大热点,或许现在已经成为一大热点了。据说豆瓣的创始人就是在IBM搞数据挖掘的,而豆瓣出彩的地方就在他的推荐机制。

    未来的搜索。搜索才刚刚兴起。而且围绕搜索已经出现了一系列的东西。不过从书中说的来看,搜索远不只如此。现在也只发掘了搜索的5%。未来是一个搜索的时代。地方化——Google Map,个性化——Google SearchHistory……很期待未来会是什么样子:)

17 novembre

Tomcat集成进Windows服务

    平时启动Tomcat都使用startup或者catalina,而如今项目要正式用了。这就存在问题了。什么问题呢?比如机器要重启,相应的Tomcat也要自动启动才能保证服务的进行。当然,还有一种认为可以解决是我们把Tomcat的startup.bat加入Windows的“启动”中,可惜这样也是不行的。因为这种方式只有在用户登陆进入的时候才会启动。所以根本是Tomcat需要把其自身加入到Windows的服务中,这样的才能保证Windows重启以后就能启动服务,同时不需要任何用户登陆进入。

    一般书上没见过(可能是以前没有关心过这个问题)。Tomcat自身带了与Windows集成的东西。在%Tomcat%/bin/下有一个service.bat,非常简单。有两个参数install和remove,对应安装和删除Windows对应的Tomcat服务。

    此服务运行起来,执行的是tomcat5.exe,这样又存在一个问题。就是以前我在Catalina.bat中添加的一些Tomcat启动参数(如:初始jvm栈大小等)就变得无效了。不过,Tomcat还是不错的。其下的tomcat5w.exe就是用来配置的。其中的Java选项提供了配置Jvm栈大小以及jvm启动参数等。

13 novembre

重拾聚集(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类中的方法。

 

 

 

未完待续......

两个google服务

    最近无意中发现两个google的服务,觉得挺实用,不过此前没怎么听人说过。刚好跟大家分享一下:)

 

    seaerchhistory:如其名所说的,这个服务记录你个人所有的搜索记录。google记录了你每次使用google进行搜索的关键字和你点击了的搜索结果。这样的好处是,某天你想起以前搜索过的东西,可以回头看看,比起你重新搜索,效率要高。大概看了一下,最早的记录到今年6月中,呵呵,看来这个服务还是有一段时间了。

 

    books:这个服务可以搜索到一些书籍,而且可以在线浏览。不过ms只提供部分的浏览。这个有点遗憾。

08 novembre

11月的香山

    似乎每年这个时候都要去趟香山,不过越来越感觉没啥意思了,一个人多,一个确实没啥红叶,呵呵,不管了,去一趟还是纪念一下,贴两张图吧.

 

唯一一棵看着还不错的"红叶"

 

 

 

门前的小花园

 

 

 

香山的塔,忘了啥名字了.......