﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-冉翔的技术专栏-文章分类-02.J2SE Technology</title><link>http://www.blogjava.net/ranxiang/category/4382.html</link><description>关注于J2SE，J2EE以及开源方面的技术。</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 08:49:14 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 08:49:14 GMT</pubDate><ttl>60</ttl><item><title>TIJ阅读笔记（第十四章）</title><link>http://www.blogjava.net/ranxiang/articles/17964.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Thu, 03 Nov 2005 07:17:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17964.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17964.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17964.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17964.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17964.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 14: 创建窗口与Applet设计的宗旨是"能轻松完成简单的任务，有办法完成复杂的任务"。本章只介绍Java 2的Swing类库，并且合理假定Swing是Java GUI类库的发展方向。本章的开头部分会讲，用Swing创建applet与创建应用程序有什么不同，以及怎样创建一个既能当applet在浏览器里运行，又能当普通的应用程序，在命令行下运行程序。...&nbsp;&nbsp;<a href='http://www.blogjava.net/ranxiang/articles/17964.html'>阅读全文</a><img src ="http://www.blogjava.net/ranxiang/aggbug/17964.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-03 15:17 <a href="http://www.blogjava.net/ranxiang/articles/17964.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第十三章）</title><link>http://www.blogjava.net/ranxiang/articles/17960.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Thu, 03 Nov 2005 07:05:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17960.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17960.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17960.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17960.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17960.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 13: 并发编程面向对象使我们能将程序划分成相互独立的模块。但是你时常还会碰到，不但要把程序分解开来，而且还要让它的各个部分都能独立运行的问题。这种能独立运行的子任务就是线程(thread)。编程的时候，你可以认为线程都是能独立运行的，有自己CPU的子任务。实际上，是一些底层机制在为你分割CPU的时间，只是你不知道罢了。这种做法能简化多线程的编程。进程(proc...&nbsp;&nbsp;<a href='http://www.blogjava.net/ranxiang/articles/17960.html'>阅读全文</a><img src ="http://www.blogjava.net/ranxiang/aggbug/17960.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-03 15:05 <a href="http://www.blogjava.net/ranxiang/articles/17960.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第十二章）</title><link>http://www.blogjava.net/ranxiang/articles/17940.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Thu, 03 Nov 2005 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17940.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17940.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17940.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17940.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 12: Java I/O 系统对编程语言的设计者来说，创建一套好的输入输出(I/O)系统，是一项难度极高的任务。File 类在介绍直接从流里读写数据的类之前，我们先介绍一下处理文件和目录的类。你会认为这是一个关于文件的类，但它不是。你可以用它来表示某个文件的名字，也可以用它来表示目录里一组文件的名字。如果它表示的是一组文件，那么你还可以用list...&nbsp;&nbsp;<a href='http://www.blogjava.net/ranxiang/articles/17940.html'>阅读全文</a><img src ="http://www.blogjava.net/ranxiang/aggbug/17940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-03 12:36 <a href="http://www.blogjava.net/ranxiang/articles/17940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第十一章）</title><link>http://www.blogjava.net/ranxiang/articles/17937.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Thu, 03 Nov 2005 04:05:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17937.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17937.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17937.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17937.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17937.html</trackback:ping><description><![CDATA[
		11：对象的集合<br>
&nbsp; 如果程序的对象数量有限，且寿命可知，那么这个程序是相当简单的。<br>
<br>
数组<br>
&nbsp;
数组与其它容器的区别体现在三个方面：效率，类型识别以及可以持有primitives。数组是Java提供的，能随机存储和访问reference序列
的诸多方法中的，最高效的一种。数组是一个简单的线性序列，所有它可以快速的访问其中的元素。但是速度是有代价的；当你创建了一个数组之后，它的容量就固
定了，而且在其生命周期里不能改变。也许你会提议先创建一个数组，等到快不够用的时候，再创建一个新的，然后将旧的数组里的reference全部导到新
的里面。其实（我们以后会讲的）ArrayList就是这么做的。但是这种灵活性所带来的开销，使得ArrayList的效率比起数组有了明显下降。<br>
&nbsp; Java对数组和容器都做边界检查；如果过了界，它旧会给一个RuntimeException。这种异常表明这个错误是由程序员造成的，这样你就用不着再在程序里面检查了。<br>
&nbsp;
还有一些泛型容器类包括List，Set和Map。他们处理对象的时候就好像这些对象都没有自己的具体类型一样。也就是说，容器将它所含的元素都看成是
（Java中所有类的根类）Object的。这样你只需要建一种容器，就能把所有类型的对象全都放进去。从这个角度来看，这种做法很不错（只是苦了
primitive。如果是常量，你还可以用Java的primitive的Wrapper类；如果是变量，那就只能放在你自己的类里了）。与其他泛型容
器相比，这里体现数组的第二革优势：创建数组的时候，你也同时指明了它所持有的对象的类型（这又引出了第三点－－数组可以持有primitives，而容
器却不行）。也就是说，它会在编译的时候作类型检查，从而防止你插入错误类型的对象，或者是在提取对象的时候把对象的类型给搞错了。Java在编译和运行
时都能阻止你将一个不恰当的消息传给对象。所有这并不是说使用容器就有什么危险，只是如果编译器能够帮你指定，那么程序运行会更快，最终用户也会较少收到
程序运行异常的骚扰。<br>
&nbsp; 从效率和类型检查的角度来看，使用数组总是没错的。但是，如果你在解决一个更为一般的问题，那数组就会显得功能太弱了点。<br>
&nbsp; <br>
&nbsp; 数组是第一流的对象<br>
&nbsp;&nbsp;&nbsp;
不管你用的是那种类型的数组，数组的标识符实际上都是一个“创建在堆（heap）里的实实在在的对象的”reference。实际上是那个对象持有其他对
象的reference。你即可以用数组的初始化语句，隐含地创建这个对象，也可以用new表达式，明确地创建这个对象，只读的length属性能告诉你
数组能存储多少元素。它是数组对象的一部分（实际上也是你唯一能访问的属性或方法）。‘[]’语法是另一条访问数组对象的途径。<br>
&nbsp;&nbsp;&nbsp;
你没法知道数组里面究竟放了多少元素，因为length只是告诉你数组能放多少元素，也就是说是数组对象的容量，而不是它真正已经持有的元素的数量。但
是，创建数组对象的时候，它所持有的reference都会被自动地初始化为null，所以你可以通过检查数组的某个“槽位”是否为null，来判断它是
否持有对象。以此类推，primitive的数组，会自动来数字初始化为零，字符初始化为(char)0，boolean初始化为false。<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp; primitive容器<br>
&nbsp;&nbsp;&nbsp;
容器类只能持有Object对象的reference。而数组除了能持有Objects的reference之外，还可以直接持有primitive。当
然可以使用诸如Integer，Double之类的wrapper类。把primitive的值放到容器中，淡这样总有点怪怪的。此外，
primitive数组的效率要比wrapper类容器的高出许多。<br>
&nbsp;&nbsp;&nbsp; 当然，如果你使用primitive的时候，还需要那种“能随需要自动扩展的”容器类的灵活性，那就不能用数组了。你只能用容器来存储primitive的wrapper类。<br>
&nbsp; <br>
&nbsp; 返回一个数组<br>
&nbsp;&nbsp;&nbsp; 假设你写了一个方法，它返回的不是一个而是一组东西。那么在Java中就可以返回的“就是一个数组”。与C++不同，你永远也不必为Java的数组操心－－只要你还需要它，它就还在；一旦你用完了，垃圾回收器会帮你把它打扫干净。<br>
&nbsp; <br>
&nbsp; Arrays类<br>
&nbsp;&nbsp;&nbsp;
java.util里面有一个Arrays类，它包括了一组可用于数组的static方法，这些方法都是一些实用工具。其中有四个基本方法：用来比较两个
数组是否相等的equals()；用来填充的fill()；用来对数组进行排序的sort()；以及用于在一个已排序的数组中查找元素的
binarySearch()。所有这些方法都对primitive和Object进行了重载。此外还有一个asList()方法，它接受一个数组，然后
把它转成一个List容器。<br>
&nbsp;&nbsp;&nbsp;
虽然Arrays还是有用的，但它的功能并不完整。举例来说，如果它能让我们不用写for循环就能直接打印数组，那就好了。此外，正如你所看到的fill
()只能用一个值填数组。所以，如果你想把随即生成的数字填进数组的话，fill()是无能为力的。<br>
&nbsp; <br>
&nbsp; 复制一个数组<br>
&nbsp;&nbsp;&nbsp; Java标准类库提供了一个System.arraycopy()的static方法。相比for循环，它能以更快的速度拷贝数组。System.arraycopy()对所有类型都作了重载。<br>
&nbsp;&nbsp;&nbsp; 对象数组和primitive数组都能拷贝。但是如果你拷贝的是对象数组，那么你只拷贝了它们的reference－－对象本身不会被拷贝。这被成为浅拷贝（shallow copy）。<br>
&nbsp; <br>
&nbsp; 数组的比较<br>
&nbsp;&nbsp;&nbsp;
为了能比较数组是否完全相等，Arrays提供了经重载的equals()方法。当然，也是针对各种primitive以及Object的。两个数组要想
完全相等，他们必须有相同数量的元素，而且数组的每个元素必须与另一个数组的相对应的位置上的元素相等。元素的相等姓，用equals()判断。（对于
primitive，它会使用其wrapper类的equals()；比如int使用Integer.equals()。）。<br>
&nbsp; <br>
&nbsp; 数组元素的比较<br>
&nbsp;&nbsp;&nbsp;
Java里面有两种能让你实现比较功能的方法。一是实现java.lang.Comparable接口，并以此实现类“自有的”比较方法。这是一个很简单
的接口，它只有一个方法compareTo()。这个方法能接受另一个对象作为参数，如果现有对象比参数小，它就会返回一个负数，如果相同则返回零，如果
现有的对象比参数大，它就返回一个正数。<br>
&nbsp;&nbsp;&nbsp; static randInt()方法会生成一个介于0到100之间的正数。<br>
&nbsp;&nbsp;&nbsp;
现在架设，有人给你一个没有实现Comparable接口的类，或者这个类实现了Comparable接口，但是你发现它的工作方式不是你所希望的，于是
要重新定义一个新的比较方法。Java没有强求你一定要把比较代码塞进类里，它的解决方案是使用“策略模式（strategy design
pattern）”。有了策略之后，你就能把会变的代码封装到它自己的类里（即所谓的策略对象strategy
object）。你把策略对象交给不会变的代码，然后用它运用策略完成整个算法。这样，你就可以用不同的策略对象来表示不同的比较方法，然后把它们都交给
同一个排序程序了。接下来就要“通过实现Comparator接口”来定义策略对象了。这个接口有两个方法compare()和equals()。但是除
非是有特殊的性能要求，否则你用不着去实现equals()。因为只要是类，它就都隐含地继承自Object，而Object里面已经有了一个
equals()了。所以你尽可以使用缺省的Object的equals()，这样就已经满足接口的要求了。<br>
&nbsp;&nbsp;&nbsp; Collections类里专门有一个会返回与对象自有的比较法相反的Comparator的方法。它能很轻易地被用到CompType上面。<br>
&nbsp;&nbsp;&nbsp; Collections.reverseOrder()返回了一个Comparator的reference。<br>
&nbsp;&nbsp;&nbsp; compare()方法会根据第一个参数是小于，等于还是大于第二个参数，分别返回负整数，零或是正整数。<br>
&nbsp; <br>
&nbsp; 数组的排序<br>
&nbsp;&nbsp;&nbsp; 有了内置的排序方法之后，你就能对任何数组排序了，不论是primitive的还是对象数组的，只要它实现了Comparable接口或有一个与之相关的Comparator对象就行了。<br>
&nbsp;&nbsp;&nbsp;
Java标准类库所用的排序算法已经作了优化－－对primitive，它用的是“快速排序（Quicksort）”，对对象，它用的是“稳定合并排序
（stable merge sort）”。所以除非是prolier表明排序算法是瓶颈，否则你不用为性能担心。<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp; 查询有序数组<br>
&nbsp;&nbsp;&nbsp; 一旦数组排完序，你就能用Arrays.binarySearch()进行快速查询了。但是切忌对一个尚未排序的数组使用binarySearch()；因为这么做的结果是没意义的。<br>
&nbsp;&nbsp;&nbsp; 如果Arrays.binarySearch()找到了，它就返回一个大于或等于0的值。否则它就返回一个负值，而这个负值要表达的意思是，如果你手动维护这个数组的话，这个值应该插在哪个为止。这个值就是：<br>
&nbsp;&nbsp;&nbsp; -(插入点)-1<br>
&nbsp;&nbsp;&nbsp; “插入点”就是，在所有“比要找的那个值”更大值中，最小的那个值的下标，或者，如果数组中所有的值都比要找的值小，它就是a.size()。<br>
&nbsp;&nbsp;&nbsp;
如果数组里面有重复元素，那它不能保证会返回哪一个。这个算法不支持重复元素，不过它也不报错。所以，如果你需要的是一个无重复元素的有序序列的话，那么
可以考虑使用本章后面所介绍的TreeSet（支持【排序顺序“sorted
order”】）和LinkedHashSet（支持【插入顺序“sorted
order”】）。这两个类会帮你照看所有细节。只有在遇到性能瓶颈的时候，你才应该用手动维护的数组来代替这两个类。<br>
&nbsp;&nbsp;&nbsp; 如果排序的时候用到了Comparator（针对对象数组，primitive数组不允许使用Comparator），那么binarySearch()的时候，也必须使用同一个Comparator（用这个方法的重载版）。<br>
&nbsp; <br>
&nbsp; 数组部分的总结<br>
&nbsp;&nbsp;&nbsp;
总而言之，如果你要持有一组对象，首选，同时也是效率最高的选择，应该是数组。而且，如果这是一组primitive的话，你也只能用数组。还有一些更为
一般的情况，也就是写程序的时候还不知道要用多少对象，或者要用一种更复杂方式来存储对象情况。为此，Java提供了“容器类（container
class）”。其基本类型有List，Set和Map。<br>
&nbsp;&nbsp;&nbsp;
它们还有一些别的特性。比方说Set所持有的对象，个个都不同，Map则是一个“关联性数组（associative
array）”，它能在两个对象之间建立联系。此外，与数组不同，它们还能自动调整大小，所以你可以往里面放任意数量的对象。<br>
<br>
<br>
容器简介<br>
&nbsp; Java2的重新设计了1.0和1.1里面那个表现差劲的容器类。新的设计更紧凑也更合理。同时它也补齐了容器类库的功能，提供了链表（linked list），队列（queue）和双向队列（deques，读成“decks”）这几种数据结构的功能。<br>
&nbsp; Java2的容器类要解决“怎样持有对象”，而它把这个问题分成两类：<br>
&nbsp;&nbsp;&nbsp; 1。Collection：通常是一组有一定规律的独立元素。List必须按照特定的顺序持有这些元素，而Set则不能保存重复的元素。（bag没有这个限制，但是Java的容器类库没有实现它，因为List已经提供这种功能了）<br>
&nbsp;&nbsp;&nbsp;
2。Map：一组以“键－－值”（key-value）形式出现的pair。初看上去，它应该是一个pair的Collection，但是真这么去做的
话，它就会变得很滑稽，所以还是把这个概念独立列出来为好。退一步说，真的要用到Map的某个自己的时候，创建一个Collection也是很方便的。
Map可以返回“键（key）的”Set，值的Collection，或者pair的Set。和数组一样，Map不需要什么修改，就能很容易地扩展成多
维。你只要直接把Map的值设成Map就可以了（然后它的值再是Map，依此类推）。<br>
&nbsp;
Java的容器类分成两种基本类型。它们的区别就在，每个位置能放多少对象。Collection只允许每个位置上放一个对象（这个名字有点误导，因为容
器类库也常被统称为collections）。它包括“以一定顺序持有一组对象”的List，以及“只能允许添加不重复的对象”的Set。
ArrayList是一种List，而HashSet则是一种Set。你可以用add()方法往Collection里面加对象。<br>
&nbsp; Map保存的是“键（key）－－值”形式的pair，很像是一个微型数据库。<br>
&nbsp; Map又被称为关联性数组（associative array）。你可以用put()方法往Map里面加元素。它接受键－－值形式pair作参数。<br>
&nbsp;
fill()方法还为Collection和Map作了重载。输出在默认情况下使用容器类的toString()方法。打印出来的Collection会
用方括号括起来，元素与元素之间用逗号分开。Map会用花括号括起来，键和值之间用等号联起来（键在左边，值在右边）。<br>
&nbsp;
List会老老实实地持有你所输入的所有对象，既不做排序也不做编辑。Set则每个对象只接受一次，而且还要用它自己的规则对元素进行重新排序（一般情况
下，你关心的只是Set包没包括某个对象，而不是它到底排在哪里－－如果是那样，你最好还是用List）。而Map也不接收重复的pair，至于是不是重
复，要由key来决定。此外，它也有它自己的内部排序规则，不会受输入顺序影响。如果插入顺序是很重要的，那你就只能使用LinkedHashSet或
LinkedHashMap了。<br>
&nbsp; <br>
&nbsp; 填充容器<br>
&nbsp;&nbsp;&nbsp;
和Arrays一样，Collection也有一个叫Collections的辅助类，它包含了一些静态的实用工具方法，其中就有一个fill()。这个
fill()也只是把同一个对象的reference复制到整个容器，而且它还只能为List，不能为Set和Map工作。<br>
<br>
<br>
容器的缺点：不知道对象的类型<br>
&nbsp;
Java的容器有个缺点，就是往容器里面放对象的时候，会把对象的类型信息给弄丢了。这是因为开发容器类的程序员不会知道你要用它来保存什么类型的对象，
而让容器仅只保存特定类型的对象又会影响它的通用性。所以容器被做成只有持有Object，也就是所有对象的根类的reference，这样它就能持有任
何类型的对象了。（当然不包括primitive，因为它们不是对象，也没有继承别的对象。）这是一个很了不起的方案，只是：<br>
&nbsp; 1，由于在将对象放入容器的时候，它的类型信息被扔掉了，所以容器对“能往里面加什么类型的对象”没有限制。比方说，即使你想让它只持有cat，别人也能很轻易地把dog放进去。<br>
&nbsp; 2，由于对象的类型信息没了，容器只知道它持有的Object的reference，所以对象在使用之前还必须进行类型转换。<br>
&nbsp;
好的一面是，Java不会让你误用放进容器里的对象。假设你往cat的容器里面扔了个dog，然后要把这个容器里的所有对象都当cat来用，当你把dog
的reference从cat的容器里面拉出来，并且试图将它转换成cat的时候，就会引发一个RuntimeException。<br>
&nbsp;
ArrayList的用法也是很简单：先创建一个，用add()把对象放进去，要用的时候再给get()传一个下标－－就跟用数组差不多，只是不需要用方
括号了。ArrayList也有一个size()方法，它会告诉你容器里面有多少对象，这样你就不会粗心大意地过了界然后引发异常了。<br>
&nbsp; <br>
&nbsp; 有时即使不正确它也能运行<br>
&nbsp;&nbsp;&nbsp;
有时，即使不把对象转换成原先的类型，它好像也能正常工作。有一种情况比较特殊：String能从编译器哪里得到一些能使之平稳工作的特殊帮助。只要编译
器没能得到它所期望的String对象，它就会调用toString()。这个方法油Object定义，能被任何Java类覆写。它所返回的String
对象，会被用到任何要用它的地方。<br>
&nbsp;&nbsp;&nbsp; 于是只要覆写了类的toString()方法，你就能打印对象了。<br>
&nbsp; <br>
&nbsp; 做一个类型敏感的ArrayList<br>
&nbsp; <br>
&nbsp; 参数化类型（Parameterized types）<br>
<br>
迭代器<br>
&nbsp;
无论是哪种容器，你都得有办法既能放东西进去，也能拿东西出来。毕竟，容器的主要任务就是存放对象。ArrayList的add()就是用来放东西的，而
get()则是把对象拿出来的办法。ArrayList恨灵活；你可以随时提取任何东西，并且换一个下标，马上就能选择另一个元素。<br>
&nbsp;
“迭代器（iterator
又是一个设计模式）”是一个对象，它的任务是，能在让“客户程序在不知道，或者不关心他所处理的是什么样的底层序列结构”的情况下，就能在一个对象序列中
前后移动，并选取其中的对象。此外迭代器还是一种通常所说的“轻量级”的对象，既创建代价很小的对象。<br>
&nbsp; Java的Iterator就属于有这种限制的迭代器。它做不了很多事情，除了：<br>
&nbsp;&nbsp;&nbsp; 1，用iterator()方法叫容器传给你一个Iterator对象。第一次调用Iterator的next()方法的时候，它就会传给你序列中的第一个元素。<br>
&nbsp;&nbsp;&nbsp; 2，用next()方法获取序列中的下一个对象。<br>
&nbsp;&nbsp;&nbsp; 3，用hasNext()方法查询序列中是否还有其他对象。<br>
&nbsp;&nbsp;&nbsp; 4，用remove()方法删除迭代器所返回的最后一个元素。<br>
&nbsp;&nbsp;&nbsp; 就这么多了。这只是迭代器的一个恨简单的实现，不过还是很强大（对List来说，还有一个更精巧的ListIterator）。<br>
&nbsp; <br>
&nbsp; 不经意的递归（Unintended recursion）<br>
&nbsp;&nbsp;&nbsp;
由于Java的标准容器类（同其它类一样）也是继承Object的，因此它们也有一个toString()方法。这个方法已经被覆写了，所以它能生成一个
表示它自己以及所有它所保存的对象的String。比如ArrayList的toString()方法就会遍历ArrayList的每个元素，然后调用它
们的toString()方法。假设你要打印类的地址。好像最直接的办法就是使用this。但是会出现很多异常，解决的办法就是去调用Object的
toString()方法，它就是干这活的。所以不要用this，应该写super.toString()。<br>
<br>
<br>
容器分类学<br>
&nbsp; 根据编程的需要，Collection和Map分别有好几个实现。实际上只有三种容器组件－－Map，List和Set，而每种又有两到三个实现。<br>
&nbsp; 与存放对象有关的接口包括Collection, List, Set和Map。在理想情况下，绝大多数代码应该只同这些接口打交道，只是在创建容器的时候才要精确地指明它的确切类型。<br>
&nbsp;
add()，就像它的名字告诉我们的，会把新的元素放进Collection。但是文档里面特别仔细地声明，“add()会确保容器包含指定的元素”。这
句话是说给Set的，因为它只添加原先没有的元素，对ArrayList或其他List，add()总是“把它放进去”，因为List并不关心它是不是保
存了相同的元素。<br>
&nbsp; Collection都能用iterator()方法产生一个Iterator。这里，我们用Iterator来遍历整个Collection，然后把他们打印出来。<br>
<br>
<br>
Collection的功能<br>
&nbsp; 下面这张表给出了Collection的所有功能，也就是你能用Set和List做什么事（不包括从Object自动继承过来的方法）。（List还有一些额外的功能。）Map不是继承Collection的，所以我们会区别对待。<br>
<br>
&nbsp;&nbsp;&nbsp; boolean add(Object)：确保容器能持有你传给它的那个参数。如果没有把它加进去，就返回false。（这是个“可选”的方法，本章稍后会再作解释。）<br>
&nbsp;&nbsp;&nbsp; boolean addAll(Collection)：加入参数Collection所含的所有元素。只要加了元素，就返回true。<br>
&nbsp;&nbsp;&nbsp; void clear()：清除容器所保存的所有元素。（“可选”）<br>
&nbsp;&nbsp;&nbsp; boolean contains(Object)：如果容器持有参数Object，就返回true。<br>
&nbsp;&nbsp;&nbsp; boolean containsAll(Collection)：如果容器持有参数Collection所含的全部元素，就返回true。<br>
&nbsp;&nbsp;&nbsp; boolean isEmpty()：如果容器里面没有保存任何元素，就返回true。<br>
&nbsp;&nbsp;&nbsp; Iterator iterator()：返回一个可以在容器的各元素之间移动的Iterator。<br>
&nbsp;&nbsp;&nbsp; boolean removeAll(Collection)：删除容器里面所有参数Collection所包含的元素。只要删过东西，就返回true。（“可选”）<br>
&nbsp;&nbsp;&nbsp; boolean retainAll(Collection)：只保存参数Collection所包括的元素（集合论中“交集”的概念）。如果发生过变化，则返回true。（“可选”）<br>
&nbsp;&nbsp;&nbsp; int size()：返回容器所含元素的数量。<br>
&nbsp;&nbsp;&nbsp; Object[] toArray()：返回一个包含容器中所有元素的数组。<br>
&nbsp;&nbsp;&nbsp; Object[] toArray(Object[] a)：返回一个包含容器中所有元素的数组，且这个数组不是普通的Object数组，它的类型应该同参数数组a的类型相同（要做类型转换）。<br>
&nbsp; 注意，这里没有能进行随机访问的get()方法。这是因为Collection还包括Set。而Set有它自己的内部顺序（因此随即访问事毫无意义的）。所以如果你要检查Collection的元素，你就必须使用迭代器。<br>
&nbsp; 接下来讲List, Set和Map的各种实现了，每讲一种容器，我都会（用星号）告诉你默认情况下应该选用哪种实现。<br>
&nbsp; <br>
&nbsp; List的功能<br>
&nbsp;&nbsp;&nbsp; List的基本用法事相当将但的。虽然绝大多数时候，你只是用add()加对象，用get()取对象，用iterator()获取这个序列的Iterator，但List还有一些别的很有用的方法。<br>
&nbsp;&nbsp;&nbsp; 实际上有两种List：擅长对元素进行随机访问的，较常用的ArrayList，和更强大的LinkedList。LinkedList不是为快速的随机访问而设计的，但是它却有一组更加通用的方法。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Lisk（接口）：List的最重要的特征就是有序；它会确保以一定的顺序保存元素。List在Collection的基础上添加了大量方法，使之能在序
列中间插入和删除元素。（只对LinkedList推荐使用。）List可以制造ListIterator对象，你除了能用它在List的中间插入和删除
元素之外，还能用它沿两个方法遍历List。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ArrayList*：一个用数组实现的List。能进行快速的随机访问，但是往列表中间插入和删除元素的时候比较慢。ListIterator只能用在
反向遍历ArrayList的场合，不要用它来插入和删除元素，因为相比LinkedList，在ArrayList里面用ListIterator的系
统开销比较高。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
LinkedList：对顺序访问进行了优化。在List中间插入和删除元素的代价也不高。随机访问的速度相对较慢。（用ArrayList吧。）此外它
还有addFirst()，addLast()，getFirst()，getLast()，removeFirst()和removeLast()等方
法（这些方法，接口和基类均未定义），你能把它当成栈（stack），队列（queue）或双向队列（deque）来用。<br>
&nbsp;&nbsp;&nbsp;
记住，容器只是一个存储对象的盒子。如果这个笑盒子能帮你解决所有的问题，那你就用不着取管它事怎么实现的（在绝大多数情况下，这是使用对象的基本概
念）。如果开发环境里面还有一些别的，会造成固定的性能开销的因素存在，那么ArrayList和LinkedList之间的性能差别就会变得不那么重要
了。你只需要它们中的一个，你甚至可以想象有这样一种“完美”的抽象容器；它能根据用途，自动地切换其底层的实现。<br>
&nbsp; <br>
&nbsp; 用LinkedList做一个栈<br>
&nbsp;&nbsp;&nbsp;
“栈（stack）”有时也被称为“后进先出”（LIFO）的容器。就是说，最后一个被“压”进栈中的东西，会第一个“弹”出来。同其他Java容器一
样，压进去和弹出来的东西都是Object，所以除非你只用Object的功能，否则就必须对弹起来的东西进行类型转换。<br>
&nbsp;&nbsp;&nbsp; LinkedList的方法能直接实现栈的功能，所以你完全可以不写Stack而直接使用LinkedList。<br>
&nbsp;&nbsp;&nbsp; 如果你只想要栈的功能，那么继承就不太合适了，因为继承出来的是一个拥有LinkedList的所有方法的类。<br>
&nbsp; <br>
&nbsp; 用LinkedList做一个队列<br>
&nbsp;&nbsp;&nbsp;
队列（queue）是一个“先进先出”（FIFO）容器。也就是，你把一端把东西放进去，从另一端把东西取出来。所以你放东西的顺序也就是取东西的顺序。
LinkedList有支持队列的功能的方法，所以它也能被当作Queue来用。<br>
&nbsp;&nbsp;&nbsp; 还能很轻易地用LinkedList做一个deque（双向队列）。它很像队列，只是你可以从任意一端添加和删除元素。<br>
<br>
Set的功能<br>
&nbsp;
Set的接口就是Collection的，所以不像那两个List，它没有额外的功能。实际上Set确确实实就是一个Collection－－只不过行为
方式不同罢了。（这是继承和多态性的完美运用：表达不同地行为。）Set会拒绝持有多个具有相同值的对象的实例（对象的“值”又是由什么决定的呢？这个问
题比较复杂，我们以后会讲）。<br>
&nbsp;&nbsp;&nbsp;
Set（接口）：加入Set的每个元素必须是唯一的；否则，Set是不会把它加进去的。要想加进Set，Object必须定义equals()，这样才能
标明对象的唯一性。Set的接口和Collection的一摸一样。Set的接口不保证它会用哪种顺序来存储元素。<br>
&nbsp;&nbsp;&nbsp; HashSet*：为优化查询速度而设计的Set。要放进HashSet里面的Object还得定义hashCode()。<br>
&nbsp;&nbsp;&nbsp; TreeSet：是一个有序的Set，其底层是一颗树。这样你就能从Set里面提取一个有序序列了。<br>
&nbsp;&nbsp;&nbsp; LinkedHashSet(JDK 1.4)：一个在内部使用链表的Set，既有HashSet的查询速度，又能保存元素被加进去的顺序（插入顺序）。用Iterator遍历Set的时候，它是按插入顺序进行访问的。<br>
&nbsp;
HashSet保存对象的顺序是和TreeSet和LinkedHashSet不一样的。这是因为它们是用不同的方法来存储和查找元素的。
（TreeSet用了一种叫红黑树的数据结构【red-black tree data
structure】来为元素排序，而HashSet则用了“专为快速查找而设计”的散列函数。LinkedHashSet在内部用散列来提高查询速度，
但是它看上去像是用链表来保存元素的插入顺序的。）你写自己的类的时候，一定要记住，Set要有一个判断以什么顺序来存储元素的标准，也就是说你必须实现
Comparable接口，并且定义compareTo()方法。<br>
&nbsp; <br>
&nbsp; SortedSet<br>
&nbsp;&nbsp;&nbsp; SortedSet（只有TreeSet这一个实现可用）中的元素一定是有序的。这使得SortedSet接口多了一些方法：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Comparator comparator()：返回Set锁使用的Comparator对象，或者用null表示它使用Object自有的排序方法。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object first()：返回最小的元素。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object last()：返回最大的元素。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SortedSet subSet(fromElement,
toElement)：返回Set的子集，其中的元素从fromElement开始到toElement为止（包括fromElement，不包括
toElement）。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SortedSet headSet(toElement)：返回Set的子集，其中的元素都应小于toElement。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SortedSet headSet(toElement)：返回Set的子集，其中的元素都应大于fromElement。<br>
&nbsp;&nbsp;&nbsp; 注意，SortedSet意思是“根据对象的比较顺序”，而不是“插入顺序”进行排序。<br>
<br>
Map的功能<br>
&nbsp;
ArrayList能让你用数字在一愕嘎对象序列里面进行选择，所以从某种意义上讲，它是将数字和对象关联起来。但是，如果你想根据其他条件在一个对象序
列里面进行选择的话，那又该怎么做呢？栈就是一个例子。它的标准是“选取最后一个被压入栈的对象”。我们常用的术语map，dictionary，或
associative
array就是一种非常强大的，能在序列里面进行挑选的工具。从概念上讲，它看上去像是一个ArrayList，但它不用数字，而是用另一个对象来查找对
象！这是一种至关重要的编程技巧。<br>
&nbsp; 这一概念在Java中表现为Map。put(Object key, Object
value)方法会往Map里面加一个值，并且把这个值同键（你查找时所用的对象）联系起来。给出键之后，get(Object
key)就会返回与之相关的值。你也可以用containsKey()和containsValue()测试Map是否包含有某个键或值。<br>
&nbsp;
Java标准类库里有好几种Map：HashMap，TreeMap，LinkedHashMap，WeakHashMap，以及
IdentityHashMap。它们都实现了Map的基本接口，但是在行为方式方面有着明显的诧异。这些差异体现在，效率，持有和表示对象pair的顺
序，持有对象的时间长短，以及如何决定键的相等性。<br>
&nbsp;
性能时Map所要面对的一个大问题。如果你知道get()时怎么工作的，你就会发觉（比方说）在ArrayList里面找对象会是相当慢的。而这正是
HashMap的强项。它不是慢慢地一个个地找这个键，而是用了一种被称为hash
code的特殊值来进行查找的。散列（hash）时一种算法，它会从目标对象当中提取一些信息，然后生成一个表示这个对象的“相对独特”的int。
hashCode()是Object根类的方法，因此所有Java对象都能生成hash
code。HashMap则利用对象的hashCode()来进行快速的查找。这样性能就有了急剧的提高。<br>
&nbsp;&nbsp;&nbsp; Map（接口）：维持键－－值的关系（既pairs），这样就能用键来找值了。<br>
&nbsp;&nbsp;&nbsp; HashMap*：基于hash表的实现。（用它来代替Hashtable。）提供时间恒定的插入与查询。在构造函数种可以设置hash表的capacity和load factor。可以通过构造函数来调节其性能。<br>
&nbsp;&nbsp;&nbsp;
LinkedHashMap(JDK
1.4)：很像HashMap，但是用Iterator进行遍历的时候，它会按插入顺序或最先使用的顺序（least-recently-used
(LRU)order）进行访问。除了用Iterator外，其他情况下，只是比HashMap稍慢一点。用Iterator的情况下，由于是使用链表来
保存内部顺序，因此速度会更快。<br>
&nbsp;&nbsp;&nbsp;
TreeMap：基于红黑树数据结构的实现。当你查看键或pair时，会发现它们时按顺序（根据Comparable或Comparator，我们过一会
讲）排列的。TreeMap的特点时，你锁得到的时一个有序的Map。TreeMap是Map中唯一有subMap()方法的实现。这个方法能让你获取这
个树中的一部分。<br>
&nbsp;&nbsp;&nbsp; WeakHashMap：一个weak key的Map，是为某些特殊问题而设计的。它能让Map释放其所持有的对象。如果某个对象除了在Map当中充当键之外，在其他地方都没有其reference的话，那它将被当作垃圾回收。<br>
&nbsp;&nbsp;&nbsp; IdentityHashMap(JDK 1.4)：一个用＝＝，而不是equals()来比较键的hash map。不是为我们平常使用而设计的，是用来解决特殊问题的。<br>
&nbsp; 散列是往Map里存数据的常用算法。<br>
&nbsp; <br>
&nbsp; SortedMap<br>
&nbsp; SortedMap（只有TreeMap这一个实现）的键肯定是有序的，因此这个接口里面就有一些附加功能的方法了。<br>
&nbsp;&nbsp;&nbsp; Comparator comparator()：返回Map所使用的comparator，如果是用Object内置的方法的话，则返回null。<br>
&nbsp;&nbsp;&nbsp; Object firstKey()：返回第一个键。<br>
&nbsp;&nbsp;&nbsp; Object lastKey()：返回最后一个键。<br>
&nbsp;&nbsp;&nbsp; SortedMap subMap(fromKey, toKey)：返回这个Map的一个子集，其键从fromKey开始到toKey为止，包括前者，不包括后者。<br>
&nbsp;&nbsp;&nbsp; SortedMap headMap(toKey)：返回这个Map的一愕嘎子集，其键均小于toKey。<br>
&nbsp;&nbsp;&nbsp; SortedMap tailMap(fromKey)：返回这个Map的一个子集，其键均大于等于fromKey。<br>
&nbsp; pair是按key的顺序存储的，由于TreeMap有顺序的概念，因此“位置”是有意义的，所以你可以去获取它的第一个和最后一个元素，以及它的子集。<br>
&nbsp; <br>
&nbsp; LinkedHashMap<br>
&nbsp;&nbsp;&nbsp;
为了提高速度，LinkedHashMap对所有东西都做了hash，而且遍历的时候（println()会遍历整个Map，所以你能看到这个过程）还会
按插入顺序返回pair。此外，你还可以在LinkedHashMap的构造函数里面进行配置，让它使用基于访问的LRU（least-recently
-used）算法，这样还没被访问过的元素（同时也是要删除的候选对象）就会出现在队列的最前头。这样，为节省资源而写一个定时清理的程序就变得很简单
了。<br>
&nbsp; <br>
&nbsp; 散列算法与Hash数<br>
&nbsp;&nbsp;&nbsp; 一个合适的equals()必须做到一下五点：<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1 反身性：对任何x, x.equals(x)必须是true的。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 对称性：对任何x和y，如果y.equals(x)是true的，那么<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x.equals(y)也必须是true的。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 传递性：对任何x，y和z，如果x.equals(y)是true的，且<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y.equals(z)也是true的，那么x.equals(z)也必须是true的。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 一致性：对任何x和y，如果对象里面用来判断相等姓的信息没有修<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 改过，那么无论调用多少次x.equals(y)，它都必须一致地返回<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true或false。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5 对于任何非空的x，x.equals(null)必须返回false。<br>
&nbsp;&nbsp;&nbsp; 默认的Object.equals()只是简单地比较两个对象的地址。<br>
&nbsp;&nbsp;&nbsp; 如果你想把子集写的类当HashMap的键来用的话，你就必须把hashCode()和equals（）都给覆写了。<br>
&nbsp; <br>
&nbsp; 理解hashCode()<br>
&nbsp;&nbsp;&nbsp; 如果你不覆写键的hashCode()和equals()的话，散列数据结构（HashSet，HashMap，LinkedHashSet，或LinkedHashMap）就没法正确地处理键。<br>
&nbsp;&nbsp;&nbsp; 散列的价值就在于速度：散列算法能很快地找出东西。<br>
&nbsp;&nbsp;&nbsp; 数组是最快的数据结构。<br>
<br>
持有reference<br>
&nbsp;
java.lang.ref类库里有一套能增进垃圾回收器工作的灵活性的类。一旦碰到了“对象达到要耗光内存”的时候，这些类就会闲的格外有用。有三个类
是继承抽象类Reference的：SoftReference，WeakReference和PhantomReference。如果待处理的对象只能
通过这些Reference进行访问的话，那么这些Reference对象就会向垃圾回收器提供一些不同级别的暗事。<br>
&nbsp; <br>
&nbsp; ……<br>
<br>
总结：<br>
&nbsp; 总结Java标准类库的容器类：<br>
&nbsp; 1。数组把对象和数字形式的下标联系起来。它持有的是类型确定的对象，这样提取对象的时候就不用再作类型传递了。它可以是多维的，也可以持有primitive。但是创建之后它的容量不能改了。<br>
&nbsp; 2。Collection持有单个元素，而Map持有相关联的pair。<br>
&nbsp;
3。和数组一样，List也把数字下标同对象联系起来，你可以把数组和List想成有序的容器。List会随元素的增加自动调整容量。但是List只能持
有Object reference，所以不能存放primitive，而且把Object提取出来之后，还要做类型传递。<br>
&nbsp; 4。如果要做很多随机访问，那么请用ArrayList，但是如果要再List的中间做很多插入和删除的话，就应该用LinkedList了。<br>
&nbsp; 5。LinkedList能提供队列，双向队列和栈的功能。<br>
&nbsp; 6。Map提供的不是对象与数组的关联，而是对象和对象的关联。<br>
&nbsp;&nbsp;&nbsp;&nbsp; HashMap看重的是访问速度，而TreeMap各国那看重键的顺序，因而它不如HashMap那么快。而LinkedHashMap则保持对象插入的顺序，但是也可以用LRU算法为它重新排序。<br>
&nbsp; 7。Set只接受不重复的对象。HashSet提供了最快的查询速度。而TreeSet则保持元素有序。LinkedHashSet保持元素的插入顺序。<br>
&nbsp; 8。没必要再在新代码里使用旧类库留下来的Vector，Hashtable和Stack了。<br>
&nbsp; 容器类库是你每天都会用到的工具，它能使程序更简介，更强大并且更搞笑。<br>
<br>
<br>
PS:坦白说，这章虽然花费了很多时间但是感觉看完跟没有看差不多，太晕了。可能使没有做书上例子的缘故把。得尽快的再看一遍。好好的按照例子上的程序敲一遍。<br>
<br>
<br>
<br>
<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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2005年03月29日 11:55 PM<img src ="http://www.blogjava.net/ranxiang/aggbug/17937.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-03 12:05 <a href="http://www.blogjava.net/ranxiang/articles/17937.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第十章）</title><link>http://www.blogjava.net/ranxiang/articles/17856.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:50:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17856.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17856.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17856.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17856.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17856.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>10：检测类型<BR>&nbsp; 运行时类型识别(run-time type identification，缩写为RTTI)。</P>
<P>为什么会需要RTTI<BR>&nbsp; collection是一种工具，它只有一种用途，就是要为你保管其它对象。因此出于通用性的考虑，这些collection应该能持有任何东西。所以它们持有Object。<BR>&nbsp; <BR>&nbsp; Class对象<BR>&nbsp;&nbsp;&nbsp; 想要知道JAVA的RTTI是如何工作的，你就必须首先知道程序运行的时候，类型信息是怎样表示的。这是由一种特殊的，保存类的信息的，叫做“Class对象(Class object)”的对象来完成。实际上类的“常规”对象是由Class对象创建的。<BR>&nbsp;&nbsp;&nbsp; 程序里的每个类都要有一个Class对象。也就是说，每次你撰写并且编译了一个新的类的时候，你就创建了一个新的Class对象(而且可以这么说，这个对象会存储在同名的.class文件里)。程序运行时，当你需要创建一个那种类的对象的时候，JVM会检查它是否装载了那个Class对象。如果没有， JVM就会去找那个.class文件，然后装载。由此也可知道，Java程序在启动的时候并没有完全装载，这点同许多传统语言是不一样的。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Class.forName("一个类的名字");<BR>&nbsp;&nbsp;&nbsp; 这是一个Class的static方法(所有的Class对象所共有的)。Class对象同其它对象一样，也可以用reference来操控(这是装载器要干的)，而要想获取其reference, forName()就是一个办法。它要一个表示这个类的名字的String作参数（一定要注意拼写喝大小写！）。这个方法会返回Class的 reference，还有一个副作用，看看这个String所说的那个类装载了没有，要是还没有那就马上装载。如果Class.forName()没有找到它要装载的类，就会抛出一个ClassNotFoundException。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Class常数<BR>&nbsp;&nbsp;&nbsp; Java还提供了一种获取Class对象的reference的方法：“class常数(class literal)”。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 类的名字.class;<BR>&nbsp;&nbsp;&nbsp; 这种写法不但更简单，而且也更安全，因为它是在编译时做检查的。此外由于没有方法调用，它的执行效率也更高一些。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; Class常数不但能用于普通类，也可以用于接口，数组和primitive类型。此外，每种primitive的wrapper类还有一个标准的，名为 TYPE的数据成员。这个TYPE能返回“与这种primitive相关联的wrapper类”的Class对象的reference，就像这样：<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... 等同于 ...<BR>&nbsp;&nbsp;&nbsp; boolean.class&nbsp;&nbsp;&nbsp; Boolean.TYPE<BR>&nbsp;&nbsp;&nbsp; char.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Character.TYPE<BR>&nbsp;&nbsp;&nbsp; byte.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Byte.TYPE<BR>&nbsp;&nbsp;&nbsp; short.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Short.TYPE<BR>&nbsp;&nbsp;&nbsp; int.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Integer.TYPE<BR>&nbsp;&nbsp;&nbsp; long.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Long.TYPE<BR>&nbsp;&nbsp;&nbsp; float.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Float.TYPE<BR>&nbsp;&nbsp;&nbsp; double.class&nbsp;&nbsp;&nbsp;&nbsp; Double.TYPE<BR>&nbsp;&nbsp;&nbsp; void.class&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Void.TYPE<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 我喜欢尽量使用“.class”，因为这种写法与普通类的保持一致。<BR>&nbsp; <BR>&nbsp; 转换之前先作检查<BR>&nbsp;&nbsp;&nbsp; 到目前为止，你看到的RTTI的形式有：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1。经典的类型转换：如“(Shape)”，这种转换要经过RTTI的检查。要是做了错误的转换，它就会抛出ClassCastException。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.代表对象类型的Class对象。你可以在运行的时候查询Class对象，以此来获取所需的信息。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 如果不进行明确的类型转换的话，编译器时不会让你把对象赋给派生类的reference的。<BR>&nbsp; <BR>&nbsp; Java里面还有第三种RTTI的形式。这就是instanceof关键词，它会告诉你对象是不是某个类的实例。它返回的是一个boolean值。<BR>&nbsp; <BR>&nbsp; 使用类常数<BR>&nbsp; <BR>&nbsp; 动态的instanceof<BR>&nbsp;&nbsp;&nbsp; isInstance()能完全替代instanceof。<BR>&nbsp; <BR>&nbsp; instanceof vs. Class的相等性</P>
<P>RTTI的语法<BR>&nbsp; <BR>&nbsp; Class.getInterfaces()方法会返回一个Class对象的数组。数组中的对象分别表示它所实现的接口。<BR>&nbsp; 如果你手上有一个Class对象，你还能用getSuperclass()问出它最近的那个父类。当然，这会返回一个Class的reference，于是你可以接着问，程序运行的时候，你能以此发现对象的完整的关系。<BR>&nbsp; Class的newInstance()方法就像是另一种clone()对象的方法。但是，你却可以用newInstance()凭空创建出一个新的对象。<BR>&nbsp; printInfo()方法，它拿一个Class对象的reference作参数，用getName()提取类的名字，用isInterface()判断它是不是接口。这样，你就能仅凭Class对象就找出所有你想知道的这个对象的信息了。</P>
<P>Reflection：运行时的类信息<BR>&nbsp; Java以JavaBeans的形式提供了基于组件的编程的支持。<BR>&nbsp; 通过网络在远程机器上创建对象并运行程序。这被成为“远程方法调用(Remote Method Invocation缩写是RMI)”。它能让一个Java程序将对象分布到很多机器上。<BR>&nbsp; 除了Class类，还有一个类库，java.lang.reflect也支持reflection。这个类库里面有Field，Method，和 Constructor类（它们都实现了Member接口）运行时，JVM会创建一些这种类的对象来代表未知类的各个成员。然后，你就能用 Constructor来创建新的对象，用get()和set()来读取和修改与Field队形爱女嘎相关联的成员数据，用invoke()方法调用与 Method对象相关联的方法了。此外，你还能用getFields()，getMethods()，getConstructors()之类的方法，获取表示成员数据，方法或构造函数的对象数组。由此，即便编译时什么信息都得不到，你也有办法能在运行时问出匿名对象的全部类型信息了。<BR>&nbsp; 有一点很重要，reflection不是什么妖术。当你用reflection与未知类的对象打交道的时候，JVM(会和普通的RTTI一样)先看看这个对象是属于那个具体类型的，但是此后，它还是得先装载Class对象才能工作。也就是，不管是从本地还是从网络，反正JVM必须拿到那个.class文件。所以RTTI同reflection的真正区别在于，RTTI是在编译时让编译器打开并且检查.class文件。换句话说，你是在通过“正常”途径调用对象的方法。而对reflection来说，编译时是得不到.class文件的；所以它是在运行时打开并检查那个文件。<BR>&nbsp; <BR>&nbsp; 一个提取类的方法的程序<BR>&nbsp;&nbsp;&nbsp; 一般来说，你不太会直接使用reflection;Java之所以要有这种功能是要用它来支持一些憋的特性，比如对象的序列化和JavaBeans。不过在有些情况下，能动态提取类的信息还是很有用的。<BR>&nbsp;&nbsp;&nbsp; Class的getMethods()和getConstructors()方法分别会返回一个Method和一个Constructor数组。这两个类又包括一些“能把它们所代表的方法的名字，参数，返回值全部拆解开来”的方法。不过你也可以像这里所作的，只用toString()去获取一个包括这个方法的全部特征签名的String。剩下的代码就是用来抽取命令行信息，以及判断方法特征是否与你输入的字符串相匹配（用indexOf()），并且把匹配的方法列出来的。</P>
<P><BR>总结：<BR>&nbsp; RTTI能让你用一个匿名的基类reference来获取对象的确切类型的信息。在不懂多台方法调用的时候，这么作是理所当然的，因此新手们会自然而然的想到它，于是就用错了地方，对很多从面向过程的编程语言转过来的人来说，刚开始的时候，它们还不习惯扔掉switch语句。于是当他们用RTTI来编程的时候，就会错过多态性所带来的编程和代码维护方面的好处。Java的本义是让你在程序里面全程使用多态性，知识在万不得已的情况下才使用RTTI。<BR>&nbsp; 但是要想正确地使用多台方法调用，你就必须要能控制基类的定义，因为当你扩展程序的时候，可能会发现基类里面没有你想要的方法。如果这个基类是来自类库的，或是由别人控制的，那么RTTI就成解决方案了：你可以继承一个新的类，然后加上你自己的方法。在程序的其他地方，你可以检测出这个类型，调用那些特殊的方法。这样做不会破坏多态性，也不影响程序的扩展性，因为加一个新的类型不会要你去到处修改switch语句。但是，如果是在程序的主体部分加入要使用新特性的嗲马的话，你就必须使用RTTI来检查对象的确切类型了。<BR>&nbsp; RTTI还会被用来解决效率问题。假设你写了一个很好的多台程序，但是运行的时候发现，有个对象反映奇慢。于是，你就可以用RTTI把则个对象捡出来，然后专门针对它的问题写代码以提高程序的运行效率，不过编程的时候切忌去过早有话代码。这是一个很有诱惑的陷阱。最好还是先让程序跑起来，然后再判断一下它跑得是不是够快了。只有觉得它还不够快，你才应该去着手解决效率问题－－用profiler。<BR><BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月19日 12:55 PM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17856.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:50 <a href="http://www.blogjava.net/ranxiang/articles/17856.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第九章）</title><link>http://www.blogjava.net/ranxiang/articles/17855.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:48:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17855.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17855.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17855.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17855.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17855.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>9：用异常来处理错误</P>
<P>基本异常<BR>&nbsp; “异常条件(exceptional condition)”是一种能阻止正在运行的方法或其某一部分继续运行下去的问题。<BR>&nbsp; <BR>&nbsp; 异常的参数<BR>&nbsp;&nbsp;&nbsp; 所有的标准异常都有两个构造函数；第一个是默认的构造函数，第二个是要拿一个字符串当参数的。</P>
<P>捕获异常<BR>&nbsp; “守护区域(guarded region)”是一段可能产生异常的代码，并且后面还跟着要处理这些异常的代码。<BR>&nbsp; <BR>&nbsp; Try区块<BR>&nbsp; <BR>&nbsp; 异常处理程序(exception handler)<BR>&nbsp; <BR>&nbsp; “中止”还是“继续”</P>
<P>创建你自己的异常<BR>&nbsp;&nbsp; Thorowable类(Exception是从它那里继承的)printStackTrace()方法会返回“被调用的方法是经过怎样一个顺序到达异常发生地点”的信息。缺省情况下，这些信息会送到标准错误流，但是这个方法的重载版也允许你将结果送到其他流。<BR>&nbsp;&nbsp; 对于异常类来说，getMessage()有点像toString()。</P>
<P>异常说明<BR>&nbsp; 会在编译时进行检查并且强制得到处理的异常被称为checked exception.</P>
<P>捕捉任意类型的异常<BR>&nbsp; 重抛异常<BR>&nbsp;&nbsp;&nbsp; fillInStackTrace()，这个方法会将当前栈的信息塞进旧的异常对象中，并返回一个Throwable对象。<BR>&nbsp; <BR>&nbsp; 异常链(exception chaining)<BR>&nbsp;&nbsp;&nbsp; JDK 1.4中所有的Throwable的子类都有一个能接受cause(原因)对象的构造函数。这个cause就是用来保存前一个异常的。<BR>&nbsp;&nbsp;&nbsp; 在Throwable的子类中，只有三种基本的异常类提供了带cause参数的构造函数，它们是Error（供JVM报告系统错误只用）， Exception和RuntimeException。如果你要链接其他异常，那就不能用构造函数，而只能用initCause()方法了。</P>
<P>标准Java异常<BR>&nbsp; RuntimeException表示编程错误：<BR>&nbsp;&nbsp;&nbsp; 1。一种你无法预料的错误。比如不在你控制之内的null reference。<BR>&nbsp;&nbsp;&nbsp; 2。一种由于“程序员忘了检查它应该检查的错误条件”而造成的错误（比如ArrayIndexOutOfBoundsException，你访问数组的时候应该对数组的大小做一个检查）。第一种情况下发生的异常，经常会演变成第二种情况下的问题。</P>
<P>用finally进行清理<BR>&nbsp; 如果你把try区放进一个循环，你就能构建一个程序运行之前必须满足的条件了。你也可以在循环里加上static的计数器，或其它什么东西，让它退出之前多试几种方法。这样你就能把程序的强壮性就能更上一个台阶。<BR>&nbsp; <BR>&nbsp; finally是用来干什么的？<BR>&nbsp;&nbsp;&nbsp; 当你需要把内存以外的东西设置到原先状态的时候，finally就显得很有必要了。<BR>&nbsp;&nbsp;&nbsp; 甚至是在“异常没有被当前这组catch子句所捕获”的情况下，finally也会在“异常处理机制在更高一层的运行环境中开始寻找处理程序”之前得到执行。<BR>&nbsp; <BR>&nbsp; 错误：丢失的异常</P>
<P>加在异常上面的限制<BR>&nbsp; 派生类的构造函数不能捕获任何由基类构造函数抛出的异常。<BR>&nbsp; 在继承过程中，编译器会对异常说明作强制要求，但异常说明本身并不属于方法的特征(signature)，特征是由方法的名字与参数的类型组成的。因此，你不能根据异常说明来重载方法。此外，一个出现在基类方法的异常说明中的异常，不一定会出现在派生类方法的异常说明里。这点同继承的规则有明显不同，在继承中，基类的方法必须出现在继承类里。换一句话说，在继承和覆写的过程中，方法的“异常说明的接口”不是变大而是变小了－－这正好和接口在继承时的情形相反。</P>
<P><BR>构造函数<BR>&nbsp; 所有的清理－－除了内存清理之外－－都不会自动发生。</P>
<P>异常的匹配</P>
<P>其它方法</P>
<P>异常运用的原则<BR>&nbsp; 1。在合适的地方处理问题。（避免在自己还不知道该如何处理的情况下去捕捉异常）。<BR>&nbsp; 2。把问题解决掉，然后重新调用那个引起问题的方法。<BR>&nbsp; 3。修正一下问题，然后绕过那个方法再继续下去。<BR>&nbsp; 4。用一些别的，不准备让这个方法返回的数字来进行计算。<BR>&nbsp; 5。把当前运行环境下能作的事情全部做完，然后把相同的异常抛到更高层。<BR>&nbsp; 6。把当前运行环境下能做的事情全部做完，然后抛一个不同的异常到更高层。<BR>&nbsp; 7。中止程序。<BR>&nbsp; 8。简化。（如果异常结构把事情搞得太复杂了，那用起来回事非常痛苦也很烦人）<BR>&nbsp; 9。把类库和程序做得更安全。（这即使在为调试作短期投资，也是在为程序的健壮性作长期投资。）</P>
<P><BR>总结：Java异常处理的目的就是要让我们能用比现在更少的代码，以一种更简单的方式来开发大型，可靠的程序，并且让你在开发过程中能更自信“你的程序里面没有未经处理地错误”。异常不是特别难学，但是却能给项目带来立杆见影的效果。<BR><BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月15日 3:31 PM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:48 <a href="http://www.blogjava.net/ranxiang/articles/17855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第八章）</title><link>http://www.blogjava.net/ranxiang/articles/17854.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:47:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17854.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17854.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17854.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17854.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>8：接口(interface)与内部类(inner class)</P>
<P>接口(interface)<BR>&nbsp; 可以把它想象成“纯的”abstract类。能让开发人员定义类的形式：方法名，参数列表，返回值的类型，但是却没有方法的正文。interface也可以包含数据成员，但是它天生就是static和final的。interface只提供形式，不谈实现。<BR>&nbsp; interface会被用作定义类之间的“协议(protocol)”。<BR>&nbsp; 当你implements一个interface的时候，你必须把这个interface的方法定义成public的。如果你不这么做，那它就会编程package权限的，这样经过继承，这些方法的访问权限就会收到限制，而这是Java的编译器所不允许的。<BR>&nbsp; <BR>&nbsp; Java的“多重继承(multiple inheritance)”。<BR>&nbsp; 只要基类的设计里面可以不包括方法合成员变量的定义，你就应该优先使用interface。只有在不得不定义方法或成员变量的情况下，你才能把它改成abstract类，或者根据需要改成实体类。<BR>&nbsp; <BR>&nbsp; 合并接口时的名字冲突<BR>&nbsp; <BR>&nbsp; 用继承扩展interface<BR>&nbsp;&nbsp;&nbsp; 你可以用继承，往interface里面添加新的方法，也可以用继承把多个interface合并成一个新的interface。在这两种情况下，你所得到的都只是一个新的interface。<BR>&nbsp; <BR>&nbsp; 常量的分组<BR>&nbsp;&nbsp;&nbsp; 由于interface的数据成员自动就是static和final的，因此interface是一种非常方便的，创建一组常量值的工具。<BR>&nbsp;&nbsp;&nbsp; interface的成员自动就是public的。<BR>&nbsp; <BR>&nbsp; 初始化接口中的数据成员<BR>&nbsp; <BR>&nbsp; 接口的嵌套</P>
<P><BR>内部类<BR>&nbsp; <BR>&nbsp; 内部类与上传<BR>&nbsp;&nbsp;&nbsp; 实际上，将对象上传给它所实现的接口与将它上传给基类是完全相同。<BR>&nbsp;&nbsp;&nbsp; 普通类（非内部类）是不能被定义成private或protected的；它们只可能是public或package权限的。<BR>&nbsp; <BR>&nbsp; 在方法和作用域里的内部类<BR>&nbsp; <BR>&nbsp; 匿名内部类<BR>&nbsp;&nbsp;&nbsp; 如果你在定义匿名内部类的时候，还要用到外面的对象，那编译就会要求你把这个参数的reference生命成final的。如果你忘了，编译的时候就会报错。<BR>&nbsp;&nbsp;&nbsp; 实际上实力初始化过程就是匿名内部类的构造函数。当然，它的功能是有限的：你不能重载实例初始化，因此你只能有一个构造函数。<BR>&nbsp; <BR>&nbsp; 与宿主类的关系<BR>&nbsp;&nbsp;&nbsp; 如果你创建了一个内部类，那么这个内部类的对象，就与创建它的“宿主类的对象(enclosing object)”产生了某种关系，这样它就能访问宿主类对象的成员了－－不需要任何特别的授权。此外，内部类还能访问宿主类的所有元素。<BR>&nbsp; <BR>&nbsp; 嵌套类<BR>&nbsp;&nbsp;&nbsp; 如果你不需要这种“内部类对象和宿主类对象之间的”联系，那么你可以把内部类定义成static的。这通常被称作“嵌套类(nested class)”。嵌套类的意思是：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1。无须宿主类的对象就能创建嵌套类的对象。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2。不能在嵌套类的对象里面访问非static的宿主类对象。<BR>&nbsp;&nbsp;&nbsp; interface里面是不能有任何代码的，但嵌套类却可以是interface的一部分。<BR>&nbsp; <BR>&nbsp; 引用宿主类的对象<BR>&nbsp;&nbsp;&nbsp; 除非你还已经创建了宿主类的对象，否则根本不可能创建内部类的对象。但是，如果你创建的是嵌套类(static的内部类)的话，那就不需要宿主类对象的reference了。<BR>&nbsp; <BR>&nbsp; 在多层潜逃的类里向外访问<BR>&nbsp;&nbsp;&nbsp; 当你在另一个类里创建多层嵌套的内部类的对象的时候，应当使用哪种语法。“.new”语句指明了正确的作用域，因此你无须在调用构造函数的语句里再去限定类的名字了。<BR>&nbsp; <BR>&nbsp; 继承内部类<BR>&nbsp;&nbsp;&nbsp; 你必须传给他宿主类对象的reference。此外，你还必须在构造函数里面使用这种语法：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enclosingClassReference.super();<BR>&nbsp; <BR>&nbsp; 内部类可以被覆写吗？<BR>&nbsp;&nbsp;&nbsp; 当你继承宿主类的时候，内部类的戏法就到此为止了。这两个内部类是相互肚里的两个实体，它们都有自己的名字空间。<BR>&nbsp; <BR>&nbsp; 本地内部类(Local inner classes)<BR>&nbsp;&nbsp;&nbsp; 用本地内部类来代替匿名内部类的唯一正当的理由就是，你需要一个有名字的构造函数，并且/或者要重载这个构造函数，因为匿名内部类只能进行实力初始化。<BR>&nbsp;&nbsp;&nbsp; 选择本地内部类而不是匿名内部类的唯一原因就是，你必须创建多个那种类的对象。<BR>&nbsp; <BR>&nbsp; 内部类的标识符(Inner class identifiers)</P>
<P><BR>为什么要有内部类？<BR>&nbsp; 每个内部类都可以独立地继承某个“实现(implementation)”。因此，内部类不会受“宿主类是否已经继承了别的实现”的约束。<BR>&nbsp; 有了内部类，你就得到了如下的附加特性：<BR>&nbsp;&nbsp;&nbsp; 1。内部类可以有多个实例，而每个又都可以有它自己的，与宿主类对象无关的状态信息。<BR>&nbsp;&nbsp;&nbsp; 2。一个宿主类里可以放上好几个内部类，他们可以用各自不同的方法来实现同一个interface或继承同一个类。<BR>&nbsp;&nbsp;&nbsp; 3。内部类对象创建的时机与宿主类对象的创建没什么关系。<BR>&nbsp;&nbsp;&nbsp; 4。内部类不存在什么让人头晕的“是”关系；他是一个独立的实体。<BR>&nbsp; <BR>&nbsp; Closure与回调(Closures &amp; Callbacks)<BR>&nbsp;&nbsp;&nbsp; closure是一种能调用的对象，它记录了创建它的那个作用域的信息。内部类就是一种面向对象的closure，因为它不仅保存了宿主类的所有信息（“创建它的作用域”），而且还自动保存指向那个宿主类的对象的reference，更何况它还有权操控这个对象的所有成员，即使他们是private 的。<BR>&nbsp; <BR>&nbsp; 内部类与控制框架(Inner classes &amp; control frameworks)<BR>&nbsp;&nbsp;&nbsp; “应用程序框架(application framework)”是一个或一组为解决某种特定类型的问题而设计的类。控制框架是应用程序框架的一种，主要用于响应时间；如果系统的首要人物就是对事件作出响应，那么它就被称为“事件驱动系统(event-driven system)”。</P>
<P><BR>总结：相比绝大多数别的OOP语言，接口和内部类的概念会更为复杂，但是和C++的MI相比，JAVA的接口和内部类还是简单的许多。虽然，这些特性本身还是比较简单，但是它们具体用法就属于设计的范畴了，这点同多态性非常相似。<BR><BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月15日 3:29 PM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:47 <a href="http://www.blogjava.net/ranxiang/articles/17854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第七章）</title><link>http://www.blogjava.net/ranxiang/articles/17853.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:46:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17853.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17853.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17853.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17853.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17853.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>7：多态性</P>
<P>再访上传(upcasting)<BR>&nbsp; 把对象的reference当作基类的reference来用，被成为上传(upcasting)。<BR>&nbsp; <BR>&nbsp; 把对象的类型忘掉<BR>&nbsp; <BR>问题的关键<BR>&nbsp; <BR>&nbsp; 方法调用的绑定(binding)<BR>&nbsp;&nbsp;&nbsp; 后绑定(late binding)是要在程序运行的时候，根据对象的类型来决定该绑定哪个方法。后绑定也被称为“动态绑定(dynamic binding)”或“运行时绑定(run-time binding)”。<BR>&nbsp;&nbsp;&nbsp; 除了static和final方法(private方法隐含有final的意思)，JAVA的所有的方法都采用后绑定。<BR>&nbsp; <BR>&nbsp; 产生正确的行为<BR>&nbsp; <BR>&nbsp; 可扩展性<BR>&nbsp; <BR>&nbsp; 错误：“覆写”private的方法</P>
<P>抽象类和抽象方法<BR>&nbsp; <BR>&nbsp; 抽象方法(abstract method)：只有声明，没有正文。<BR>&nbsp; <BR>构造函数与多态性<BR>&nbsp; <BR>&nbsp; 构造函数的调用顺序<BR>&nbsp;&nbsp;&nbsp; 复杂对象的构造函数的调用顺序尸这样的：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1。调用基类的构造函数。这是一个递归的过程，因此会先创建继承体系的跟，然后是下一级派生类，依此类推，直到最后一个继承类的构造函数。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2。成员对象按照其声明的顺序进行初始化。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3。执行继承类的构造函数的正文。<BR>&nbsp; <BR>&nbsp; 继承与清理<BR>&nbsp;&nbsp;&nbsp; 先进行派生类的清理，再进行基类的清理。<BR>&nbsp; 多态方法在构造函数中的行为<BR>&nbsp;&nbsp;&nbsp; 一个好的构造函数应该，“用最少的工作量把对象的状态设置好，而且要尽可能地避免去调用方法。”构造函数唯一能安全调用的方法，就是基类的final方法 (这一条也适用private方法，因为它自动就是final的。)。他们不会被覆写，因此也不会产生这种意外的行为。</P>
<P><BR>用继承来进行设计<BR>&nbsp; 纯继承与扩展<BR>&nbsp; <BR>&nbsp; 下传与运行时的类型鉴别</P>
<P><BR>总结：多态性是一种不能孤立的看待的特性（不像switch语句），相反只有放在类关系的“大背景”下，它才有用武之地。要想在编程中有效地使用多态性，以及面向对象的技术，那你就必须扩展你的编程视野，不能只关注单个类的数据成员和消息，而是要去理解类与类之间的共同性，以及他们之间的关系。虽然这个要求很高，但是这种努力是值得的，因为它能加速程序的开发，改善代码的逻辑组织，使得程序更易于扩展，同时维护代码也变得更方便了。</P>
<P>&nbsp;</P>&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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月13日 1:59 AM&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; 
<P>&nbsp;</P><img src ="http://www.blogjava.net/ranxiang/aggbug/17853.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:46 <a href="http://www.blogjava.net/ranxiang/articles/17853.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第六章）</title><link>http://www.blogjava.net/ranxiang/articles/17852.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:44:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17852.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17852.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17852.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17852.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17852.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>6：复用类</P>
<P>合成所使用的语法<BR>&nbsp; 如果想对reference进行初始化，那么可以在以下几个时间进行：<BR>&nbsp;&nbsp;&nbsp; 1。在定义对象的时候。这就意味着在构造函数调用之前，它们已经初始化完毕了。<BR>&nbsp;&nbsp;&nbsp; 2。在这个类的构造函数里。<BR>&nbsp;&nbsp;&nbsp; 3。在即将使用那个对象之前。这种做法通常被成为“偷懒初始化（lazy initialization）”。如果碰到创建对象的代价很高，或者不是每次都需要创建对象的时候，这种做法就能降低程序的开销了。<BR>&nbsp; <BR>&nbsp; 继承所使用的语法。<BR>&nbsp;&nbsp;&nbsp; 继承设计方面有一条通用准则，那就是把数据都设成private的，把方法都设成public的。当然碰到特殊情况还要调整，但是这还是一条非常有用的准则。<BR>&nbsp; <BR>&nbsp; 基类的初始化<BR>&nbsp;&nbsp;&nbsp; 构造行为是从积累“向外”发展的，所以基类会在派生类的构造函数访问它之前先进行初始化。<BR>&nbsp; <BR>&nbsp; 带参数的构造函数<BR>&nbsp;&nbsp;&nbsp; 对派生类构造函数而言，调用基类的构造函数应该是它做的第一件事。<BR>&nbsp; <BR>&nbsp; 捕获积累构造函数抛出的异常。</P>
<P><BR>把合成和继承结合起来<BR>&nbsp; 虽然编译器会强制你对基类进行初始化，并且会要求你在构造函数的开始部分完成初始化。但是它不会检查你是不是进行了成员对象的初始化，因此你只能自己留神了。<BR>&nbsp; <BR>&nbsp; 确保进行妥善地清理<BR>&nbsp;&nbsp;&nbsp; 先按照创建对象的相反顺序进行类的清理。然后调用基类的清理方法。<BR>&nbsp; <BR>&nbsp; 名字的遮盖</P>
<P><BR>用合成还是继承<BR>&nbsp; 继承要表达的是一种“是(is-a)”关系，而合成要表达的是“有(has-s)”关系。<BR>&nbsp; <BR>&nbsp; protected<BR>&nbsp;&nbsp;&nbsp; Java的protected也提供package的权限。</P>
<P>渐进式的开发</P>
<P>上传(upcasting)：总是安全的。</P>
<P>合成还是继承，再探讨。</P>
<P>final关键词<BR>&nbsp; Final的数据<BR>&nbsp;&nbsp;&nbsp; 对primitive来说，final会将这个值定义成常量，但是对于对象的reference而言，final的意思则是这个reference是常量。Java没有提供将某个对象作成常量的方法。这种局限性也体现在数组上，因为它也是一个对象。<BR>&nbsp; <BR>&nbsp; 空白的final数据(Blank finals)<BR>&nbsp;&nbsp;&nbsp; 一定得为final数据赋值，要么是在定义数据的时候用一个表达式赋值，要么是在构造函数里面进行赋值。<BR>&nbsp; <BR>&nbsp; Final的参数<BR>&nbsp;&nbsp;&nbsp; Java允许你在参数表中生命参数是final的，你不能在方法里让参数reference指向另一个对象。<BR>&nbsp; <BR>&nbsp; Final方法<BR>&nbsp; <BR>&nbsp; final和private<BR>&nbsp;&nbsp;&nbsp; private方法都隐含有final的意思。<BR>&nbsp; <BR>&nbsp; Final类<BR>&nbsp;&nbsp;&nbsp; 不允许别人去继承。<BR>&nbsp; <BR>&nbsp; 小心使用final</P>
<P><BR>初始化与类的装载<BR>&nbsp; 继承情况下的初始化</P>
<P>总结：本章主要讲述了继承和合成的概念和用法及一些注意事项。尽管面向对象的变成会反复强调继承，但是当你着手设计的时候，通唱情况下还是应该先考虑合成，只有在必要的时候才使用继承。合成会更灵活。<BR><BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月12日 3:42 AM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17852.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:44 <a href="http://www.blogjava.net/ranxiang/articles/17852.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第五章）</title><link>http://www.blogjava.net/ranxiang/articles/17851.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:43:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17851.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17851.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17851.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17851.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17851.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>5：隐藏实现</P>
<P>package：类库的单元<BR>&nbsp;&nbsp; package和import这两个关键词的作用是要把一个单独的全局名字空间分割开来。</P>
<P>创建独一无二的package名字</P>
<P>一个自定义的工具类库</P>
<P>使用import来改变程序的行为方式</P>
<P>使用package的忠告<BR>&nbsp; 这个package必须保存在由它的名字所指示的目录里，而这个目录又必须在CLASSPATH下面。</P>
<P><BR>JAVA的访问控制符<BR>&nbsp; package访问权限<BR>&nbsp; public：访问接口的权限<BR>&nbsp; private：你碰都碰不到<BR>&nbsp; protected：继承的访问权限</P>
<P>接口(Interface)与实现(implementation)<BR>&nbsp; 为了让代码显得更有条理，可能你选用这种风格，就是讲public成员都放在类的开头，接下来是protected成员，然后是package权限的，最后是private成员。</P>
<P>类的访问权限<BR>&nbsp; 1。每个编译单元（文件）只能有一个public类。这么做的意思是，每个编译单元只能有一个公开的接口，而这个接口就由其public类来表示。你可以根据需要，往这个文件里面添加任意多个提供辅助功能的package权限的类。但是如果这个编译单元里面有两个或两个以上public类的话，编译器就会报错。<BR>&nbsp; 2。public类的名字必须和这个编译单元的文件名完全相同，包括大小写。所以对Widget类，文件名必须是Widget.java，不能是widget.java或WIDGET.java。如果你不遵守，编译器又要报错了。<BR>&nbsp; 3。编译单元里面可以没有public类，虽然这种情况不常见，但确实可以的，这时，你就能随意为文件起名字了。<BR>&nbsp; <BR>&nbsp; 类只有两种访问权限：package权限和public。</P>
<P><BR>总结：本章主题是怎样用类来构建类库：首先是怎样讲类封装成类库，然后是，类是怎样控制它的成员的访问权限的。<BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月12日 12:12 AM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:43 <a href="http://www.blogjava.net/ranxiang/articles/17851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第四章）</title><link>http://www.blogjava.net/ranxiang/articles/17850.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:42:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17850.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17850.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17850.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17850.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17850.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>4：初始化与清理</P>
<P>用构造函数确保初始化<BR>&nbsp; new表达式确实会返回这个新创建的对象和reference，但是构造函数本身不返回任何值。</P>
<P>方法的重载<BR>&nbsp; 区分经重载的方法<BR>&nbsp; 对primitive进行重载<BR>&nbsp; 用返回值重载<BR>&nbsp;&nbsp;&nbsp; 不能用返回值来区分重载的方法。</P>
<P>默认的构造函数</P>
<P>this关键词<BR>&nbsp; this关键词只能用于方法内部，它负责返回调用这个方法的对象的reference。</P>
<P>static的含义<BR>&nbsp; 不能在static方法里调用非static的方法（虽然反过来是可以的），但是却可以不通过对象，直接对类调用static方法。</P>
<P>在构造函数里调用构造函数</P>
<P>清理：finalization和垃圾回收<BR>&nbsp; 为什么要有finalize()？<BR>&nbsp;&nbsp;&nbsp; 1。对象不一定会被垃圾回收器回收。<BR>&nbsp;&nbsp;&nbsp; 2。垃圾回收不是拆构(destruction)。<BR>&nbsp;&nbsp;&nbsp; 3。垃圾回收只与内存有关。<BR>&nbsp; <BR>&nbsp; 你必须亲自进行清理<BR>&nbsp; <BR>&nbsp; 中止条件<BR>&nbsp; <BR>&nbsp; 垃圾回收器是如何工作的<BR>&nbsp; <BR>&nbsp; 指定初始化<BR>&nbsp; <BR>&nbsp; 用构造函数进行初始化<BR>&nbsp;&nbsp;&nbsp; 初始化的顺序是由变量在类的定义里面的顺序锁决定的。<BR>&nbsp;&nbsp;&nbsp; 变量的初始化会先于任何方法，甚至是构造函数的调用。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 静态数据的初始化<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果尚未创建类的对象，因而其static的成员尚未初始化的话，初始化会先处理其static成员，再处理非static的对象。只有创建第一个对象时，static成员被初始化，此后static对象就不会再作初始化。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 显示的静态初始化<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 静态初始化只运行一次。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 非静态的实例初始化</P>
<P><BR>数组的初始化<BR>&nbsp; 可以访问的最大的数组下标是length-1<BR>&nbsp; <BR>&nbsp; 多维数组</P>
<P><BR><BR>总结：本章主要讲述了JAVA初始化方面的机制和一些规则和技巧，也对JAVA的内存回收，垃圾处理机制做了一定的介绍和分析。<BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月11日 6:08 AM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:42 <a href="http://www.blogjava.net/ranxiang/articles/17850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第三章）</title><link>http://www.blogjava.net/ranxiang/articles/17848.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:31:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17848.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17848.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17848.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17848.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17848.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;
<P>3:控制程序流程</P>
<P>使用Java运算符<BR>&nbsp; 优先级：先乘除后加减<BR>&nbsp;&nbsp;&nbsp; 赋值<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当你‘在对象之间’进行复制的时候，实际上你是在拷贝它的reference。<BR>&nbsp; 方法调用期间的aliasing</P>
<P>&nbsp; 数学运算符<BR>&nbsp; <BR>&nbsp; 正则表达式(Regular expressions)<BR>&nbsp; <BR>&nbsp; 自动递增与递减<BR>&nbsp; <BR>&nbsp; 关系运算符<BR>&nbsp;&nbsp;&nbsp; 测试对象的相等性<BR>&nbsp; <BR>&nbsp; 逻辑运算符<BR>&nbsp;&nbsp;&nbsp; 短接(short circuiting)<BR>&nbsp; <BR>&nbsp; 位运算符<BR>&nbsp; <BR>&nbsp; 移位运算符<BR>&nbsp; <BR>&nbsp; 三元if-else运算符<BR>&nbsp; <BR>&nbsp; 逗号运算符</P>
<P>&nbsp; String和＋运算符<BR>&nbsp; <BR>&nbsp; 常见的使用运算符方面的错误<BR>&nbsp; <BR>&nbsp; 类型转换符<BR>&nbsp; <BR>&nbsp; 常量(Literals)</P>
<P>&nbsp; Java没有"sizeof"</P>
<P>&nbsp; 重访优先级<BR>&nbsp; <BR>&nbsp; 运算符的总结<BR>&nbsp;&nbsp;&nbsp; 除了boolean之外，所有的primitive类型都能被转换成其他的primitive类型。</P>
<P><BR>执行控制<BR>&nbsp; <BR>&nbsp; true和false<BR>&nbsp;&nbsp;&nbsp; “条件判断(conditional)”必须要能产生一个boolean结果。<BR>&nbsp; return<BR>&nbsp; 循环语句<BR>&nbsp;&nbsp;&nbsp; while<BR>&nbsp;&nbsp;&nbsp; do-while<BR>&nbsp;&nbsp;&nbsp; for<BR>&nbsp; 逗号运算符<BR>&nbsp; break和continue<BR>&nbsp;&nbsp;&nbsp; 臭名昭著的“goto”<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.普通的continue会退到内部循环的最开始，然后继续执行内部循环。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.带标签的continue会跳转到标签，并且重新进入直接跟在标签后面的循环。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.break会从循环的“底部溜出去”。<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.带标签的break会从由这个标签标识的循环的“底部溜出去”。<BR>&nbsp; <BR>&nbsp; siwtch<BR>&nbsp;&nbsp;&nbsp; Math.random()会生成0.0，它的值域是[0,1)。</P>
<P><BR>总结：这一章讲述了绝大多数的变成语言都有的基本特性：计算，操作符优先级，类型转换，选择与循环。还有一些小知识和容易犯错误的地方：P<BR><BR><BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月10日 5:40 AM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17848.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:31 <a href="http://www.blogjava.net/ranxiang/articles/17848.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第二章）</title><link>http://www.blogjava.net/ranxiang/articles/17847.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:25:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17847.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17847.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17847.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17847.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17847.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp;2:万物皆对象<BR><BR>用reference操纵对象<BR><BR>你必须创造所有的对象<BR><BR>&nbsp; 数据存在哪里？<BR>&nbsp;&nbsp;&nbsp; 1。寄存器(registers)。<BR>&nbsp;&nbsp;&nbsp; 2。栈(stack)。<BR>&nbsp;&nbsp;&nbsp; 3。堆(heap)。<BR>&nbsp;&nbsp;&nbsp; 4。静态存储(static storage)。<BR>&nbsp;&nbsp;&nbsp; 5。固定存储(constant storage)。<BR>&nbsp;&nbsp;&nbsp; 6。非内存的存储(Non-RAM storage)：流对象(streamed object)和persistent对象。<BR><BR>特例：primitive类型<BR>&nbsp; Primitive类型：boolean, char, byte, short, int, long, float, double, void<BR>&nbsp; Wrapper类型：Boolean, Character, Byte, Short, Integer, Long, Float, Double, Void<BR>&nbsp; <BR>&nbsp; 高精度的数值<BR>&nbsp;&nbsp;&nbsp; BigInteger支持任意精度的整数。也就是说，它可以精确地表示任意大的自然数，所以运算的时候不会丢失任何信息。<BR>&nbsp;&nbsp;&nbsp; BigDecimal能表示任意精度的浮点数；因此，你可以用它来进行精度要求极高的货币兑换的计算。<BR><BR>&nbsp; Java中的数组<BR><BR>你永远不需要清理对象<BR>&nbsp; 作用域(scope)<BR>&nbsp; 对象的作用域<BR><BR>创建新的数据类型：类<BR>&nbsp; 数据成员与方法(field &amp; method)<BR>&nbsp; Primiteve成员的缺省值：<BR>&nbsp;&nbsp;&nbsp; Primitive类型&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 缺省值<BR>&nbsp;&nbsp;&nbsp; boolean&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; False<BR>&nbsp;&nbsp;&nbsp; char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '\u0000'(null)<BR>&nbsp;&nbsp;&nbsp; byte&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (byte)0<BR>&nbsp;&nbsp;&nbsp; short&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (short)0<BR>&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<BR>&nbsp;&nbsp;&nbsp; long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0L<BR>&nbsp;&nbsp;&nbsp; float&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0f<BR>&nbsp;&nbsp;&nbsp; double&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0d<BR><BR>方法，参数和返回值<BR>&nbsp;&nbsp;&nbsp; 方法(method)的基本的组成包括方法的名字，参数，返回类型，以及方法的正文。<BR>&nbsp;&nbsp;&nbsp; 返回类型是指调用方法所返回的值的类型。参数列表则表示传给这个方法的数据的类型和名字。方法的名字再配合其参数列表，就可以唯一地标识一个方法。<BR>&nbsp;&nbsp;&nbsp; 调用方法通常被成为向对象发消息。<BR><BR>&nbsp; 参数列表<BR>&nbsp;&nbsp;&nbsp; Java传递对象的时候，实际上是在传reference。<BR><BR><BR>构建Java程序<BR>&nbsp; 名字的可见性<BR>&nbsp;&nbsp;&nbsp; 使用其他组件<BR>&nbsp;&nbsp;&nbsp; static关键词<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当你声明某样东西是static的时候，你的意思是，这项数据或方法没有被连到类的任何一个实例之上。因此即使你从没创建过那个类的对象，你也可以调用其static方法或者访问其static数据。<BR><BR><BR>第一个Java程序<BR>&nbsp; 编译和运行<BR><BR>注释和嵌入式的文档<BR>&nbsp; 注释文档<BR>&nbsp; 嵌入式的HTML<BR>&nbsp; 标记举例<BR><BR>编程风格<BR><BR>总结：本章对JAVA最基础的一些概念做了介绍。还有一些语法上的讲解，最后还给出一个完整的示例程序，还配合了javadoc做了演示。&nbsp;<BR><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;&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;&nbsp;&nbsp;<!--StartFragment --> 2005年03月09日 6:11 PM <img src ="http://www.blogjava.net/ranxiang/aggbug/17847.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:25 <a href="http://www.blogjava.net/ranxiang/articles/17847.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TIJ阅读笔记（第一章）</title><link>http://www.blogjava.net/ranxiang/articles/17846.html</link><dc:creator>冉翔</dc:creator><author>冉翔</author><pubDate>Wed, 02 Nov 2005 09:22:00 GMT</pubDate><guid>http://www.blogjava.net/ranxiang/articles/17846.html</guid><wfw:comment>http://www.blogjava.net/ranxiang/comments/17846.html</wfw:comment><comments>http://www.blogjava.net/ranxiang/articles/17846.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ranxiang/comments/commentRss/17846.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ranxiang/services/trackbacks/17846.html</trackback:ping><description><![CDATA[<!--StartFragment -->&nbsp; 
<P>1·对象简介</P>
<P>抽象的过程</P>
<P>Smalltalk的五项特征代表了纯的面向对象的编程方法：<BR>1。万物皆对象。<BR>2。程序就是一组相互之间传递消息，告诉对象该干些什么的对象。<BR>3。每个对象都利用别的对象来组建它自己的记忆。<BR>4。对象都有类型。<BR>5。所有属于同一类型的对象能接受相同的消息。</P>
<P>对象有接口</P>
<P>对象会提供服务</P>
<P>隐藏实现</P>
<P>复用实现</P>
<P>继承：复用接口</P>
<P>可凭借多态性相互替换的对象</P>
<P>abstract基类和interface</P>
<P>对象的创建，使用和生命周期</P>
<P>Collection和迭代器</P>
<P>单根继承体系</P>
<P>下传与模板/泛型</P>
<P>确保正确地清除</P>
<P>垃圾回收器的效率与灵活性</P>
<P></P>
<P>异常处理：与错误打交道</P>
<P>并发</P>
<P>Persistence</P>
<P></P>
<P>Java 和 Internet</P>
<P>Web是什么？</P>
<P>把Web当作巨型的服务器</P>
<P>客户端编程</P>
<P><BR>Java为什么能成功</P>
<P>系统能更易于表达和理解</P>
<P>最大程度上利用类库</P>
<P>错误处理</P>
<P>编写大项目</P>
<P></P>
<P>总结：第三次看TIJ了，第一次没看明白，第二次看了一般。这次重看，虽然只看了第一章，但是感觉自己又有了不少收获。一定要再接再厉。爱Java，爱生活。感觉第一章没有什么需要评论的地方，主要是理解OOP的思想和吹捧JAVA的好处，所以仅列了几个标题。后续继续看，准备写一些自己的看法和感想。。。自己给自己加油，嘿嘿。<BR><BR><BR><BR><!--StartFragment -->&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;&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;&nbsp; 2005年03月08日 6:10 PM </P><img src ="http://www.blogjava.net/ranxiang/aggbug/17846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ranxiang/" target="_blank">冉翔</a> 2005-11-02 17:22 <a href="http://www.blogjava.net/ranxiang/articles/17846.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>