登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

青山妩媚

新的一年,新的心情,新的挑战,新的起点...

 
 
 

日志

 
 

《Java编程思想》读书笔记  

2008-06-27 22:08:05|  分类: IT常识 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

引用

John@[百印]《Java编程思想》读书笔记(未完成)

要点笔记

说明:在Java中,“函数”称为“方法”

第一章 对象简介

   用已有的类来合成新的类,这一概念称为合成(composition,如果这个对象是动态合成的,通常把它称为聚合aggregation)。通常将合成称为“有(has-a)”关系,就像“轿车有引擎”。

   一味地使用继承会导致很奇怪也很复杂的设计。相反,在创建新类的时候,你应该优先考虑使用合成,这么做会更简单也更灵活,整个设计也会变得更加井井有条。

   基类同派生类的关系称作是(is-a)关系,如“圆是一种形状”。

   动态绑定(后绑定)是Java的缺省行为,在C++中这要用virtual关键字声明,因为这不是C++的缺省行为。

   把派生类当作它的基类来用的过程称为(类型的)上传(upcast)。上传是安全的。
   沿着继承图将消息向下传给一个更为具体的类型成为下传(downcast)。除非你对那些类型有十足地把握,否则下传十有八九是不安全的。
   Java的缺省访问权限为package权限,同属一个package的类可以访问这个package中其他类的“缺省权限”的成员,出了这个package,他们就都是private的了。

   Java只使用在堆中动态创建对象的方法,每次创建对象都要用new关键字动态地申请。但是Java的对象没有拆构函数,内存的回收是由垃圾收集器完成的。当然,你也可以用java.lang.System.gc()或java.lang.Runtime.gc()语句让垃圾回收器马上去工作,但是本人不保证效果。:P


第二章 万物皆对象

   Java使用reference操控对象,就像在C++中的指向对象的指针。但是在Java中,reference并不一定连着对象,所以比较安全的做法是,创建reference的时候就对它进行初始化。

   本地变量——也就是非类的成员变量,是不会获得缺省值的,所以它的值在初始化之前是任意的,这同C/C++是一样的。

   使用static关键字声明某样数据或方法后,这个数据或方法就可以不必连到具体的类的实例上,亦既是你不必通过类的实例来调用该数据或方法。但是用static关键字定义的类,只能由一个实例,亦既是该类的多个reference都连接到该类的同一个实例上。static方法常常被用来管理本类型的对象。

   javadoc只会处理public和protected成员的注释稳当,它不会去管private和package访问权限的成员的注释,不过你可以使用-private标记,将private成员也包括进去,但是我本人不推荐你这么做。


第三章 控制程序流程

   几乎所有的运算符都只能作用于primitive,但是'=','==',以及'!='是例外,他们可以作用于任何对象。此外,String类也支持'+'和'+='。

   equals()的缺省行为是比较reference。

   短接效应/短路效应,比如a && b && c,如果a&& b为假,那么整个表达式的结果就为假。类似地,在a || b ||c中,如果a || b为真,则真个表达式为真。

   Java的右移位操作>>是带符号的右移位(signextension)。不带符号的右移位操作(zeroextension)为>>>。

   Java没有sizeof运算符,因为Java没有移植问题,所有的数据类型在所有的机器上都是相同的。

   Java的break和continue可以是带标签的,这意味着Java不需要goto语句。

第四章 初始化与清理


第十章

   让绝大多数代码只同代表这个类系的基类对象打交道,对它们来说,越少知道下面的具体类型越好。这样一来,代码的读写和维护就会变得更简单,而实现、理解和修改设计反感也会变得更容易一些。

   获取一个class对象的reference,可以使用所有class所共有的static属性的forName()方法,就像这样:Class.forName("ClassName")。也可以使用class常数,就像这样:ClassName.class。相对来说,使用class常数不但更简单,而且更安全,因为它是在编译时做检查的。此外由于没有方法调用,它的执行效率也更高一些。

   当你发现instanceof太多的时候,你就知道设计方案有问题了。

   instanceof vsclass的相等性:instanceof何instanceof()遵循了类型的概念,它问的是:“你是这个类,或者是从这个类派生出来的类吗?”而用“==”或equals()去比较两个class对象就与继承无关了——它要么是这个具体类型的,要么就不是。

   Java的本意是让你在程序里面全程使用多态性,只是在万不得已的情况下才使用RTTI。

   RTTI是在编译时让编译器打开并检查.class文件,也就是说,你是在通过“正常”途径调用对象的方法。而对reflection来说,编译时是得不到.class文件的;所以它是在运行时打开并检查那个文件。

   RTTI可以被用来记决效率问题。假设你写了一个很好的多态程序,但是运行的时候发现,有个对象反映奇慢。于是,你就可以用RTTI把这个对象捡出来。然后专门针对它的问题写代码以提高程序的运行效率。不过变成的时候切忌区过早优化代码。这是一个很有诱惑的陷阱。最好还是先让程序跑起来,然后再判断一下它跑得是不是够快了。只有觉得它还不够快,你才应该去着手解决效率问题——用profiler(第15章)

第十一章

   数组与其它容器的区别体现在三个方面:效率、类型识别以及可持有primitives(原始数据类型)。我个人认为第三点是最重要的一点。

   Java标准类库提供了一个System.arraycopy()的static方法。相比for循环,它能以更快的速度拷贝数组,且其对所有类型都作了重载。起用法为:
System.arraycopy(源数组,源数组起始下标,目标数组,目标数组起始下标,要拷贝的元素数量)。

   Java2(JDK1.4+)的容器类要解决“怎样持有对象”的问题,而它把这个问题分成了两类:
1.Collection:通常是一组有一定规律的独立元素。List必须按照特定的顺序持有这些元素,而Set则不能保存重复的元素(bag没有这个限制,但是Java的容器类库没有实现他,因为List已经提供这种功能了)。
2. Map:一组以“键——值(key -value)”形式出现的pair。初看上去,它应该是一个pair的Collection,但是真这么去做的话,它就会变得很滑稽,所以还是把这个概念独立列出来为好。退一步说,真的要用到Map的某个子集的时候,创建一个Collection也是很方便的。Map可以返回“键(key)的”Set,值的Collection,或者pair的Set。和数组一样,Map不需要什么修改,就能很容易地扩展成多维。你只要直接把Map的值设成Map就可以了(然后它的值再失Map,依此类推)。

   Java的容器有个缺点,就是往容器里面放对象的时候,会把对象的类型信息给弄丢了,因为容器被做成支持由Object(为了其通用性),也就是所有对象的根累得reference。故:
1.由于在将对象放入容器的时候,它的类型信息被扔掉了,所以容器对“能让里面加什么类型的对象”没有限制。比方说,即使你想让它只持有cat,别人也能很轻易地把dog放进去。
2.由于对象的类型信息没了,容器只知道它持有的Object的reference,所以对象在使用之前还必须进行类型转换。

   迭代器是一个对象,它的任务时,能在让“客户程序员在不知道,或者不关心他所处理的是什么样的底层序列结构”的情况下,就能在一个对象序列中前后移动,并选取其中的对象,此外迭代器还是一种通常所说的“轻量级”对象,即创建代价很小的对象。所以,你常会发现迭代器有一些看上去很奇怪的限制:比如有些迭代器只能按一个方向移动。

   printly()对所有的primitive和Object都作了重载;在各种情况下,它都会自动调用和使得toString()方法来生成它所需要的String对象。


   不经意的递归:
   由于Java的标准容器类(同其它类一样)也是继承Object的,因此他们也有一个toString()方法。这个方法已经被覆写了,所以它能生成一个表示它自己以及所有它所保存的独享的String。比如ArrayList的toString()方法就会便利ArrayList的每个元素,然后调用它们的toString()方法。假设你要打印类的地址。好像最直接的办法就是使用this(C++的程序员尤其喜欢用这种办法):
//:c11:InfiniteRecursion.java
//Accidental recursion.
//{RunByHand}
import java.util.*

public class InfiniteRecursion{
 public String toString(){
  return " InfiniteRecursionaddress: " + this + "\n";
 }
 public static woid main(String[] args){
  List v =  newArrayList();
  for(int i = 0; i < 10;i++)
   v.add(newnfiniteRecursion());
  System.out.printly(v);
 }
}///:\
如果你直接创建一个InfiniteRecursion,然后把它打印出来,你就会得到一串无穷无尽的异常。把它放到ArrayList也一样。这是toString()在作怪。当你写:

 " InfiniteRecursion address: " + this

的时候,编译器看到String和 '+'后面跟着的不是String。于是它试着将this转换成String。转换要用到toString(),于是就变成递归调用了。
   如果你真的想打印对象的地址,解决办法就是去调用Object的toString()方法,它就是干这活的。所以不要用this,应该写super.toString()。(PS:我之所以把这段完整地摘抄下来,就是为了以后能避免这种错误,因为它太让人痛苦了:P)


   Set的借口就是Collection德,所以其不像List(ArrayList和LinkedList)那样,它没有额外的功能。实际上Set确确实实就是一个Collection——只不过行为方式不同罢了。
   假如Set的每个元素必须是唯一的;否则,Set是不会把它加进去的。要想加进Set,Object必须定义equals(),这样才能表明对象的唯一性。同一个值,Set之接收一个实例。


   SortedSet意思是“根据随想的比较顺序”,而不是“插入顺序”进行排序。

   一个合适的equals()必须做到以下五点:
1. 反身性:对任何 x,x.equals( x ) 必须是 true 的。
2. 对称性:对任何 x 和 y ,如果 y.equals( x ) 是 true 的,那么x.equals( y ) 也必须是 true 的。
3. 传递性:对任何 x,y 和 z,如果 x.equals( y ) 是 true的,且y.equals( z ) 也是 true 的,那么 x.equals( z ) 也必须是 true的。
4. 一致性:对任何 x 和 y,如果对象里面涌来判断相等性的信息没有修改过,那么无论调用多少次x.equals(y),它都必须一致地返回 true 或 false。
5. 对于任何非空的 x,x.equals(null) 必须返回 false。

第十二章

Adding attributes and useful interfaces

 There is a drawback to the decorator pattern,however. Decorator give you mach more flexibility while you'rewriting a program (since you can easily mix and match attributes),but they add complexity to your code. The reason that the Java I/Olibrary is awkward to use is that you must create many classes -the "core" I/O type plus all the decorators - in order to get thesingle I/O object that you want.

 FilterInputStream and FilterOutputStream arederived from the base classes of the I/O library, InputStream andOutputStream, which is the key requirement of the decorator.


Writing to an PutputStream with FilterOutputStream

 PrintStream can be problematic because ittraps all IOExceptions (you must explicitly test the error statuswith checkError(), which returns true if an error has occured).Also, PrintStream doesn't internationalize properly and doesn'thandle line breaks in a platform-independent way (these problemsare solved with PrintWriter).


Readers & Writers

 The InputStream and OutputStream classesprovide valuable functionality in the form of byte-oriented I/O,whereas the Reader and Writer classes provide Unicode-compliant,character-based I/O. If you use the latters to replace the formers,you will receive a warning from compiler. While there are timeswhen you must use classes from the "byte" hierarchy in combinationwith classes in the "characher" hierarchy. To accomplish this,there are "adapter" classes:
InputStreamReader converts an InputStream to a Reader andOutputStreamWriter converts an OutputStream to a Writer.


Off by itselt: RandomAccessFile

 RandomAccessFile is not part of tehInputStream or OutputStream hierarchy. It stands alone, as a directdescendant of Object. The seeking methods are available only inRandomAccessFile, which works for files only.

  评论这张
 
阅读(378)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018