<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>糊墙</title>
	<atom:link href="http://www.liubida.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.liubida.com</link>
	<description>践行，渐远</description>
	<lastBuildDate>Sat, 19 May 2012 06:12:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>java泛型的擦除以及桥方法</title>
		<link>http://www.liubida.com/programming_language/java_generic_erase/</link>
		<comments>http://www.liubida.com/programming_language/java_generic_erase/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 01:27:42 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[bridge method]]></category>
		<category><![CDATA[generic]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[jvm]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=292</guid>
		<description><![CDATA[java泛型的擦除 在1.5之后, java语言中的泛型编程得到了广泛的运用. 但是为了使得java语言在引入泛型之后, 能够兼容以前java的非泛型代码, java的泛型特性做了相当的阉割&#8211;即对于泛型的类型信息(type information), jvm采取了摒弃的策略. 造成了以下的事实. Class c1 = new ArrayList().getClass(); Class c2 = new ArrayList().getClass(); System.out.println(c1 == c2); //true “The cold truth is:There’s no information about...]]></description>
			<content:encoded><![CDATA[<p>java泛型的擦除<br />
在1.5之后, java语言中的泛型编程得到了广泛的运用. 但是为了使得java语言在引入泛型之后, 能够兼容以前java的非泛型代码, java的泛型特性做了相当的阉割&#8211;即对于泛型的类型信息(type information), jvm采取了摒弃的策略. 造成了以下的事实.</p>
<p>Class c1 = new ArrayList<String>().getClass();<br />
Class c2 = new ArrayList<Integer>().getClass();<br />
System.out.println(c1 == c2); //true</p>
<p>“The cold truth is:There’s no information about generic parameter types available inside generic code”&#8211;对于List<String> 和 List<Integer> 这两种泛型类型来说, 他们的运行时类型是一样的, 事实上，jvm并不知道泛型，所有的泛型在编译阶段就已经被处理成了普通类和方法。jvm会认为都是List类型, List中的元素的”String”类型和”Integer”类型就给擦除(erased)掉了. 虽然擦除掉了, 但我们知道, java是强类型语言, 不管什么元素, 你总得有一个类型才行, 否则jvm就没法处理, 编译器也不会过. 那List里的元素被认为成什么类型呢?<br />
一般说来, 泛型的类型尖括号里面的泛型类型, 在编译时会被处理成一个原始类型.<br />
<strong>如果有限定(<T extends A>)，jvm就A作为原始类型<br />
如果有多个限定(<T extends A&#038;B>)，jvm就用第一个边界的类型变量A类作为原始类型<br />
如果泛型类型的类型变量没有限定(<T>) ，等同于(<T extends Object>), 所以就用Object作为原始类型</strong><br />
<span id="more-292"></span><br />
class Gener<T extends A> {<br />
    T data = null;<br />
    void print(T t) {<br />
        System.out.println(t);<br />
    }<br />
}<br />
编译器会擦除掉类型变量T, 并且把T用原始类型A来替代,<br />
class Gener{<br />
    A data = null;<br />
    void print(A t) {<br />
        System.out.println(t);<br />
    }<br />
}<br />
为什么说java泛型是被阉割了的? 我们来看看c++的泛型使用.<br />
#include <iostream><br />
using namespace std;<br />
template<class T> class Manipulator {<br />
    T obj;<br />
    public:<br />
    Manipulator(T x) { obj = x; }<br />
    void manipulate() { obj.f(); }<br />
};<br />
class HasNoF{}<br />
    class HasF {<br />
      public:<br />
        void f() { cout << "HasF::f()" << endl; }<br />
    };<br />
 int main() {<br />
  HasF hf;<br />
  Manipulator<HasF> manipulator(hf);<br />
  manipulator.manipulate();</p>
<p>  // HasNoF hnf;<br />
  // Manipulator<HasNoF> manipulator(hnf);<br />
}<br />
Output:<br />
HasF::f()</p>
<p>看出蹊跷来了么?泛型类Manipulator里面居然可以直接对obj调用f方法(obj.f()), 他怎么能够知道泛型参数T所对应的类有f()这样一个方法呢??? 答案就是c++的编译器. 当我们在代码里用HasF类来实例化Manipulator时, 编译器进行检查并发现了HasF类是有一个方法f()的. 编译器就会同意你在Manipulator类型中调用T的f()方法. 反之, 如果在所有实例化Manipulator的类中, 只要有一个没有方法f(), 则编译器报错. 你可以仿照这个写出java代码, 然后就会发现, 在java中, 我们只能调用Object的方法(<T>的情况).</p>
<p>一些隐含的问题: 桥方法(bridge method), 看下面的例子<br />
public class Gener<T> {<br />
    void print(T t) {<br />
        System.out.println(“parent: ” + t);<br />
    }<br />
    public static void main(String[] args) {<br />
        Gener s = new SonGener();<br />
        s.print(new Object());<br />
    }<br />
}</p>
<p>class SonGener extends Gener<String> {<br />
    void print(String s) {<br />
        System.out.println(“son: ” + s);<br />
    }<br />
}<br />
输出-><br />
Exception in thread “main” java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String<br />
	at SonGener.print(Gener.java:1)<br />
	at Gener.main(Gener.java:15)<br />
为啥??<br />
首先, 这个代码编译是通过的, 说明在编译器认为这个代码的是o的. 不是废话的废话, 埋笔.<br />
我们先来梳理下这个代码. 首先声明了一个Gener类型的s变量, 然后让这个变量指向了一个SonGen类型的对象, 最后通过变量s调用print方法. 前面讲过, java的泛型在编译的时候会被处理成一个原始类型, 例子中Gen的T就被处理成了Object. 那么代码实际上就变成了这样的:<br />
public class Gener {<br />
    void print(Object t) {<br />
        System.out.println(“parent: ” + t);<br />
    }<br />
    public static void main(String[] args) {<br />
        Gener s = new SonGener();<br />
        s.print(new Object());<br />
    }<br />
}<br />
class SonGener extends Gener {<br />
    void print(String s) {<br />
        System.out.println(“son: ” + s);<br />
    }<br />
}<br />
基于以上的分析, 这个变化后的代码没有任何问题. 运行这个代码, 可以得到输出: “parent: java.lang.Object@1690726&#8243;. fk, 这是怎么回事? 我们基于原型的分析是错误的? 再回头来, 我们看下报的错误, “java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String”<br />
代码中只有SonGener的print方法需要String类型的参数, 并且直觉上感觉, 这个错误的发生是因为<strong>向SonGener的print方法中传递了一个Object类型的参数, 在把Object cast to String的时候, 喀嚓了</strong><br />
同时, 回想下前面的那句废话, 说明这个因调用引起的cast过程是在运行时发生的, 即编译的时候, 编译器还不知道s.print(new Object())会调用print(String s), 否则编译器就直接”出红”了. 不玩虚了, 我们还是看下SonGener的字节码吧.</p>
<p>Compiled from “Gener.java”<br />
class SonGener extends Gener{<br />
SonGener();<br />
  Code:<br />
   0:	aload_0<br />
   1:	invokespecial	#1; //Method Gener.”<init>“:()V<br />
   4:	return</p>
<p>void print(java.lang.String);<br />
  Code:<br />
   0:	getstatic	#2; //Field java/lang/System.out:Ljava/io/PrintStream;<br />
   3:	new	#3; //class java/lang/StringBuilder<br />
   6:	dup<br />
   7:	invokespecial	#4; //Method java/lang/StringBuilder.”<init>“:()V<br />
   10:	ldc	#5; //String son:<br />
   12:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;<br />
   15:	aload_1<br />
   16:	invokevirtual	#6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;<br />
   19:	invokevirtual	#7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;<br />
   22:	invokevirtual	#8; //Method java/io/PrintStream.println:(Ljava/lang/String;)V<br />
   25:	return</p>
<p>void print(java.lang.Object);<br />
  Code:<br />
   0:	aload_0<br />
   1:	aload_1<br />
   2:	checkcast	#9; //class java/lang/String<br />
   5:	invokevirtual	#10; //Method print:(Ljava/lang/String;)V<br />
   8:	return<br />
}<br />
&#8230;汗了, 这个void print(java.lang.Object)是个什么鸟玩? 查了下, 这货就是桥方法(bridge method).<br />
桥方法是编译器自己偷偷搞出的东西, 在java的source里面是看不出痕迹的. 我所知道的用了桥方法的地方有, 子类继承了带有泛型化参数的父类(正在说的这个), 还一个场景就是public的子类继承了非public的父类&#8230;<br />
详细的介绍, 看<a href="http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html" target="_blank">这儿</a><br />
接着来, 我们先别急着问编译器为什么要搞出这么个东西, 先来顺着编译器的桥方法的思路重新来梳理下代码. 如果SonGener里面生成了桥方法, 则代码应该是这样的:<br />
public class Gener {<br />
    void print(Object t) {<br />
        System.out.println(“parent: ” + t);<br />
    }</p>
<p>    public static void main(String[] args) {<br />
        Gener s = new SonGener();<br />
        s.print(new Object());<br />
    }<br />
}<br />
class SonGener extends Gener {<br />
    void print(String s) {<br />
        System.out.println(“son: ” + s);<br />
    }</p>
<p>    void print(Object s){<br />
        // i&#8217;m the bridge method<br />
	print((String) s);<br />
    }<br />
}<br />
如果是这样的话, 则SonGener的print(Object s)方法就覆盖了父类的print, 请注意下面的话, 只是这个覆盖是由编译器偷偷生成的桥方法来覆盖的, 而不是print(String s)来覆盖的. 桥方法print(Object s)只是做了一个代理, 内部再次调用了print(String s), 而在调用之前需要有一个cast操作, 我们的错误就是在这里蹦出来的. 小结下: 1. 本意应该调用父类Gener的print方法, 由于子类SonGener中桥方法的存在, 使得print方法被覆盖, 所以会调用子类SonGener的print方法; 2. 桥方法只是做一个代理, 会调用真实的print(String s)方法. 其实, 细心的人可以发现, 在eclipse中编译代码时, 那个覆盖方法的绿色小三角会出现在print(String s)的方法旁边.<br />
话说回来了, 为么子要搞这个桥方法出来呢? 下面只是我个人的想法. 因为java泛型的阉割, 导致jvm中的编译是将泛型蜕化成了原始类型, 这就会导致一个问题, 就是在泛型中定义的一些函数无法被覆盖, 比如Gener的print(T t), 对于编码的人来说, 当SonGener继承Gener<String>时, 自然不会考虑到其父类会存在一个print(String s); 即使有, 我重写一个覆盖你总可以吧. 而在尝试重写print(String s)时, 却发现怎么都覆盖不了, 因为父类有一个print(Object o)罩着呢. 所以, 为了兼容也好, 对泛型阉割的补救也罢, 桥方法诞生了.<br />
class SonGener extends Gener<String> {<br />
    void print(String s) {<br />
        System.out.println(“son: ” + s);<br />
    }<br />
}</p>
<p>关于泛型蜕化成什么类型的问题, 我还有点没想透, 想清楚了再补上.</p>
<p>bridge method详解: http://stas-blogspot.blogspot.com/2010/03/java-bridge-methods-explained.html</p>
<p>http://hxraid.iteye.com/blog/549509</p>
<p>http://wen66.iteye.com/blog/730995</p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/programming_language/java_generic_erase/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql innodb ibdata文件瘦身</title>
		<link>http://www.liubida.com/tips/mysql_innodb_ibdata_file/</link>
		<comments>http://www.liubida.com/tips/mysql_innodb_ibdata_file/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 07:07:32 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[tips]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=245</guid>
		<description><![CDATA[转载请注明出处: http://www.liubida.com/uncategorized/mysql_innodb_ibdata_file/ 今天给开机之后ubuntu更新, 竟然提示说磁盘空间满. df一看, 根目录只有不到190MB. 但是根目录没道理用的这么快, 于是检查下, 看看是哪个文件占用了大量的磁盘. 如果有必要, 以下命令可能需要加上sudo. du -m &#8211;max-depth=1 &#124; sort -g du -h &#8211;max-depth=1 /var/* 层层递进之后发现是因为mysql目录下的ibdata文件太大, 竟然就占用了5G大小, 用了很长时间, 也是该清理下了. 思路很简单, 就是先备份数据库, 然后删除, 再还原数据库就行了. #...]]></description>
			<content:encoded><![CDATA[<p>转载请注明出处: <a href="http://www.liubida.com/uncategorized/mysql_innodb_ibdata_file/">http://www.liubida.com/uncategorized/mysql_innodb_ibdata_file/</a></p>
<p>今天给开机之后ubuntu更新, 竟然提示说磁盘空间满. df一看, 根目录只有不到190MB. 但是根目录没道理用的这么快, 于是检查下, 看看是哪个文件占用了大量的磁盘. 如果有必要, 以下命令可能需要加上sudo.</p>
<blockquote><p>du -m &#8211;max-depth=1 | sort -g<br />
du -h &#8211;max-depth=1 /var/*</p></blockquote>
<p>层层递进之后发现是因为mysql目录下的ibdata文件太大, 竟然就占用了5G大小, 用了很长时间, 也是该清理下了. 思路很简单, 就是先备份数据库, 然后删除, 再还原数据库就行了.</p>
<blockquote><p>
# 备份数据库<br />
mysqldump -uDBuser -pPassword &#8211;quick &#8211;force &#8211;routines &#8211;add-drop-database &#8211;all-databases &#8211;add-drop-table > /home/liubida/backup.sql</p>
<p># 关闭mysql服务<br />
sudo service mysql stop</p>
<p># 手动删除除mysql之外所有文件<br />
sudo rm /var/lib/mysql/ib*<br />
sudo rm /var/lib/mysql/armory -rf<br />
&#8230;</p>
<p># 启动mysql服务<br />
sudo service mysql start</p>
<p># 还原数据库<br />
mysql -uDBuser -pPassword < /home/liubida/backup.sql</p></blockquote>
<p>最后, 看看根目录的变化吧.<span id="more-245"></span></p>
<blockquote><p>liubida@liubida-office:/var/lib/mysql$ df -h<br />
Filesystem            Size  Used Avail Use% Mounted on<br />
/dev/sda6             9.4G  4.5G  4.5G  51% /<br />
none                  1.6G  664K  1.6G   1% /dev<br />
none                  1.6G  3.7M  1.6G   1% /dev/shm<br />
none                  1.6G  112K  1.6G   1% /var/run<br />
none                  1.6G     0  1.6G   0% /var/lock<br />
/dev/sda7              93G   81G  7.3G  92% /home</p></blockquote>
<p><br/><br/></p>
<p>附1:<br />
mysqldump命令参数说明:</p>
<blockquote><p>&#8211;quick, -q<br />
在恢复数据的时候强制让mysqldump一行一行的恢复, 而不是把整个行数据缓存之后一次恢复.(我的理解: 尽快的恢复每一行数据, 能够尽可能的降低数据的不可读时间)</p>
<p>           This option is useful for dumping large tables. It forces mysqldump to retrieve rows for a table from the server a<br />
           row at a time rather than retrieving the entire row set and buffering it in memory before writing it out.
</p></blockquote>
<blockquote><p>&#8211;force, -f<br />
强制执行完成, 如果遇到错误打印出错误信息, 继续执行后续的sql语句</p>
<p>           Continue even if an SQL error occurs during a table dump.</p>
<p>           One use for this option is to cause mysqldump to continue executing even when it encounters a view that has become<br />
           invalid because the definition refers to a table that has been dropped. Without &#8211;force, mysqldump exits with an<br />
           error message. With &#8211;force, mysqldump prints the error message, but it also writes an SQL comment containing the<br />
           view definition to the dump output and continues executing.
</p></blockquote>
<blockquote><p>&#8211;routines, -R<br />
对存储过程和事务也进行dump</p>
<p>           Included stored routines (procedures and functions) for the dumped databases in the output. Use of this option<br />
           requires the SELECT privilege for the mysql.proc table. The output generated by using &#8211;routines contains CREATE<br />
           PROCEDURE and CREATE FUNCTION statements to re-create the routines. However, these statements do not include<br />
           attributes such as the routine creation and modification timestamps. This means that when the routines are reloaded,<br />
           they will be created with the timestamps equal to the reload time.</p>
<p>           If you require routines to be re-created with their original timestamp attributes, do not use &#8211;routines. Instead,<br />
           dump and reload the contents of the mysql.proc table directly, using a MySQL account that has appropriate privileges<br />
           for the mysql database.</p>
<p>           This option was added in MySQL 5.1.2. Before that, stored routines are not dumped. Routine DEFINER values are not<br />
           dumped until MySQL 5.1.8. This means that before 5.1.8, when routines are reloaded, they will be created with the<br />
           definer set to the reloading user. If you require routines to be re-created with their original definer, dump and<br />
           load the contents of the mysql.proc table directly as described earlier.
</p></blockquote>
<blockquote><p>&#8211;add-drop-database</p>
<p>           Add a DROP DATABASE statement before each CREATE DATABASE statement. This option is typically used in conjunction<br />
           with the &#8211;all-databases or &#8211;databases option because no CREATE DATABASE statements are written unless one of those<br />
           options is specified</p></blockquote>
<blockquote>
<p>&#8211;add-drop-table</p>
<p>           Add a DROP TABLE statement before each CREATE TABLE statement</p></blockquote>
<blockquote>
<p>&#8211;all-databases, -A</p>
<p>           Dump all tables in all databases. This is the same as using the &#8211;databases option and naming all the databases on<br />
           the command line</p></blockquote>
<p>附2:<br />
在ubuntu10.04系统下, mysql服务的操作命令<br />
sudo /etc/init.d/mysql start/stop/restart<br />
sudo service mysql start/stop/restart</p>
<p>参考:<br />
<a href="http://hi.baidu.com/higkoo/blog/item/4d52f05241dab9050df3e3ce.html">http://hi.baidu.com/higkoo/blog/item/4d52f05241dab9050df3e3ce.html</a><br />
<a href="http://www.lampblog.net/2011/01/linux%E4%B8%8B%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6%E5%92%8C%E6%96%87%E4%BB%B6%E5%A4%B9%E5%A4%A7%E5%B0%8F%E7%9A%84df%E5%92%8Cdu%E5%91%BD%E4%BB%A4/">http://www.lampblog.net/2011/01/linux%E4%B8%8B%E6%9F%A5%E7%9C%8B%E6%96%87%E4%BB%B6%E5%92%8C%E6%96%87%E4%BB%B6%E5%A4%B9%E5%A4%A7%E5%B0%8F%E7%9A%84df%E5%92%8Cdu%E5%91%BD%E4%BB%A4/</a></p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/tips/mysql_innodb_ibdata_file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在eclipse中查看android源码</title>
		<link>http://www.liubida.com/tips/see_android_source_in_eclipse/</link>
		<comments>http://www.liubida.com/tips/see_android_source_in_eclipse/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 07:37:32 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[eclipse android source 源码]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=226</guid>
		<description><![CDATA[开发android不能看到源码实在是一件非常不爽的事情, 不过要把android的源码attacht到eclipse里也不是那么的容易. (真不知道google是怎么想的, 把这个东西搞的这么麻烦..).所以得空的时候, 花了点时间, 把源码这货给搞定了. 需要提醒的是,这活对网络要求很高, 源码下载大概得2-3G, 所以您要是网络不太好, 推荐您在晚上睡觉前开始做这事儿, 一个晚上应该能下完. 大致的环境: eclipse: Indigo os: ubuntu11.04(32bit) 需要预装的命令包: git : sudo apt-get install git-core 1. 先到android source上下载源码包命令很简单, 照做就行. “To check out...]]></description>
			<content:encoded><![CDATA[<p>开发android不能看到源码实在是一件非常不爽的事情, 不过要把android的源码attacht到eclipse里也不是那么的容易. (真不知道google是怎么想的, 把这个东西搞的这么麻烦..).所以得空的时候, 花了点时间, 把源码这货给搞定了. 需要提醒的是,这活对网络要求很高, 源码下载大概得2-3G, 所以您要是网络不太好, 推荐您在晚上睡觉前开始做这事儿, 一个晚上应该能下完.</p>
<p>大致的环境:<br />
eclipse: Indigo<br />
os: ubuntu11.04(32bit)</p>
<p>需要预装的命令包:<br />
git : sudo apt-get install git-core</p>
<p><strong>1. 先到<a href="http://source.android.com/source/downloading.html">android source</a>上下载源码包</strong>命令很简单, 照做就行. </p>
<p>“To check out a branch other than “master”, specify it with -b:<br />
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1&#8243;</p>
<p>这个命令的意思是去下载android-4.0.1_r1分支, 而不是从主干(master)上下东西. 具体查看每个分支的名字, 可以这样点这里.<br />
如果这个步骤还不是很清楚, 可以参看这个post http://android.yaohuiji.com/archives/2652</p>
<p>执行 “$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1&#8243;时<br />
要进入你要下载的目的文件夹($DEST)里面, 不然会载的满地都是. 下载的时候会提示你输入用户名, 邮箱之类的, 按部就班即可.</p>
<p><strong>2.下载完成之后, 在你的$DEST目录下就会有若干的文件夹</strong>, dalvik, bootable之类的, 这些就是android的源文件了, 有底层的cpp, 也有应用层的java. 但是我们需要的java散落在各个目录下, 如何整理起来使之能够attach到eclipse上呢?<br />
在<a href="http://blog.michael-forster.de/2008/12/view-android-source-code-in-eclipse.html?showComment=1324861622343#c6560476551216066901 ">这里</a>, 作者写了个python脚本, 能够按照包名来抓取所需的java文件.<span id="more-226"></span></p>
<div class="source" style="color: rgb(0, 0, 0); background-color: rgb(249, 247, 237); font-family: Consolas, 'Lucida Console', 'Courier New'; "> <span style="color: rgb(0, 0, 0); ">from</span> <span style="color: rgb(0, 0, 0); ">__future__</span> <span style="color: rgb(0, 0, 0); ">import</span> <span style="color: rgb(0, 0, 0); ">with_statement</span>&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; "># for Python &lt; 2.6</span></p>
<p> <span style="color: rgb(0, 0, 0); ">import</span> <span style="color: rgb(0, 0, 0); ">os</span><br /> <span style="color: rgb(0, 0, 0); ">import</span> <span style="color: rgb(0, 0, 0); ">re</span><br /> <span style="color: rgb(0, 0, 0); ">import</span> <span style="color: rgb(0, 0, 0); ">zipfile</span></p>
<p> <span style="color: rgb(0, 136, 0); font-style: italic; "># open a zip file</span><br /> <span style="color: rgb(0, 0, 0); ">DST_FILE</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 255); ">&#39;sources.zip&#39;</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> <span style="color: rgb(0, 0, 0); ">os</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">path</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">exists</span>(<span style="color: rgb(0, 0, 0); ">DST_FILE</span><span style="color: rgb(0, 0, 0); ">):</span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">print</span> <span style="color: rgb(0, 0, 0); ">DST_FILE</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;already exists&quot;</span><br /> &nbsp; <span style="color: rgb(0, 0, 0); ">exit</span>(<span style="color: rgb(0, 0, 255); ">1</span>)<br /> <span style="color: rgb(0, 0, 0); ">zip</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">zipfile</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">ZipFile</span>(<span style="color: rgb(0, 0, 0); ">DST_FILE</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&#39;w&#39;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">zipfile</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">ZIP_DEFLATED</span>)</p>
<p> <span style="color: rgb(0, 136, 0); font-style: italic; "># some files are duplicated, copy them only once</span><br /> <span style="color: rgb(0, 0, 0); ">written</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">{}</span></p>
<p> <span style="color: rgb(0, 136, 0); font-style: italic; "># iterate over all Java files</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> <span style="color: rgb(0, 0, 0); ">dir</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">subdirs</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">files</span> <span style="font-weight: bold; ">in</span> <span style="color: rgb(0, 0, 0); ">os</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">walk</span>(<span style="color: rgb(0, 0, 255); ">&#39;.&#39;</span><span style="color: rgb(0, 0, 0); ">):</span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> <span style="color: rgb(0, 0, 0); ">file</span> <span style="font-weight: bold; ">in</span> <span style="color: rgb(0, 0, 0); ">files</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> <span style="color: rgb(0, 0, 0); ">file</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">endswith</span>(<span style="color: rgb(0, 0, 255); ">&#39;.java&#39;</span><span style="color: rgb(0, 0, 0); ">):</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; "># search package name</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">path</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">os</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">path</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">join</span>(<span style="color: rgb(0, 0, 0); ">dir</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">file</span>)<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">with</span> <span style="color: rgb(0, 0, 0); ">open</span>(<span style="color: rgb(0, 0, 0); ">path</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">as</span> <span style="color: rgb(0, 0, 0); ">f</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> <span style="color: rgb(0, 0, 0); ">line</span> <span style="font-weight: bold; ">in</span> <span style="color: rgb(0, 0, 0); ">f</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">match</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">re</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">match</span>(<span style="color: rgb(0, 0, 255); ">r&#39;\s*package\s+([a-zA-Z0-9\._]+);&#39;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">line</span>)<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> <span style="color: rgb(0, 0, 0); ">match</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; "># copy source into the zip file using the package as path</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">zippath</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">match</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">group</span>(<span style="color: rgb(0, 0, 255); ">1</span>)<span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">replace</span>(<span style="color: rgb(0, 0, 255); ">&#39;.&#39;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&#39;/&#39;</span>) <span style="color: rgb(0, 0, 0); ">+</span> <span style="color: rgb(0, 0, 255); ">&#39;/&#39;</span> <span style="color: rgb(0, 0, 0); ">+</span> <span style="color: rgb(0, 0, 0); ">file</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> <span style="color: rgb(0, 0, 0); ">zippath</span> <span style="font-weight: bold; ">not</span> <span style="font-weight: bold; ">in</span> <span style="color: rgb(0, 0, 0); ">written</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">written</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 0); ">zippath</span><span style="color: rgb(0, 0, 0); ">]</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 255); ">1</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">zip</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">write</span>(<span style="color: rgb(0, 0, 0); ">path</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">zippath</span>)<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> <span style="color: rgb(0, 0, 0); ">zip</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(0, 0, 0); ">close</span>()</div>
<p>在你的$DEST目录下执行这个脚本, 就会生成source.zip文件. 然后在eclipse里面attach这个文件就可以看到source code了.</p>
<p><strong>3. 为了避免每个项目都要attach这个文件</strong>, 把source.zip解压到eclipse默认的source位置: /android-sdk/platforms/android-14/sources, 就一劳永逸了.</p>
<p>公司的网速不坑爹, 源码一会就下载完成, 我把最后打包好的sources.zip放出来, 希望能给需要的朋友一点帮助.<br />
android-14_sources.zip  对应的branch: android-4.0.1_r1<br />
android-7_sources.zip   对应的branch: android-2.1_r1</p>
<p>对于一般的开发时看源码的需求来说, 这两个版本基本上就够用了, 如果的确有需求某个版本的, 可以到国内这个post去看看, 他提供了直接的源码压缩包下载, 如果需要自行编译android玩玩而网速又不行的朋友可以去看看, 我试了下, 速度30KB/s左右.</p>
<p>http://zhuwenhao.com/950/%E6%8A%80%E6%9C%AF/%E8%87%AA%E7%94%B1%E8%BD%AF%E4%BB%B6%E7%A4%BE%E5%8C%BA/android/%E6%8F%90%E4%BE%9B%E6%9C%80%E6%96%B0%EF%BC%8C%E6%9C%80%E5%AE%8C%E6%95%B4%E7%9A%84android%E6%BA%90%E4%BB%A3%E7%A0%81%E5%8E%8B%E7%BC%A9%E5%8C%85%E4%B8%8B%E8%BD%BD/</p>
<p>当然, 也可以留言给我, 帮你下载并打包出sources.zip的.<br />
<br/><br />
<strong>感谢这些朋友:</strong><br />
<a href="http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/">http://stuffthathappens.com/blog/2008/11/01/browsing-android-source-in-eclipse/</a><br />
<a href="http://blog.michael-forster.de/2008/12/view-android-source-code-in-eclipse.html?showComment=1324861622343#c6560476551216066901">http://blog.michael-forster.de/2008/12/view-android-source-code-in-eclipse.html?showComment=1324861622343#c6560476551216066901</a><br />
<a href="http://android.opensourceror.org/2010/01/18/android-source">http://android.opensourceror.org/2010/01/18/android-source</a>  &#8211;这个网址的sources.zip下载失效了.</p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/tips/see_android_source_in_eclipse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>查看android源码的branch列表</title>
		<link>http://www.liubida.com/tips/get_the_android_source_branch_list/</link>
		<comments>http://www.liubida.com/tips/get_the_android_source_branch_list/#comments</comments>
		<pubDate>Sun, 25 Dec 2011 20:17:07 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[android]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=216</guid>
		<description><![CDATA[Following directions on Android&#8217;s main website to pull down sources, I&#8217;m looking at this command to initialize repo for the cupcake branch: repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake How can...]]></description>
			<content:encoded><![CDATA[<p>Following directions on Android&#8217;s main website to pull down sources, I&#8217;m looking at this command to initialize repo for the cupcake branch:<br />
repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake</p>
<p>How can I view all available branches besides cupcake, i.e eclair, donut, etc&#8230;?<br />
$ git clone git://android.git.kernel.org/platform/manifest.git<br />
$ cd manifest<br />
$ git branch -r</p>
<p><a href="http://stackoverflow.com/questions/2874347/how-to-display-available-branches-in-android-source-tree">来自这里</a></p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/tips/get_the_android_source_branch_list/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>遇到的死锁问题分析</title>
		<link>http://www.liubida.com/programming_language/dead_lock_analysis/</link>
		<comments>http://www.liubida.com/programming_language/dead_lock_analysis/#comments</comments>
		<pubDate>Wed, 23 Nov 2011 12:02:48 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[多线程]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[死锁]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=201</guid>
		<description><![CDATA[转载请注明出处: http://www.liubida.com/programming_language/dead_lock_analysis 前几天遇到一个问题, 导致连续3天的虚拟机数据没有更新成功, 后来通过监控发现每天的定时任务会报出大量的异常, 异常信息直指数据库的DeadLock 异常和堆栈的部分信息如下: com.alibaba.armory.exception.ArmoryServiceException: SqlMapClient operation; SQL []; --- The error occurred in ibatis/VmServer.xml. --- The error occurred while applying a parameter map. --- Check the...]]></description>
			<content:encoded><![CDATA[<p>转载请注明出处: <a href="http://www.liubida.com/programming_language/dead_lock_analysis" target="_blank">http://www.liubida.com/programming_language/dead_lock_analysis</a><br/><br />
前几天遇到一个问题, 导致连续3天的虚拟机数据没有更新成功, 后来通过监控发现每天的定时任务会报出大量的异常, 异常信息直指数据库的DeadLock<br />
异常和堆栈的部分信息如下:<br />
<code>com.alibaba.armory.exception.ArmoryServiceException: SqlMapClient operation; SQL [];<br />
--- The error occurred in ibatis/VmServer.xml.<br />
--- The error occurred while applying a parameter map.<br />
--- Check the VmServer.updateVMStateByHostId-InlineParameterMap.<br />
--- Check the statement (update failed).<br />
--- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:<br />
--- The error occurred in ibatis/VmServer.xml.<br />
--- The error occurred while applying a parameter map.<br />
--- Check the VmServer.updateVMStateByHostId-InlineParameterMap.<br />
--- Check the statement (update failed).<br />
--- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction<br />
	at com.alibaba.armory.exchange.dragoon.data.DragoonDataHandler.refreshVMToHost(DragoonDataHandler.java:432)<br />
	at ...</code></p>
<p>执行的定时任务是对宿主机刷新数据. 任务由很多线程执行, 并且在涉及到数据库update的方法时, 使用了spring的@Transactional来标记为事务处理, 我们定义为事务A.<br />
比较关键的几个sql语句,<br />
<code>1. select lock_state from server where id = ? for update<br />
2. update server set lock_state = ? where id = ?<br />
3. select s.*, d.*, s.id as server_id, ast.po_number as po,   ast.in_service_date as buy_time,   ast.cost_value as original_cost,   v.host_id as host_id,   v.vm_index as vm_index,   v.vm_resource as vm_resource,   v.state as vm_state,   v.op_state as op_state,   cpu.amount as cpu_amount,   cpu.core_num as cpu_core,   mssize as mem_size   from server s   left join device_base d on s.device_base_id = d.id   left join device_base_asset ast on ast.tag_number = d.assets_num   right join vmserver v on v.server_id = s.id   left join cpu on s.id = cpu.server_id   left join (select server_id,sum(size) mssize from memory_slot group by server_id) mstmp on   mstmp.server_id = s.id   where v.host_id in   (    ?   )<br />
4. update vmserver set state = ? where host_id = ?<br />
5. update server set lock_state = ? where id = ?  </code><span id="more-201"></span></p>
<p>我们对着这几个简单的语句研究了半天也没发现有什么不妥, 只是语句1的”for update”有点点风险.<br />
mysql中使用<a href="http://www.neo.com.tw/archives/900" target="_blank">for update</a>, 必须针对InnoDB, 并且在一个事务中, 才能起作用. 它会对查询的数据加上行锁,或者表锁. 在我们的场景中, 是加上了行锁.</p>
<p>后来通过查看<a href="http://imysql.cn/2008_05_22_walk_through_show_innodb_status" target="_blank">show innodb status</a>的输出,<br />
<code>------------------------<br />
LATEST DETECTED DEADLOCK<br />
------------------------<br />
111123 13:30:02<br />
*** (1) TRANSACTION:<br />
TRANSACTION 3 4124628169, ACTIVE 0 sec, process no 3818, OS thread id 1184938304 starting index read<br />
mysql tables in use 3, locked 3<br />
LOCK WAIT 28 lock struct(s), heap size 6752, 429 row lock(s)<br />
MySQL thread id 2015123, query id 2099159826 172.22.24.98 armory Sending data<br />
update vmserver set op_state='UPDATE_FINISH' where host_id in (   select id   from server where device_base_id in(   select id from device_base where   service_tag in   (    '030JNA10A2000060'   )   )   )<br />
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:<br />
RECORD LOCKS space id 1857 page no 203 n bits 200 index `PRIMARY` of table `armory`.`server` trx id 3 4124628169 lock mode S locks rec but not gap waiting<br />
Record lock, heap no 122 PHYSICAL RECORD: n_fields 19; compact format; info bits 0<br />
 0: len 4; hex 800001b9; asc     ;; 1: len 6; hex 0003f5d8d4c5; asc       ;; 2: len 7; hex 00000340021a01; asc    @   ;; 3: len 4; hex 80000534; asc    4;; 4: len 6; hex 78636e2d7879; asc xcn-xy;; 5: SQL NULL; 6: len 4; hex 4bbc094b; asc K  K;; 7: len 4; hex 4ecc84da; asc N   ;; 8: len 5; hex 312e322e33; asc 1.2.3;; 9: len 13; hex 5550444154455f46494e495348; asc UPDATE_FINISH;; 10: len 1; hex 01; asc  ;; 11: len 1; hex 08; asc  ;; 12: len 7; hex 312e312e313135; asc 1.1.115;; 13: len 13; hex 5550444154455f46494e495348; asc UPDATE_FINISH;; 14: len 1; hex 88; asc  ;; 15: len 10; hex 4e4f5f494e5354414c4c; asc NO_INSTALL;; 16: len 7; hex 6e6f4572726f72; asc noError;; 17: len 7; hex 6e6f4572726f72; asc noError;; 18: SQL NULL;</p>
<p>*** (2) TRANSACTION:<br />
TRANSACTION 3 4124628165, ACTIVE 0 sec, process no 3818, OS thread id 1224608064 starting index read<br />
mysql tables in use 1, locked 1<br />
5 lock struct(s), heap size 1216, 3 row lock(s), undo log entries 1<br />
MySQL thread id 1998379, query id 2099159869 172.22.24.98 armory Updating<br />
update vmserver set state = 'unknown' where host_id = '441'<br />
*** (2) HOLDS THE LOCK(S):<br />
RECORD LOCKS space id 1857 page no 203 n bits 200 index `PRIMARY` of table `armory`.`server` trx id 3 4124628165 lock_mode X locks rec but not gap<br />
Record lock, heap no 122 PHYSICAL RECORD: n_fields 19; compact format; info bits 0<br />
 0: len 4; hex 800001b9; asc     ;; 1: len 6; hex 0003f5d8d4c5; asc       ;; 2: len 7; hex 00000340021a01; asc    @   ;; 3: len 4; hex 80000534; asc    4;; 4: len 6; hex 78636e2d7879; asc xcn-xy;; 5: SQL NULL; 6: len 4; hex 4bbc094b; asc K  K;; 7: len 4; hex 4ecc84da; asc N   ;; 8: len 5; hex 312e322e33; asc 1.2.3;; 9: len 13; hex 5550444154455f46494e495348; asc UPDATE_FINISH;; 10: len 1; hex 01; asc  ;; 11: len 1; hex 08; asc  ;; 12: len 7; hex 312e312e313135; asc 1.1.115;; 13: len 13; hex 5550444154455f46494e495348; asc UPDATE_FINISH;; 14: len 1; hex 88; asc  ;; 15: len 10; hex 4e4f5f494e5354414c4c; asc NO_INSTALL;; 16: len 7; hex 6e6f4572726f72; asc noError;; 17: len 7; hex 6e6f4572726f72; asc noError;; 18: SQL NULL;</p>
<p>*** (2) WAITING FOR THIS LOCK TO BE GRANTED:<br />
RECORD LOCKS space id 1693 page no 8 n bits 232 index `PRIMARY` of table `armory`.`vmserver` trx id 3 4124628165 lock_mode X locks rec but not gap waiting<br />
Record lock, heap no 3 PHYSICAL RECORD: n_fields 11; compact format; info bits 0<br />
 0: len 4; hex 000002da; asc     ;; 1: len 6; hex 0003f5d8ca57; asc      W;; 2: len 7; hex 0000034007089b; asc    @   ;; 3: len 4; hex 00003150; asc   1P;; 4: len 4; hex 000001b9; asc     ;; 5: len 4; hex 00000001; asc     ;; 6: len 2; hex 6f6e; asc on;; 7: len 8; hex 5550444154494e47; asc UPDATING;; 8: len 4; hex 4d2d00ef; asc M-  ;; 9: len 4; hex 4ecc84d4; asc N   ;; 10: len 4; hex 80000002; asc     ;;</p>
<p>*** WE ROLL BACK TRANSACTION (2)</code></p>
<p>明确了问题的关键是这两条语句<br />
<code>a. update vmserver set op_state='UPDATE_FINISH' where host_id in (   select id   from server where device_base_id in(   select id from device_base where   service_tag in ('030JNA10A2000060')))<br />
b. update vmserver set state = 'unknown' where host_id = '441'</code><br />
原来在这个刷新数据的方法后面, 还有一个更新操作状态(op_state)的sql, 可恶的它居然也是一个事务处理(叫事务B). 从输出的信息已经明确的发现死锁就是发生在这两个事务当中, 那么这两个事务是肿么就死锁了呢?<br />
先来看语句b, 这个语句b就是方法里的语句4, 基本上是只会加行锁的, 除非vmserver中查不到host_id的的值的记录, 这种情况下该语句会由行锁上升到表锁, 但是问题不在这儿.</p>
<p>这里需要说明下, 虽然输出信息里报的是两个transaction的这两个语句死锁, 但是一般来说, 这只能表明这两个语句是这两个事务(A和B)死锁时的最后的语句. 因为事务B只有语句a, 自然就是语句a导致死锁, 而事务A的语句就多了, 见前面的语句1,2,3. 我们思考之后, 把嫌疑放在语句1上.<br />
对事务B的语句a的分析:<br />
) 这个语句写的很搓, 双层嵌套in查询, 会分别对device_base, server和vmserver分别查询之后再update<br />
) vmserver表中host_id没有建索引, 对vmserver是表锁. (为什么vmserver是表锁, 而不是只对host_id的那几行加锁? 因为host_id in (&#8230;) 在查询前是无法确定到底是要锁哪几行; 并且server中的device_base_id没有加索引, 所以server是表锁, 这也导致vmserver直接表锁)<br />
) 这个语句写的很搓, 双层嵌套in查询, 这会导致整条语句的锁会是这三个表的锁中最强的一个.<br />
) 加锁的顺序是先对vmserver加表锁(意向锁), 然后对server表加表锁, 然后去做update</p>
<p>对事务B的语句1和语句4分析:<br />
) 本来select是不需要锁的, 但是由于”for update”, 所以需要对server加上行锁<br />
) 然后后面的语句4, 也就是语句b, 需要对vmserver加行锁</p>
<p>问题来了,<br />
事务A的加锁顺序是vmserver(表锁)->server(表锁)<br />
事务B的加锁顺序是server(行锁)->vmserver(行锁)<br />
fk~!<br />
<div id="attachment_204" class="wp-caption alignnone" style="width: 310px"><a href="http://www.liubida.com/wordpress/wp-content/uploads/2011/11/deadlock_analysis.jpg"><img src="http://www.liubida.com/wordpress/wp-content/uploads/2011/11/deadlock_analysis-300x214.jpg" alt="deadlock_analysis" title="deadlock_analysis" width="300" height="214" class="size-medium wp-image-204" /></a><p class="wp-caption-text">死锁分析</p></div><br />
死锁重现:<br />
1. 线程1完成事务A, 进入事务B, 切换到线程2<br />
2. 线程2进入事务A, 对server加上行锁, 切换到线程1<br />
3. 线程1对vmserver加上表锁, 尝试对server加表锁, 因失败而等待, 切换到线程2<br />
4. 线程2尝试对vmserver加行锁, 因失败而等待, 至此, 死锁已成</p>
<p>可以看见, 死锁的原因:<br />
1. 事务A和B中对vmserver和server表加锁的相反顺序<br />
2. 本来多线程之间都是各自锁自己相关的行, 由于事务B的sql写法不规范, 导致线程在事务B时升级为表锁</p>
<p>修正方法:<br />
1. 修改事务B的update语句<br />
<code>update vmserver vms<br />
left join server      s  on s.id  = vms.host_id<br />
left join device_base db on db.id = s.device_base_id<br />
set vms.op_state= ?<br />
where db.service_tag in (?,?,?...)</code><br />
这样, 事务B的锁就退化为行锁, 那么多个线程就是各自锁各自的行, 应该不会死锁了.</p>
<p>tips:<br />
1. 假设有表A(id, sid, name, comment), id是主键, sid建有索引, 表数据100条, 一个sid可能对应多个id.<br />
那么当使用sid来对表进行update时, update A set comment = ? where sid = ?<br />
sid=0, 有20条记录,<br />
sid=1, 有30条记录,<br />
sid=2, 有40条记录,<br />
sid=3, 有10条记录,<br />
这时候, 就有可能在sid=2或sid=3时就是对整张表加锁<br />
2. “show innodb status”的输出信息里报的是两个transaction的两个语句死锁, 但是这只能表明这两个语句是这两个事务(A和B)死锁时的最后的语句, 并不能说明死锁一定是由这两个语句造成.<br />
3. update的逻辑代码要加事务, sql语句不能用in<br />
4. 由于对mysql的不熟悉, 导致我们刚开始一直没有找到问题的根源在哪里..工具很重要</p>
<p>后话:<br />
有人问我为什么要在事务A中的select后面加for update, 其实这里是为了防止, 在对某台宿主机刷新数据时有用户会对用户执行操作而导致的状态异常, 和多线程之间的刷新没有关系.</p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/programming_language/dead_lock_analysis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>质数小求</title>
		<link>http://www.liubida.com/programming_language/prime/</link>
		<comments>http://www.liubida.com/programming_language/prime/#comments</comments>
		<pubDate>Tue, 06 Sep 2011 13:46:45 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[数学]]></category>
		<category><![CDATA[算法]]></category>

		<guid isPermaLink="false">http://liubida.sinaapp.com/?p=57</guid>
		<description><![CDATA[实践了一些求质数的方法，包括尝试相除法和筛选法。]]></description>
			<content:encoded><![CDATA[<p>转载请注明出处: <a href="http://www.liubida.com/programming_language/prime" title="http://www.liubida.com/programming_language/prime" target="_blank">http://www.liubida.com/programming_language/prime/</a><br />
&nbsp;<br /><strong>什么是质数？</strong><br />
1. 大于1的正整数<br />
2. 只能被1和自己整除<br />
满足1和2的就是一个质数（也叫素数），反之被叫做合数。<br />
&nbsp;<br />
<strong>质数相关的东西</strong><br />
数学上，任何一个整数均可表示为质数的乘积，所以质数在数学上很重要。虽然从质数中很难得到一些定理。<br />
公元前3世纪，古希腊数学家欧几里德证明了质数的数目是无穷的。而最近几年，由陶哲轩和格林证明了“存在任意长度的质数等差数列”这一重要命题。我不打算就这些个数学证明写点什么，就简单的就这个命题举一些例子吧。<br />
命题：存在任意长度的质数等差数列，它的意思：能够找到一个由质数构成的等差数列，其长度为指定的L。<br />
比如，长度为5的质数等差数列：5，17，29，41，53；<br />
长度为10的质数等差数列：199，409，619，829，1039，1249，1459，1669，1879，2089；<br />
到目前为止，已知的质数等差数列的长度为23，其数列的第一个数是56211383760397，间隔常数为44546738095860。<br />
对于一个随机的正整数n来说，它有50%的几率能被2整除，33%的几率能被3整除。可以计算出，n有88%的几率能够被100以内的某个数整除，有92%的几率能够被1000以内的某个数整除。基于这些分析，关于质数分布的事实是：随着正整数数值的增加，质数的分布变得越来越稀疏。<br />
&nbsp;<br />
那么，我们的问题是？<br />
如何判断正整数n是否为一个质数？<br />
请列出1000，10000以内的质数？<br />
现在求质数的方法有很多，wiki上列举了AKS/Elliptic curve/Miller-Rabin/Solovay-Strassen/Fermat等这些专业方法。但是我们平时用的一般是尝试相除法和筛选法。<br /><span id="more-57"></span><br />
&nbsp;<br />
<strong><em>尝试相除法&#8211;Trial division</em></strong><br />
算法描述：对于给定的正整数n，依次从集合[2...n-1]中取数，如果存在m使得n能被m整除，那么n就不是质数，反之n为质数。<br />
java代码：<span style="color: #3366ff;"><br />
&nbsp;&nbsp;&nbsp;&nbsp; boolean IsPrime1(int n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (n &lt;= 1)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt; n-1 ; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (n % i == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span><br />
这种方法有一个优化。<br />
注意到当n&gt;2时,n-1肯定不能被n整除,所以循环边界设定在i&lt;n-1,对这一点我们多想几步.<br />
当n=4时，n-1不能被整除;<br />
当n=5时，n-1,n-2,n-3不能被整除;<br />
当n=10时，n-1,n-2,n-3,n-4,n-5等不能被整除;<br />
当n=100时，n-1,n-2,n-3,n-4,n-5,n-5等不能被整除;<br />
可以发现,其实有很多m是没有必要的,比如n=100时,51~99的数都没法被其整除,<br />
那么对这些除数的判定是否有更简单的方法呢?<br />
我们假设存在正整数p和q,它们使得n=pq成立.<br />
p=1,q=n;//其中的一个解<br />
p=√n,q=√n; //考虑n是一个平方数,则存在这样一对解<br />
p=n,q=1;//随着p逐渐增大,对应的q必须逐渐的减小,才能使得等式可能成立,直到得到最后的一个解.<br />
通过分析得出,p是在逐渐增大,q是在逐渐减小.那么实际上,我们只需判定[2,√n]区间的数能否被整除就可以了.<br />
假设,p=√n+r能被整除,则对应q则必定小于√n,则在对[2,√n]区间内进行判定时就能找出一对解.<br />
所以,除数的判定区间可以缩小到[2,√n].<br />
算法描述: 对于给定的正整数n，依次从集合[2,√n]中取数，如果存在m使得n能被m整除，那么n就不是质数，反之n为质数。<br />
java代码:<span style="color: #3366ff;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean IsPrime2(int n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (n &lt;= 1) return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int b = (int) Math.sqrt(n);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= b; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (n % i == 0) return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span></p>
<p><strong><em>筛选法&#8211;Sieve of Eratosthenes</em></strong></p>
<blockquote><p>In mathematics, the Sieve of Eratosthenes ancient algorithm for finding all prime numbers up to a specified integer. It works efficiently for the smaller primes (below 10 million). It was created by Eratosthenes, an ancient Greek mathematician. However, none of his mathematical works survived—the sieve was described and attributed to Eratosthenes in the Introduction to Arithmetic by Nicomachus.<br />
&#8211;摘自wiki: <a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes</a></p></blockquote>
<p>
筛选法说起来还是比较简单的,它的具体过程可以看图<br />
<br /><img alt="New_Animation_Sieve_of_Eratosthenes.gif" src="http://upload.wikimedia.org/wikipedia/commons/8/8c/New_Animation_Sieve_of_Eratosthenes.gif" width="554" height="445"><br />
<br />
&nbsp;<br />
目的:列出&lt;=n的所有质数<br />
算法描述:<br />
1. 创建一个从2到n的顺序列表List:[2,3,4,...,n]<br />
2. 2是第一个质数,初始时让p=2<br />
3. 从p开始,在List中标记出p的倍数(2倍开始,2p,3p,4p&#8230;)<br />
4. 找出List中p之后的没有被标记的那个数,将其值赋给p<br />
5. 重复步骤3,步骤4,直到List中p之后的所有数都被标记<br />
6. List中未被标记的数就是质数<br />
java代码:<span style="color: #3366ff;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;static void ListPrime2(int n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 标记0为质数,1为合数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int[] primeList = new int[n + 1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= n; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (primeList[i] == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// 加法版<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int j = i + i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; j = j + i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt; ret = new ArrayList&lt;Integer&gt;(10000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= n; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (primeList[i] == 0) {<br />
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(i + &quot; &quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><br />
对于这个算法有几点可以优化:<br />
a. step3: 开始比较p的倍数可以从p^2开始标记. 因为p*(p-1),p*(p-2),p*(p-3),&#8230;这些已经在前面被(p-i)标记过了,即p^2之前的都已经被判定标记过了.<br />
b. step5: 由上面可知,p^2之前的都已经被判定标记过,则当p^2&gt;=n时,说明n之前的都被判定标记过,筛选结束.<br />
c. 当p=2时,所有的偶数都会被标记;则当p&gt;2时,p的偶数倍可以直接被忽略(已经被p=2标记过).p=1p,每次标记的步长为2p, 则标记的index依次为1p,3p,5p,&#8230;<br />
java代码:<span style="color: #3366ff;"><br />
static void ListPrime3(int n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 标记0为质数,1为合数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int[] primeList = new int[n + 1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= n; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (primeList[i] == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int j = i * i;&nbsp;&nbsp;&nbsp;&nbsp;//从p^2开始标记<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (j &gt; n) break; //如果p^2&gt;n,则列表中的数已经被标记完<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (i &gt; 2) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//当p&gt;2时,步长为2p<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + i + i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt; ret = new ArrayList&lt;Integer&gt;(10000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= n; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (primeList[i] == 0) {<br />
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(i + &quot; &quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><br />
结合前面的根号n(只筛选根号n之前的数), 下面的应该更快!<br />
经过实际测试,Prime4和Prime3其实差不多&#8230;为什么呢?因为if (j &gt; n) break;这一句使两者的实际循环次数一样<br />
java代码:<span style="color: #3366ff;"><br />
&nbsp;&nbsp;&nbsp;&nbsp;static void ListPrime4(int n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/**<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 标记0为质数,1为合数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int[] primeList = new int[n + 1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int sqrt = (int)Math.sqrt(n);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= sqrt; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (primeList[i] == 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int j = i * i;&nbsp;&nbsp;&nbsp;&nbsp;//从p^2开始标记<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//if (j &gt; n) break; //如果p^2&gt;n,则列表中的数已经被标记完<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (i &gt; 2) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//当p&gt;2时,步长为2p<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + i + i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt; ret = new ArrayList&lt;Integer&gt;(10000);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= n; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (primeList[i] == 0) {<br />
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.print(i + &quot; &quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><br />
&nbsp;<br />
&nbsp;<br />
wiki链接：<br />
<a href="http://en.wikipedia.org/wiki/Prime_number">http://en.wikipedia.org/wiki/Prime_number</a><br />
<a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes</a></p>
<p>今天小猪跑来要和我比.虽然败了但是他用了个讨巧的方法, 我也借鉴来. 果然快了许多. 2000w 668ms <img src='http://www.liubida.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  <br />
Java代码: <span style="color: #3366ff;"><br />
static void ListPrime(int n) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * false为质数,true为合数 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean[] primeList = new boolean[n + 1];&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 2; i &lt;= n; i++) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!primeList[i]) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int j = i * i;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (j &gt; n)&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (i &gt; 2) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = true;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + i + i;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (j &lt;= n) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;primeList[j] = true;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j = j + i;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;Integer&gt; ret = new ArrayList&lt;Integer&gt;(10000);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(2);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 3; i &lt;= n;) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (!primeList[i]) {&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//System.out.print(i + &quot; &quot;);&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ret.add(i);&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i += 2;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
</span></p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/programming_language/prime/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>lucene的分词和过滤简介</title>
		<link>http://www.liubida.com/programming_language/lucene_analyzer_intro/</link>
		<comments>http://www.liubida.com/programming_language/lucene_analyzer_intro/#comments</comments>
		<pubDate>Thu, 18 Aug 2011 12:38:54 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[lucene]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=154</guid>
		<description><![CDATA[转载请注明出处: http://www.liubida.com/uncategorized/lucene_analyzer_intro/ 没接触过lucene的童鞋可以看看 这篇文章, 算是lucence入门比较好的文章, 读完之后可以对lucene有个简单的认识. 我也是最近有项目用到了lucene, 具体实践是对数据库的某个字段做索引, 实现了一个针对该字段匹配查询. 有点意思. 然后就趁机看了下lucene中分析器(Analyzer)的一些代码, 觉得它的分词和过滤的设计还是蛮有意思的. lucene的分析器的功能就是对输入的数据进行分词(对文本资源进行切分, 将文本按规则切分为一个个可以进入索引的最小单位)和过滤(对最小单位进行预处理, 比如大写转小写). 在lucene中, 所有的分析器都继承自抽象类Analyzer(org.apache.lucene.analysis.Analyzer). Analyzer的代码里只定义了两个毫无意义的方法. 如下所示: /** An Analyzer builds TokenStreams, which analyze text.&#160; It thus represents...]]></description>
			<content:encoded><![CDATA[<p>转载请注明出处: <a href="http://www.liubida.com/uncategorized/lucene_analyzer_intro/" title="http://www.liubida.com/uncategorized/lucene_analyzer_intro/" target="_blank">http://www.liubida.com/uncategorized/lucene_analyzer_intro/</a></p>
<p>没接触过lucene的童鞋可以看看 <a href="http://www.chedong.com/tech/lucene.html" title="http://www.chedong.com/tech/lucene.html" target="_blank">这篇文章</a>, 算是lucence入门比较好的文章, 读完之后可以对lucene有个简单的认识. 我也是最近有项目用到了lucene, 具体实践是对数据库的某个字段做索引, 实现了一个针对该字段匹配查询. 有点意思. 然后就趁机看了下lucene中分析器(Analyzer)的一些代码, 觉得它的分词和过滤的设计还是蛮有意思的.</p>
<p>lucene的分析器的功能就是对输入的数据进行分词(对文本资源进行切分, 将文本按规则切分为一个个可以进入索引的最小单位)和过滤(对最小单位进行预处理, 比如大写转小写). 在lucene中, 所有的分析器都继承自抽象类Analyzer(org.apache.lucene.analysis.Analyzer). Analyzer的代码里只定义了两个毫无意义的方法. 如下所示:</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 136, 0); font-style: italic; ">/** An Analyzer builds TokenStreams, which analyze text.&nbsp; It thus represents a</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; policy for extracting index terms from text.</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; &lt;p&gt;</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; Typical implementations first build a Tokenizer, which breaks the stream of</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; characters from the Reader into raw Tokens.&nbsp; One or more TokenFilters may</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; then be applied to the output of the Tokenizer.</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; &lt;p&gt;</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; WARNING: You must override one of the methods defined by this class in your</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> *&nbsp; subclass or the Analyzer will enter an infinite loop.</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> */</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">abstract</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">Analyzer</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/** Creates a TokenStream which tokenizes all the text in the provided</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp; Reader.&nbsp; Default implementation forwards to tokenStream(Reader) for </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp; compatibility with older version.&nbsp; Override to allow Analyzer to choose </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp; strategy based on document and/or field.&nbsp; Must be able to handle null</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp; field name for backward compatibility. */</span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">TokenStream</span> <span style="color: rgb(0, 0, 0); ">tokenStream</span>(<span style="color: rgb(0, 0, 0); ">String</span> <span style="color: rgb(0, 0, 0); ">fieldName</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">Reader</span> <span style="color: rgb(0, 0, 0); ">reader</span>)<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">// implemented for backward compatibility</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 0); ">tokenStream</span>(<span style="color: rgb(0, 0, 0); ">reader</span>);<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> &nbsp; <br /> &nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/** Creates a TokenStream which tokenizes all the text in the provided</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp; *&nbsp; Reader.&nbsp; Provided for backward compatibility only.</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp; * @deprecated use tokenStream(String, Reader) instead.</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp; * @see #tokenStream(String, Reader)</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp; */</span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">TokenStream</span> <span style="color: rgb(0, 0, 0); ">tokenStream</span>(<span style="color: rgb(0, 0, 0); ">Reader</span> <span style="color: rgb(0, 0, 0); ">reader</span>)<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 0); ">tokenStream</span>(<span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">reader</span>);<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>分析器的分词功能由Tokenizer的子类来完成, 过滤功能由TokenFilter的子类来完成. 同样的, 这也是两个虚无飘渺的抽象类. 下面我直接以StandardAnalyzer为实例来讲述分词和过滤的过程.<br />
StandardAnalyzer是lucene开发包中内置的一种Analyzer的实现, 这个分析器是最容易使用也是使用很频繁的一种Analyzer, 它使用了lucene内部自带的几种分词器和过滤器.<br />
在其代码中, 可以看到StandardAnalyzer也是继承了Analyzer, 并且实现了抽象类Analyzer的tokenStream方法. 我们注意到在这个方法里, reader首先是作为参数创建了一个分词器StandardTokenizer, 然后用这个分词器依次创建了LowerCaseFilter(大写转小写)和StopFilter(停止词过滤器)这两个过滤器. 目前为止, 基本还是一头雾水, 完全不知道分词和过滤是怎样一个过程? 其实, 到目前为止, tokenStream方法只是利用分词器, 过滤器在reader这个读入流后面铺设了一个管道而已, 真正的分词和过滤过程是在另一个地方执行的. 打个比方, reader就好像是自来水管道, tokenStream所做的只是接着这个管道又铺设了一段管道, 并且这一段的管道是用StandardTokenizer这种材质制造的, 能够对流过的文本进行切分, 然后又加上了LowerCaseFilter和StopFilter这两个过滤网.<span id="more-154"></span></p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">StandardAnalyzer</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> <span style="color: rgb(0, 0, 0); ">Analyzer</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">private</span> <span style="color: rgb(0, 0, 0); ">Set</span> <span style="color: rgb(0, 0, 0); ">stopSet</span>;</p>
<p> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">static</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 0); ">String</span><span style="color: rgb(0, 0, 0); ">[]</span> <span style="color: rgb(0, 0, 0); ">STOP_WORDS</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">StopAnalyzer</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">ENGLISH_STOP_WORDS</span>;</p>
<p> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">StandardAnalyzer</span>() <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">this</span>(<span style="color: rgb(0, 0, 0); ">STOP_WORDS</span>);<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span></p>
<p> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">StandardAnalyzer</span>(<span style="color: rgb(0, 0, 0); ">String</span><span style="color: rgb(0, 0, 0); ">[]</span> <span style="color: rgb(0, 0, 0); ">stopWords</span>) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">stopSet</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">StopFilter</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">makeStopSet</span>(<span style="color: rgb(0, 0, 0); ">stopWords</span>);<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span></p>
<p> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">TokenStream</span> <span style="color: rgb(0, 0, 0); ">tokenStream</span>(<span style="color: rgb(0, 0, 0); ">String</span> <span style="color: rgb(0, 0, 0); ">fieldName</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">Reader</span> <span style="color: rgb(0, 0, 0); ">reader</span>) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">TokenStream</span> <span style="color: rgb(0, 0, 0); ">result</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">StandardTokenizer</span>(<span style="color: rgb(0, 0, 0); ">reader</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">result</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">StandardFilter</span>(<span style="color: rgb(0, 0, 0); ">result</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">result</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">LowerCaseFilter</span>(<span style="color: rgb(0, 0, 0); ">result</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">result</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">StopFilter</span>(<span style="color: rgb(0, 0, 0); ">result</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">stopSet</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 0); ">result</span>;<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>分词和过滤的操作到底是从哪里开始的呢? 以<a href="http://www.chedong.com/tech/lucene.html" title="http://www.chedong.com/tech/lucene.html" target="_blank">车东blog</a>上的一段代码为例</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">IndexFiles</span> <span style="color: rgb(0, 0, 0); ">{</span> <br /> &nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//使用方法：: IndexFiles [索引输出目录] [索引的文件列表] &#8230; </span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">static</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">void</span> <span style="color: rgb(0, 0, 0); ">main</span>(<span style="color: rgb(0, 0, 0); ">String</span><span style="color: rgb(0, 0, 0); ">[]</span> <span style="color: rgb(0, 0, 0); ">args</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">throws</span> <span style="color: rgb(0, 0, 0); ">Exception</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">String</span> <span style="color: rgb(0, 0, 0); ">indexPath</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">args</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 255); ">0</span><span style="color: rgb(0, 0, 0); ">];</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">IndexWriter</span> <span style="color: rgb(0, 0, 0); ">writer</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//用指定的语言分析器构造一个新的写索引器（第3个参数表示是否为追加索引）</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">writer</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">IndexWriter</span>(<span style="color: rgb(0, 0, 0); ">indexPath</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">SimpleAnalyzer</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">false</span>);</p>
<p> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> (<span style="color: rgb(0, 0, 128); font-weight: bold; ">int</span> <span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">=</span><span style="color: rgb(0, 0, 255); ">1</span>; <span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">&lt;</span><span style="color: rgb(0, 0, 0); ">args</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">length</span>; <span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">++)</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">System</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">out</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">println</span>(<span style="color: rgb(0, 0, 255); ">&quot;Indexing file &quot;</span> <span style="color: rgb(0, 0, 0); ">+</span> <span style="color: rgb(0, 0, 0); ">args</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">]);</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">InputStream</span> <span style="color: rgb(0, 0, 0); ">is</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">FileInputStream</span>(<span style="color: rgb(0, 0, 0); ">args</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">]);</span></p>
<p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//构造包含2个字段Field的Document对象</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//一个是路径path字段，不索引，只存储</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//一个是内容body字段，进行全文索引，并存储</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">Document</span> <span style="color: rgb(0, 0, 0); ">doc</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">Document</span>();<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">doc</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">add</span>(<span style="color: rgb(0, 0, 0); ">Field</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">UnIndexed</span>(<span style="color: rgb(0, 0, 255); ">&quot;path&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">args</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">]));</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">doc</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">add</span>(<span style="color: rgb(0, 0, 0); ">Field</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Text</span>(<span style="color: rgb(0, 0, 255); ">&quot;body&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> (<span style="color: rgb(0, 0, 0); ">Reader</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">InputStreamReader</span>(<span style="color: rgb(0, 0, 0); ">is</span>)));<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//将文档写入索引</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">writer</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">addDocument</span>(<span style="color: rgb(0, 0, 0); ">doc</span>);&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//在这里!</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">is</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">close</span>();<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">};</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//关闭写索引器</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">writer</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">close</span>();<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>debug进入writer.addDocument(doc), 最后发现它实际最终调用的是index包下DocumentWriter.java中的DocumentWriter类的private final void invertDocument(Document doc) throws IOException方法. 方法中这样一段代码, for循环中每次都会调用TokenStream的next()方法. 这个next()方法就是在不断的读取文本流的下一个token, 但是这个next()可并不那么简单.</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 136, 0); font-style: italic; ">// Tokenize field and add to postingTable</span><br /> <span style="color: rgb(0, 0, 0); ">TokenStream</span> <span style="color: rgb(0, 0, 0); ">stream</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">analyzer</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">tokenStream</span>(<span style="color: rgb(0, 0, 0); ">fieldName</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">reader</span>);<br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">try</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> (<span style="color: rgb(0, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">stream</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">next</span>(); <span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">!=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>; <span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">stream</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">next</span>()) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">position</span> <span style="color: rgb(0, 0, 0); ">+=</span> (<span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">getPositionIncrement</span>() <span style="color: rgb(0, 0, 0); ">-</span> <span style="color: rgb(0, 0, 255); ">1</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">addPosition</span>(<span style="color: rgb(0, 0, 0); ">fieldName</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">termText</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 0); ">position</span><span style="color: rgb(0, 0, 0); ">++);</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> <span style="color: rgb(0, 0, 0); ">(++</span><span style="color: rgb(0, 0, 0); ">length</span> <span style="color: rgb(0, 0, 0); ">&gt;</span> <span style="color: rgb(0, 0, 0); ">maxFieldLength</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">finally</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">stream</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">close</span>();<br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>TokenStream stream = analyzer.tokenStream(fieldName, reader); 这一句就是调用了StandardAnalyzer的tokenStream方法, 根据前面的描述, 在这个方法中依次创建分词器和过滤器. tokenStream方法最终返回的result的类型其实是StopFilter, 所以invertDocument方法的for循环里调用的是StopFilter的next()方法, 如下代码所示:</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">next</span>() <span style="color: rgb(0, 0, 128); font-weight: bold; ">throws</span> <span style="color: rgb(0, 0, 0); ">IOException</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> (<span style="color: rgb(0, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">input</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">next</span>(); <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">!=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">input</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">next</span>())<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> <span style="color: rgb(0, 0, 0); ">(!</span><span style="color: rgb(0, 0, 0); ">stopWords</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">contains</span>(<span style="color: rgb(0, 0, 0); ">token</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">termText</span>)) <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 0); ">token</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>;<br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>我们看到, StopFilter的next()方法的for循环里又调用了input的next()方法, 分析代码(此处略)可以发现这个input其实是传入参数result的类型, 也就是LowerCaseFilter. LowerCaseFilter的代码如下所示:</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">LowerCaseFilter</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> <span style="color: rgb(0, 0, 0); ">TokenFilter</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">LowerCaseFilter</span>(<span style="color: rgb(0, 0, 0); ">TokenStream</span> <span style="color: rgb(0, 0, 0); ">in</span>) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">super</span>(<span style="color: rgb(0, 0, 0); ">in</span>);<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> &nbsp; <br /> &nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">next</span>() <span style="color: rgb(0, 0, 128); font-weight: bold; ">throws</span> <span style="color: rgb(0, 0, 0); ">IOException</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">input</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">next</span>();<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">==</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>)<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">termText</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">termText</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">toLowerCase</span>();<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 0); ">t</span>;<br /> &nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>LowerCaseFilter的next()方法里又再次调用了input的next()方法, 而此时的input其实就是构造器的in参数, 所以input和in的类型是StandardFilter. 继续进入StandardFilter的next()方法, 代码如下所示:</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 0); ">org</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">apache</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">lucene</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">analysis</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">next</span>() <span style="color: rgb(0, 0, 128); font-weight: bold; ">throws</span> <span style="color: rgb(0, 0, 0); ">java</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">io</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">IOException</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">org</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">apache</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">lucene</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">analysis</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">input</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">next</span>();</p>
<p> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 0); ">t</span> <span style="color: rgb(0, 0, 0); ">==</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>)<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>;</p>
<p> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">String</span> <span style="color: rgb(0, 0, 0); ">text</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">termText</span>();<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">String</span> <span style="color: rgb(0, 0, 0); ">type</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">type</span>();</p>
<p> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 0); ">type</span> <span style="color: rgb(0, 0, 0); ">==</span> <span style="color: rgb(0, 0, 0); ">APOSTROPHE_TYPE</span> <span style="color: rgb(0, 0, 0); ">&amp;&amp;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">// remove &#39;s</span><br /> &nbsp;&nbsp;&nbsp; (<span style="color: rgb(0, 0, 0); ">text</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">endsWith</span>(<span style="color: rgb(0, 0, 255); ">&quot;&#39;s&quot;</span>) || <span style="color: rgb(0, 0, 0); ">text</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">endsWith</span>(<span style="color: rgb(0, 0, 255); ">&quot;&#39;S&quot;</span>))) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">org</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">apache</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">lucene</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">analysis</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Token</span><br /> &nbsp;&nbsp;&nbsp; (<span style="color: rgb(0, 0, 0); ">text</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">substring</span>(<span style="color: rgb(0, 0, 255); ">0</span><span style="color: rgb(0, 0, 0); ">,</span><span style="color: rgb(0, 0, 0); ">text</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">length</span><span style="color: rgb(0, 0, 0); ">()-</span><span style="color: rgb(0, 0, 255); ">2</span><span style="color: rgb(0, 0, 0); ">),</span><br /> &nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">startOffset</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">endOffset</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 0); ">type</span>);</p>
<p> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">else</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 0); ">type</span> <span style="color: rgb(0, 0, 0); ">==</span> <span style="color: rgb(0, 0, 0); ">ACRONYM_TYPE</span>) <span style="color: rgb(0, 0, 0); ">{</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">// remove dots</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">StringBuffer</span> <span style="color: rgb(0, 0, 0); ">trimmed</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">StringBuffer</span>();<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">for</span> (<span style="color: rgb(0, 0, 128); font-weight: bold; ">int</span> <span style="color: rgb(0, 0, 0); ">i</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 255); ">0</span>; <span style="color: rgb(0, 0, 0); ">i</span> <span style="color: rgb(0, 0, 0); ">&lt;</span> <span style="color: rgb(0, 0, 0); ">text</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">length</span>(); <span style="color: rgb(0, 0, 0); ">i</span><span style="color: rgb(0, 0, 0); ">++)</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">char</span> <span style="color: rgb(0, 0, 0); ">c</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">text</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">charAt</span>(<span style="color: rgb(0, 0, 0); ">i</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 0); ">c</span> <span style="color: rgb(0, 0, 0); ">!=</span> <span style="color: rgb(128, 0, 128); ">&#39;.&#39;</span>)<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">trimmed</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">append</span>(<span style="color: rgb(0, 0, 0); ">c</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">org</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">apache</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">lucene</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">analysis</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Token</span><br /> &nbsp;&nbsp;&nbsp; (<span style="color: rgb(0, 0, 0); ">trimmed</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">toString</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">startOffset</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 0); ">t</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">endOffset</span><span style="color: rgb(0, 0, 0); ">(),</span> <span style="color: rgb(0, 0, 0); ">type</span>);</p>
<p> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">else</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 0); ">t</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>好吧, 第一行又调用了input的next()方法, 这里的input是传入参数result的类型->StandardTokenizer, 继续进入StandardTokenizer的next()方法. </p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 0); ">org</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">apache</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">lucene</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">analysis</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">next</span>() <span style="color: rgb(0, 0, 128); font-weight: bold; ">throws</span> <span style="color: rgb(0, 0, 0); ">ParseException</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 0); ">IOException</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp; <span style="color: rgb(0, 0, 0); ">Token</span> <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">switch</span> ((<span style="color: rgb(0, 0, 0); ">jj_ntk</span><span style="color: rgb(0, 0, 0); ">==-</span><span style="color: rgb(0, 0, 255); ">1</span><span style="color: rgb(0, 0, 0); ">)?</span><span style="color: rgb(0, 0, 0); ">jj_ntk</span><span style="color: rgb(0, 0, 0); ">():</span><span style="color: rgb(0, 0, 0); ">jj_ntk</span>) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">ALPHANUM:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">ALPHANUM</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">APOSTROPHE:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">APOSTROPHE</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">ACRONYM:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">ACRONYM</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">COMPANY:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">COMPANY</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">EMAIL:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">EMAIL</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">HOST:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">HOST</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">NUM:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">NUM</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 0); ">CJK:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 0); ">CJK</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">case</span> <span style="color: rgb(0, 0, 255); ">0</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_consume_token</span>(<span style="color: rgb(0, 0, 255); ">0</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">break</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">default</span><span style="color: rgb(0, 0, 0); ">:</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">jj_la1</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 255); ">0</span><span style="color: rgb(0, 0, 0); ">]</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">jj_gen</span>;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">jj_consume_token</span><span style="color: rgb(0, 0, 0); ">(-</span><span style="color: rgb(0, 0, 255); ">1</span>);<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">throw</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">ParseException</span>();<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 0); ">token</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">kind</span> <span style="color: rgb(0, 0, 0); ">==</span> <span style="color: rgb(0, 0, 0); ">EOF</span>) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">{</span><span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 128); font-weight: bold; ">true</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span><span style="color: rgb(0, 0, 0); ">;}</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">else</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">{</span><span style="color: rgb(0, 0, 128); font-weight: bold; ">if</span> (<span style="color: rgb(0, 0, 128); font-weight: bold; ">true</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">return</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">org</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">apache</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">lucene</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">analysis</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">Token</span>(<span style="color: rgb(0, 0, 0); ">token</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">image</span><span style="color: rgb(0, 0, 0); ">,</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">token</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">beginColumn</span><span style="color: rgb(0, 0, 0); ">,</span><span style="color: rgb(0, 0, 0); ">token</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">endColumn</span><span style="color: rgb(0, 0, 0); ">,</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">tokenImage</span><span style="color: rgb(0, 0, 0); ">[</span><span style="color: rgb(0, 0, 0); ">token</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">kind</span><span style="color: rgb(0, 0, 0); ">]);}</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">throw</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">Error</span>(<span style="color: rgb(0, 0, 255); ">&quot;Missing return statement in function&quot;</span>);<br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>终于, 在这里, 我们没有继续看到next()方法. 在StandardTokenizer的next()方法里, 我们看到了深藏其中的分词功能代码. StandardTokenizer其实就是JavaCC为lucene生成的分词器, 它的next()方法则是从reader对象中取出下一个词. 这个代码的分析我就不细谈了, 水太深, 暂时也用不太着. </p>
<p>我们来回顾下, 源头是DocumentWriter类的invertDocument()方法中for循环, 每次循环都会调用一次next()方法, 就好像自来水管道的口, 每一次调用就好像是从管道里吸水, 调用一次就吸一次. 这里需要注意的是StopFilter的next()方法, 里面也有一个for循环, 但是注意, 这里的for循环的目的是不停的寻找停止词, 也就是说invertDocement()方法中每次调用next(), 就是一次从管道里吸水的过程, 而从管道里吸多少水是由StopFilter中next()决定的, 一旦遇到停止词就返回本次next()调用提取的词.</p>
<p>为了更加清晰的理解这个过程, 这几个类的关系如下图所示:<br />
<a href="http://www.liubida.com/wordpress/wp-content/uploads/2011/09/lucene_tokenStream.jpg"><img src="http://www.liubida.com/wordpress/wp-content/uploads/2011/09/lucene_tokenStream.jpg" alt="" title="lucene_tokenStream" width="722" height="407" class="alignnone size-full wp-image-176" /></a><br />
好了, 就这样吧.<br />
<br/><br/><br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;我是分割线&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
停止词, 指的就是如英文中的a, an, the这样的小单词, 它们在建立索引的过程中并无实际的意义, 因此需要被过滤掉, 不能加入索引.<br />
“StopAnalyzer.ENGLISH_STOP_WORDS;” 定义了这些停止词的集合.</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">static</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 0); ">String</span><span style="color: rgb(0, 0, 0); ">[]</span> <span style="color: rgb(0, 0, 0); ">ENGLISH_STOP_WORDS</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 255); ">&quot;a&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;an&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;and&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;are&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;as&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;at&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;be&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;but&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;by&quot;</span><span style="color: rgb(0, 0, 0); ">,</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 255); ">&quot;for&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;if&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;in&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;into&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;is&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;it&quot;</span><span style="color: rgb(0, 0, 0); ">,</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 255); ">&quot;no&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;not&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;of&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;on&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;or&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;s&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;such&quot;</span><span style="color: rgb(0, 0, 0); ">,</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 255); ">&quot;t&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;that&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;the&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;their&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;then&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;there&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;these&quot;</span><span style="color: rgb(0, 0, 0); ">,</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 255); ">&quot;they&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;this&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;to&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;was&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;will&quot;</span><span style="color: rgb(0, 0, 0); ">,</span> <span style="color: rgb(0, 0, 255); ">&quot;with&quot;</span><br /> &nbsp; <span style="color: rgb(0, 0, 0); ">};</span></div>
<p></p>
<p>车东的blog: <a href="http://www.chedong.com/tech/lucene.html" title="http://www.chedong.com/tech/lucene.html" target="_blank">http://www.chedong.com/tech/lucene.html</a><br />
lucene细致深入的分析: <a href="http://forfuture1978.iteye.com/category/89151" title="http://forfuture1978.iteye.com/category/89151" target="_blank">http://forfuture1978.iteye.com/category/89151</a><br />
书: <a href="http://book.douban.com/subject/1769398/" title="http://book.douban.com/subject/1769398/" target="_blank">《Ajax+Lucene构建搜索引擎》</a></p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/programming_language/lucene_analyzer_intro/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>httpd: Could not reliably determine the server&#8217;s fully qualified domain name, using 127.0.0.1 for ServerName</title>
		<link>http://www.liubida.com/tips/httpd-could-not-reliably-determine-the-servers-fully-qualified-domain-name/</link>
		<comments>http://www.liubida.com/tips/httpd-could-not-reliably-determine-the-servers-fully-qualified-domain-name/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 19:08:35 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[tips]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[httpd]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=185</guid>
		<description><![CDATA[httpd: Could not reliably determine the server&#8217;s fully qualified domain name, using 127.0.0.1 for ServerName 启动APACHE时出现的提示: httpd: Could not reliably determine the server&#8217;s fully qualified domain name, using 127.0.0.1 for...]]></description>
			<content:encoded><![CDATA[<p>httpd: Could not reliably determine the server&#8217;s fully qualified domain name, using 127.0.0.1 for ServerName  </p>
<p>启动APACHE时出现的提示:<br />
httpd: Could not reliably determine the server&#8217;s fully qualified domain name, using 127.0.0.1 for ServerName</p>
<p>解决办法：只要把/conf/httpd.conf文件的#ServerName 前的#去掉，然后重启下服务就好了。</p>
<blockquote><p>httpd.conf的内容:<br />
# ServerName gives the name and port that the server uses to identify itself.<br />
# This can often be determined automatically, but we recommend you specify<br />
# it explicitly to prevent problems during startup.<br />
#<br />
# If your host doesn&#8217;t have a registered DNS name, enter its IP address here.<br />
#<br />
ServerName 127.0.0.1:80</p></blockquote>
<p><strong>感谢他们:</strong><br />
<a href="http://yinqingsong520.blog.163.com/blog/static/3921002009663949562" title="http://yinqingsong520.blog.163.com/blog/static/3921002009663949562" target="_blank">http://yinqingsong520.blog.163.com/blog/static/3921002009663949562</a><br />
<a href="http://hi.baidu.com/zeldady/blog/item/93153533a64fe9f41a4cffe9.html" title="http://hi.baidu.com/zeldady/blog/item/93153533a64fe9f41a4cffe9.html" target="_blank">http://hi.baidu.com/zeldady/blog/item/93153533a64fe9f41a4cffe9.html</a></p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/tips/httpd-could-not-reliably-determine-the-servers-fully-qualified-domain-name/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>java范型中的extends和super</title>
		<link>http://www.liubida.com/programming_language/extendsandsuper/</link>
		<comments>http://www.liubida.com/programming_language/extendsandsuper/#comments</comments>
		<pubDate>Sun, 26 Jun 2011 12:33:05 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[generic]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=195</guid>
		<description><![CDATA[转载请注明出处:http://www.liubida.com/uncategorized/extendsandsuper package com.liubida.ThinkingInJAVA.generics; import java.util.ArrayList; import java.util.List; /** * @author liubida */ class E{} class D extends E{} class C extends D{} class B extends C{} final class A extends...]]></description>
			<content:encoded><![CDATA[<p>转载请注明出处:<a href="http://www.liubida.com/uncategorized/extendsandsuper/">http://www.liubida.com/uncategorized/extendsandsuper</a><br/></p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(249, 247, 237); "> <span style="color: rgb(0, 0, 0); ">package</span> <span style="color: rgb(0, 0, 0); ">com</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">liubida</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">ThinkingInJAVA</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">generics</span>;</p>
<p> <span style="color: rgb(0, 0, 0); ">import</span> <span style="color: rgb(0, 0, 0); ">java.util.ArrayList</span>;<br /> <span style="color: rgb(0, 0, 0); ">import</span> <span style="color: rgb(0, 0, 0); ">java.util.List</span>;</p>
<p> <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> * @author liubida</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; "> */</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">E</span><span style="color: rgb(0, 0, 0); ">{}</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">D</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> <span style="color: rgb(0, 0, 0); ">E</span><span style="color: rgb(0, 0, 0); ">{}</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">C</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> <span style="color: rgb(0, 0, 0); ">D</span><span style="color: rgb(0, 0, 0); ">{}</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> B <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> <span style="color: rgb(0, 0, 0); ">C</span><span style="color: rgb(0, 0, 0); ">{}</span><br /> <span style="color: rgb(0, 0, 128); font-weight: bold; ">final</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">A</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> B<span style="color: rgb(0, 0, 0); ">{}</span></p>
<p> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">class</span> <span style="color: rgb(0, 0, 0); ">GenericExtendsSuper</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">@SuppressWarnings</span>(<span style="color: rgb(0, 0, 255); ">&quot;unused&quot;</span>)<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">static</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">void</span> <span style="color: rgb(0, 0, 0); ">main</span>(<span style="color: rgb(0, 0, 0); ">String</span><span style="color: rgb(0, 0, 0); ">[]</span> <span style="color: rgb(0, 0, 0); ">args</span>) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * List&lt;? extends E&gt; 表明：list中的元素的类型的上届是类E</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 编译器只知道list可能存放类E，或者E的子类，编译器无法知道list中元素到底是什么类型</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">List</span><span style="color: rgb(0, 0, 0); ">&lt;?</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">extends</span> <span style="color: rgb(0, 0, 0); ">E</span><span style="color: rgb(0, 0, 0); ">&gt;</span> <span style="color: rgb(0, 0, 0); ">list</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">ArrayList</span><span style="color: rgb(0, 0, 0); ">&lt;</span><span style="color: rgb(0, 0, 0); ">D</span><span style="color: rgb(0, 0, 0); ">&gt;();</span> <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 这里，list.add(anything)都是会编译出错</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 编译器的逻辑：如果list中的元素是E或者E的子类，那么这个赋值就有可能是非法的</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * list.add(new D());&nbsp;&nbsp; &#8212;&gt; 编译器想，可能list中元素是A，那么参数传入就存在这样的赋值: A tmp = new D(); 所以报错</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * &#8212;分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * list.add(new A());&nbsp;&nbsp; &#8212;&gt; 对于这个也报错，我觉得是编译器没想明白。注意这时候类A是final class，即不能再有子类。</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 按照上文的逻辑，编译器如果能想到list中元素的类型不可能是A的子类，那么参数传入的赋值是合法的。</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但是依然报错，显然就是编译器就把这一条特殊情况下的思路给忽略了。</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.add(new Object()); //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.add(new E());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.add(new D());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.add(new C());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.add(new B());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list.add(new A());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">list</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">add</span>(<span style="color: rgb(0, 0, 128); font-weight: bold; ">null</span>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">//正确，但是没有任何意义。null没有类型信息，</span></p>
<p> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * list中元素的类型的上届是类E，所以用E去接收list.get(0)出来的元素是合法的</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 编译器想，如果list中元素类型是E，那用D去接收就是非法，所以报错</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">E</span> <span style="color: rgb(0, 0, 0); ">e</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">list</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">get</span>(<span style="color: rgb(0, 0, 255); ">0</span>);<br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D d = list.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C c = list.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B b = list.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A a = list.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * List&lt;? super B&gt; 表明：list中的元素的类型的下届是类B</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 编译器只知道list可能存放类B，或者B的父类，编译器无法知道list中元素到底是什么类型</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">List</span><span style="color: rgb(0, 0, 0); ">&lt;?</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">super</span> B<span style="color: rgb(0, 0, 0); ">&gt;</span> <span style="color: rgb(0, 0, 0); ">alist</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">ArrayList</span><span style="color: rgb(0, 0, 0); ">&lt;</span><span style="color: rgb(0, 0, 0); ">D</span><span style="color: rgb(0, 0, 0); ">&gt;();</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * alist.add(O): 如果O&gt;B，则报错；如果O&lt;=B，则编译通过</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 编译器的逻辑：如果alist中的元素是B或者B的父类，如果O&gt;B，那么这个赋值就有可能是非法的；如果O&lt;=B，那么这个赋值就是合法的。</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * alist.add(new E());&nbsp;&nbsp; &#8212;&gt; 编译器想，可能alist中元素是B，那么参数传入就存在这样的赋值: B tmp = new E(); 所以报错</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * alist.add(new A());&nbsp;&nbsp; &#8212;&gt; 编译器想，alist中元素类型最低也是B，那么参数传入就存在这样的赋值: B tmp = new A(); 所以通过</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alist.add(new Object()); //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alist.add(new E());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alist.add(new D());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alist.add(new C());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">alist</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">add</span>(<span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> B());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">alist</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">add</span>(<span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">A</span>());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * alist中元素的类型的下界是类B，list.get(0)返回的类型可能是B，C，D，E&#8230; Object</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * D d1 = alist.get(0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8212;&gt; 编译器想，可能alist中元素是E，那么就存在这样的赋值: D d1 = new E(); 所以报错</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * &#8212;分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Object o1 = alist.get(0); &#8212;&gt; Object是所有类的父类，是最大的类。</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alist中所有元素的类都不能大于Object，所以这个get是通过的。</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * </span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">Object</span> <span style="color: rgb(0, 0, 0); ">o1</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">alist</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">get</span>(<span style="color: rgb(0, 0, 255); ">0</span>);<br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; E e1 = alist.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D d1 = alist.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; C c1 = alist.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B b1 = alist.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A a1 = alist.get(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //编译错误</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * “?”代表未知类型</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * extends关键字声明了类型的上界，表示参数化的类型可能是所指定的类型，或者是此类型的子类</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * super关键字声明了类型的下界，表示参数化的类型可能是所指定的类型，或者是此类型的父类型，直至Object</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/programming_language/extendsandsuper/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>回车符和换行符</title>
		<link>http://www.liubida.com/programming_language/randn/</link>
		<comments>http://www.liubida.com/programming_language/randn/#comments</comments>
		<pubDate>Mon, 13 Jun 2011 00:35:19 +0000</pubDate>
		<dc:creator>liubida</dc:creator>
				<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://www.liubida.com/?p=122</guid>
		<description><![CDATA[转载请注明出处: http://www.liubida.com/programming_language/randn/ 今天调试一个代码, 用java的Process执行了一个命令, 然后从Process的InputStream里读出了命令的返回信息. 遇到了一些关于回车符和换行符的问题. 索性仔细研究下. \r = 回车 = carriage return = CR = 13 \n = 换行 = line feed = LF = 10 回车符与换行符的起源 转自这里 计算机还没有出现之前，有一种叫做电传打字机（Teletype...]]></description>
			<content:encoded><![CDATA[<p>转载请注明出处: <a href="http://www.liubida.com/programming_language/randn/" title="http://www.liubida.com/programming_language/randn/" target="_blank">http://www.liubida.com/programming_language/randn/</a><br />
<br/><br />
今天调试一个代码, 用java的Process执行了一个命令, 然后从Process的InputStream里读出了命令的返回信息. 遇到了一些关于回车符和换行符的问题. 索性仔细研究下.<br />
<strong>\r = 回车 = carriage return = CR = 13<br />
\n = 换行 = line feed       = LF = 10</strong></p>
<p><strong>回车符与换行符的起源</strong>  转自<a href="http://kmplayer.iteye.com/blog/557820" title="回车符和换行符的起源" target="_blank">这里</a><br />
计算机还没有出现之前，有一种叫做电传打字机（Teletype Model 33）的玩意，每秒钟可以打10个字符。但是它有一个问题，就是打完一行换行的时候，要用去0.2秒，正好可以打两个字符。要是在这0.2秒里面，又有新的字符传过来，那么这个字符将丢失。于是，研制人员想了个办法解决这个问题，就是在每行后面加两个表示结束的字符。<br />
一个叫做“回车”，‘\r’，ASCII（13），告诉打字机把打印头定位在左边界；<br />
一个叫做“换行”，‘\n’，ASCII（10）告诉打字机把纸向下移一行。<br />
这就是“回车”和“换行”的来历。<br />
后来，计算机发明了，这两个概念也就被般到了计算机上。但是在初期，存储器很贵，在每行结尾加两个字符太浪费了，只加一个也可以实现相应的功能。于是，不同的系统就出现了分歧。<br />
Unix系统里，每行结尾只有“<换行>”，即’\n‘，’10‘；<br />
Windows系统里面，每行结尾是“<回车><换行>”，即“\r\n”，“13 10”；<br />
Mac系统里，每行结尾是“<回车>”，即’\r‘，’13‘。<br />
一个直接后果是，Unix/Mac系统下的文件在Windows里打开的话，所有文字会变成一行；而Windows里的文件在Unix/Mac下打开的话，在每行的结尾可能会多出一个^M符号。 </p>
<p><strong>实践小例:</strong><br />
Linux系统下test.o文件的信息:<br />
aaa<br />
bbb<br />
ccc</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); "> <span style="color: rgb(0, 0, 128); font-weight: bold; ">public</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">static</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">void</span> <span style="color: rgb(0, 0, 0); ">main</span>(<span style="color: rgb(0, 0, 0); ">String</span><span style="color: rgb(0, 0, 0); ">[]</span> <span style="color: rgb(0, 0, 0); ">args</span>) <span style="color: rgb(0, 0, 128); font-weight: bold; ">throws</span> <span style="color: rgb(0, 0, 0); ">IOException</span> <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">File</span> <span style="color: rgb(0, 0, 0); ">f</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">File</span>(<span style="color: rgb(0, 0, 255); ">&quot;/home/liubida/test.o&quot;</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">FileInputStream</span> <span style="color: rgb(0, 0, 0); ">fi</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 128); font-weight: bold; ">new</span> <span style="color: rgb(0, 0, 0); ">FileInputStream</span>(<span style="color: rgb(0, 0, 0); ">f</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">int</span> <span style="color: rgb(0, 0, 0); ">c</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 255); ">0</span>;<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 128); font-weight: bold; ">while</span> <span style="color: rgb(0, 0, 0); ">(-</span><span style="color: rgb(0, 0, 255); ">1</span> <span style="color: rgb(0, 0, 0); ">!=</span> (<span style="color: rgb(0, 0, 0); ">c</span> <span style="color: rgb(0, 0, 0); ">=</span> <span style="color: rgb(0, 0, 0); ">fi</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">read</span>())) <span style="color: rgb(0, 0, 0); ">{</span><br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">System</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">out</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">print</span>(<span style="color: rgb(0, 0, 0); ">c</span><span style="color: rgb(0, 0, 0); ">+</span><span style="color: rgb(0, 0, 255); ">&quot;#&quot;</span>);<br /> &nbsp;&nbsp;&nbsp; <span style="color: rgb(0, 0, 0); ">}</span><br /> <span style="color: rgb(0, 0, 0); ">}</span></div>
<p>输出结果:<br />
97#97#97#10#98#98#98#10#99#99#99#10#<br />
说明Unix系统中，文件只用换行符’10‘来换行。</p>
<p><strong>在<a href="http://www.ibm.com/developerworks/cn/linux/l-ipmi/" title="ipmitool" target="_blank">ipmitool</a>使用中遇到的回车, 换行的问题分析.</strong><br />
输出A: 通过ipmitool进入sol模式, 进入os交互, 键入ls, 在shell中得到返回的信息. <span id="more-122"></span><br />
“ipmitool -Ilanplus -Uroot -H192.168.1.100 -Ppassword sol activate”<br />
输出B和C是我们用Process对象执行ls命令返回的输出流信息. B是用readline()读入的文本信息; C是用read()读入的byte信息, 10进制, 在C中我们发现了”13 10&#8243;这样的”\r\n”行结尾, 比较奇怪(Linux系统中不是用&#8217;\n&#8217;来换行的么?)</p>
<blockquote><p>A<br />
    [Intranet root@ipmi-test /root]<br />
01: #ls<br />
02: backup	  install.log  local_hw_oob_init_dhcp.sh  ph_create.log  rc.local<br />
03: dig_test  JKYYG2X      ngis_post.sh		  post.log<br />
04:<br />
05: [Intranet root@ipmi-test /root]<br />
06: #</p></blockquote>
<blockquote><p>B<br />
01: #ls<br />
02: backup	  install.log  local_hw_oob_init_dhcp.sh  ph_create.log  rc.local<br />
03: dig_test  JKYYG2X      ngis_post.sh		  post.log<br />
04:<br />
05:<br />
06: [1;37m[[1;35mIntranet [m[1;32mroot[m[1;33m@[m[1;31mipmi-test[m [4m/root[m[1;37m][m[1;36m[m<br />
07: </p></blockquote>
<blockquote><p>C<br />
01: 108 115 13 10<br />
02: 98 97 99 107 117 112 9 32 32 105 110 115 116 97 108 108 46 108 111 103 32 32 108 111 99 97 108 95 104 119 95 111 111 98 95 105 110 105 116 95 100 104 99 112 46 115 104 32<br />
    32 112 104 95 99 114 101 97 116 101 46 108 111 103 32 32 114 99 46 108 111 99 97 108 13 10<br />
03: 100 105 103 95 116 101 115 116 32 32 74 75 89 89 71 50 88 32 32 32 32 32 32 110 103 105 115 95 112 111 115 116 46 115 104 9 9 32 32 112 111 115 116 46 108 111 103 13 10<br />
04: 13 13 10<br />
05: 27 91 49 59 51 55 109 91 27 91 49 59 51 53 109 73 110 116 114 97 110 101 116 32 27 91 109 27 91 49 59 51 50 109 114 111 111 116 27 91 109 27 91 49 59 51 51 109 64 27 91 109 27 91<br />
    49 59 51 49 109 105 112 109 105 45 116 101 115 116 27 91 109 32 27 91 52 109 47 114 111 111 116 27 91 109 27 91 49 59 51 55 109 93 27 91 109 27 91 49 59 51 54 109 27 91 109 13 13 10<br />
06: 35</p></blockquote>
<p>注释1: 为什么B是7行?<br />
答: 因为B是用readline()来读取的, readline()在遇到'\r','\n','\r\n'时都认为是一个行的结束. 那么在在C的03行末和04行首的"13 10 13 13 10", 这时候readline()理解就是:<br />
1行: 13 10<br />
2行: 13<br />
3行: 13 10<br />
这就导致了B多出了一行, 而A是由shell来解释的, 具体的解释方法我就不清楚了.</p>
<p>注释2: 如果"13 10"的确是作为结果换行的话, 那04行的"13 13 10"是有特别的解释, 还是就是普通的"回车符 回车符 换行符"来作为空行?<br />
答: 不得而知.</p>
<p>注释3: 注意到A和C中最后都是有个'35'('#')输出的, 而B的最后却没有.<br />
答: 仔细观察, C的05行就是对应的A的05行, B的06行, 表示的就是shell提示符, 只不过因为shell的提示符是有颜色的, 所以需要有字节来表示linux提示符的颜色(这是由shell去解析的)所以有一些多余的字符我们从文本上是不能进行一一映射的. 这也是B中06行有乱码的原因.<br />
但是B中为什么会少掉最后的'#', 其实没少, B的开头第一个字符是'#', 这个'#'是上一次B的输出流中遗留下来的. 为什么会遗留? 是因为我们的B的读取线程是用的readline()来读取的, 而每次输出中的'#'后面没有回车或者换行符, 所以'#'就没有被读出来, readline()也是被这个没有回车/换行符的'#'给阻塞着.</p>
<p>注释4:在Java的BufferedReader中，readLine方法其实是将\r，\n以及\r\n统统认为是一行的分隔符的<br />
答:
<div class="source" style="font-family: '[object HTMLOptionElement]&#8216;, Consolas, &#8216;Lucida Console&#8217;, &#8216;Courier New&#8217;; color: rgb(0, 0, 0); background-color: rgb(249, 247, 237); “> <span style="color: rgb(0, 136, 0); font-style: italic; ">/**</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">* Reads a line of text.&nbsp; A line is considered to be terminated by any one</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">* of a line feed (&#39;\n&#39;), a carriage return (&#8216;\r&#8217;), or a carriage return</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">* followed immediately by a linefeed.</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">*</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">* @return&nbsp;&nbsp;&nbsp;&nbsp; A String containing the contents of the line, not including</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; any line-termination characters, or null if the end of the</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stream has been reached</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">*</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">* @exception&nbsp; IOException&nbsp; If an I/O error occurs</span><br /> <span style="color: rgb(0, 136, 0); font-style: italic; ">*/</span></div>
<p><br/><br />
想蛋痛不? 把下面代码的1行和2行换下位置之后再看看输出(linux系统)? 唉, 求个解释&#8230;</p>
<div class="source" style="font-family: '[object HTMLOptionElement]', Consolas, 'Lucida Console', 'Courier New'; color: rgb(0, 0, 0); background-color: rgb(249, 247, 237); "> <span style="color: rgb(0, 0, 0); ">System</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">out</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">print</span>(<span style="color: rgb(128, 0, 128); ">&#39;\n&#39;</span>);<br /> <span style="color: rgb(0, 0, 0); ">System</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">out</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">print</span>(<span style="color: rgb(128, 0, 128); ">&#39;\r&#39;</span>);<br /> <span style="color: rgb(0, 0, 0); ">System</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">out</span><span style="color: rgb(0, 0, 0); ">.</span><span style="color: rgb(255, 0, 0); ">print</span>(<span style="color: rgb(128, 0, 128); ">&#39;a&#39;</span>);</div>
<p></p>
<p>校长说是编译器做了一个善意的解释,<br />
&#8216;\r&#8217;,     它认为是1行<br />
&#8216;\n&#8217;,     它认为是1行<br />
“\n\r”,   它认为是2行<br />
“\n\r\r”, 它认为是3行<br />
但是一旦”\r\n”,或&#8217;\r&#8217;和&#8217;\n&#8217;连续输出, 它就把这个挨在一起&#8217;\r&#8217;和&#8217;\n&#8217;作为一行来解释, 具体为什么我就不知道了,<br />
可能编译器认为, 一般情况下, 你要多行就直接多个&#8217;\r&#8217;或者&#8217;\n&#8217;吧, 结合着windows的&#8217;\r\n&#8217;是换行标志, 那么连续&#8217;\r&#8217;和&#8217;\n&#8217;的意思更多的可能是换一行吧.<br />
“\n\r\n”, 它认为是2行<br />
“\n\n\r\n\r\n\r\n\r\r\n”, 你数数是几行?</p>
<div style=float:left><!-- JiaThis Button BEGIN -->
<script type="text/javascript">var jiathis_config = {data_track_clickback:true};</script>
<script type="text/javascript" src="http://v2.jiathis.com/code_mini/jiathis_r.js?btn=r2.gif&amp;uid=1581227" charset="utf-8"></script>
<!-- JiaThis Button END --></div>]]></content:encoded>
			<wfw:commentRss>http://www.liubida.com/programming_language/randn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

