欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java编程思想第三版摘录

程序员文章站 2022-07-16 16:56:41
...

=========== <!----> <o:p> </o:p>

<o:p>   </o:p>

Chap1 对象简介 <o:p> </o:p>

<o:p>   </o:p>

       1. 抽象的过程 <o:p> </o:p>

       Alan Kay 总结了 Smalltalk 的五项基本特征。这些特征代表了纯的面向对象的编程方法: <o:p> </o:p>

       (1). 万物皆对象。将对象想成一种特殊的变量;它存储数据,而且还可以让你“提要求”,命令它进行某些操作。从理论上讲,你可以把所有待解决的问题中的概念性组件(狗,建筑,服务等)都标识成程序里的对象。 <o:p> </o:p>

       (2). 程序就是一组相互之间传递消息的对象。你只要向那个对象“发一个消息”,就能向它提出要求。更确切的说,你可以这样认为,消息是调用专属某个对象的方法的请求。 <o:p> </o:p>

       (3). 每个对象都利用别的对象来组建它自己的记忆。换言之,你通过将已有的对象打成一个包,来创建新的对象。由此,你可以将程序的复杂性,隐藏在对象的简单性之下。 <o:p> </o:p>

       (4). 对象都有类型。任何对象都是某个类的实例 (instance of a class) 。用以区分类的最突出的特点就是“你能传给它什么消息?” <o:p> </o:p>

       (5). 所有属于同一类型的对象能接受相同的消息。这种互换性 (substitutability) OOP 最强大的功能之一。 <o:p> </o:p>

       Booch 还给对象下了个更为简洁的定义: <o:p> </o:p>

       对象有状态,行为和标识。 <o:p> </o:p>

       这就是说,对象可以有内部数据(状态),有方法(因而产生了行为),以及每个对象都能同其它对象区分开来--具体而言,每个对象在内存里都有唯一的地址。 <o:p> </o:p>

       这句话或许有点太过了。因为对象还能存在于另一台及其上以及不同的内存空间中,此外还能保存在硬盘上。在这种情况下,对象的身份就不能用内存地址,而必须要用别的方法来确定。 <o:p> </o:p>

       <o:p> </o:p>

       2. 可凭借多态性相互替换的对象 <o:p> </o:p>

       OOP 的编译器的做法称为前绑定 (early binding) 。编译器会产生那个名字的函数的调用,而连接器负责将这个调用解析成须执行的代码的绝对地址。在 OOP 中,不到运行的时候,程序没法确定代码的地址,所以向泛型对象发送一个消息的时候,就要用到一些特别的手段。 <o:p> </o:p>

       OOP 语言用了后绑定 (late binding) 的概念。当你向某个对象送了一个消息后,不到运行时,系统不能确定到底该调用哪段代码。编译器只保证这个方法存在,并且检查参数和返回值的类型(不这么做的语言属于弱类型 weakly typed ),但是它并不知道具体执行的是哪段代码。 <o:p> </o:p>

       在有些语言中,你必须明确申明,某个方法要用到后绑定的灵活性( C++ virtual 关键字)。在这些语言中,方法不是默认地动态绑定的。而动态绑定是 Java 的缺省行为,因此无需添加什么额外的关键词就能获得多态性。 <o:p> </o:p>

       将派生类当作它的基类来用的过程称为上传( upcast ),反之称为下传( downcast )。下传所需的运行时检查会引起程序运行效率的降低,也加重了编程的负担。解决方案就是参数化类型 (parameterized type) 机制,即泛型。 <o:p> </o:p>

       <o:p> </o:p>

       3.Collection 和迭代器 <o:p> </o:p>

       ArrayList LinkedList ,都是简单的线性序列,具有相同的接口和外部行为。对于 ArrayList ,随机访问是一种时间恒定的操作。然而对于 LinkedList ,随机访问和选取元素的代价会很大。另一方面,如果要在序列中插入元素, LinkedList 的效率会比 ArrayList 的高出许多。 <o:p> </o:p>

<o:p>   </o:p>

<o:p>   </o:p>

<o:p>   </o:p>

============= <o:p> </o:p>

Chap2 万物皆对象 <o:p> </o:p>

<o:p>   </o:p>

       1. 数据存在哪里 <o:p> </o:p>

       数据可以存储在以下六个地方: <o:p> </o:p>

       (1). 寄存器 (registers) 。这是反应最快的存储,因为它处在 CPU 里。但寄存器数量有限,由编译器分配,你不能直接控制。 <o:p> </o:p>

       (2). (stack) 。位于常规内存区里, CPU 可以通过栈指针对它进行直接访问。栈指针下移就创建新的存储空间,上移就释放内存空间。这是仅次于寄存器的最快、最有效率的分配内存的方法。由于 Java 编译器必须生成能控制栈指针上下移的代码,所以程序编译的时候,那些将被存储在栈中的数据的大小和生命周期必须是已知的。 Java 把对象的 reference 存放在栈里。 <o:p> </o:p>

       (3). (heap) 。这是一段多用途的内存池,所有 Java 对象都保存在这里。在堆中分配空间时,编译器无需知道该分配多少空间,或数据会在堆里待多长时间。但是其速度比分配栈的慢些。 <o:p> </o:p>

       (4). 静态存储 (static storage) 。这里“静态”的意思是“在固定的位置” ( 尽管还是在 RAM 里面 ) 。静态存储里面的数据在整个程序运行期间都能访问到。可以用 static 关键词指明对象的某个元素是静态的,但是 Java 对象本身是决不会放到静态存储中去的。 <o:p> </o:p>

       (5). 固定存储 (constant storage) 。常量值通常直接放在程序里。有时常量还能为自己设置界限,这样在嵌入式系统中,就能选择是不是把它们放到 ROM 里面去。 <o:p> </o:p>

       (6). 非内存的存储 (Non-RAM storage) 。如果数据完全独立于程序,那么即使程序不运行,它也应该还在。对象被转化成某种能保存在其它介质上的东西,要用的时候,又能在内存里重建。 Java 提供了轻量级 persistence 的支持。 <o:p> </o:p>

       <o:p> </o:p>

       特例: primitive 类型 <o:p> </o:p>

       primitive( 原始 ) 类型的变量直接保存值,并且存储在栈中。 <o:p> </o:p>

       <o:p> </o:p>

       高精度的数值 <o:p> </o:p>

       Java 还包括两个能进行高精度算术运算的类: BigInteger BigDecimal <o:p> </o:p>

       <o:p> </o:p>

       作用域 <o:p> </o:p>

       int x = 12;<o:p></o:p>

       {<o:p></o:p>

       int x = 100;//illegal<o:p></o:p>

       }<o:p></o:p>

       <o:p> </o:p>

       2. 创建新的数据类型:类 <o:p> </o:p>

       只有在“变量被用作类的成员”时, Java 才能确保它获得默认值。本地变量,没有这种保障。 <o:p> </o:p>

       不管在哪种情况下, Java 在传递对象的时候,实际上是在传递 reference <o:p> </o:p>

       <o:p> </o:p>

       <o:p> </o:p>

       <o:p> </o:p>

============ <o:p> </o:p>

Chap3 控制程序流程 <o:p> </o:p>

<o:p>   </o:p>

       1. 运算符 <o:p> </o:p>

       逗号运算符 <o:p> </o:p>

       Java 里面,唯一一个把逗号当运算符用的地方是 for 循环。 <o:p> </o:p>

       <o:p> </o:p>

       String + 运算符 <o:p> </o:p>

       加号 (+) 用在 String 上的时候,如果表达式中有 String ,那么 Java 编译器会把其他的操作数都转换成 String <o:p> </o:p>

<o:p>   </o:p>

       Java 没有 sizeof<o:p></o:p>

       C C++ sizeof() 用于获取数据要占用多少字节的内存,需要 sizeof 的主要原因是为了移植。相同的数据类型在不同的机器上占用的内存长度可能会不一样。 <o:p> </o:p>

       Java 没有移植的问题,因此不需要 sizeof ,所有数据类型在所有的机器上都是相同的。 <o:p> </o:p>

<o:p>   </o:p>

       运算符的总结 <o:p> </o:p>

       在进行数学运算或混和赋值的时候, char byte short ,都会先进行提升,运算结果也是 int 。如果要把结果赋给原先那个变量,就必须明确地进行类型转换。 <o:p> </o:p>

       除了 boolean 之外,所有的 primitive 类型都能被转换成其它的 primitive 类型。 <o:p> </o:p>

       <o:p> </o:p>

       2. 执行控制 <o:p> </o:p>

       Java 不允许把数字当作 boolean 用,尽管 C C++ 允许这么做(非零值表示 true ,零表示 false )。 <o:p> </o:p>

       <o:p> </o:p>

       Java 里,唯一能放标签的地方,就是在循环语句的外面。而且必须直接放--在循环语句和标签之间不能有任何东西。而这么做的唯一理由就是,你会嵌套多层循环或选择。因为通常情况下 break continue 关键词只会中断当前循环,而用了标签后,就会退到 label 所在的地方。 <o:p> </o:p>

       label1:<o:p></o:p>

       outer-iteration{<o:p></o:p>

              inner-iteration{<o:p></o:p>

                     break;// 中断内循环,退到外循环 <o:p> </o:p>

                     continue;// 中断本次内循环,重新移到内循环开始处,执行下次内循环 <o:p> </o:p>

                     continue label1;// 中断本次外循环,移到外循环开始处,重新执行下次外循环 <o:p> </o:p>

                     break label1;// 退出外循环,执行循环以后的语句 <o:p> </o:p>

              }<o:p></o:p>

       }<o:p></o:p>

       如果退出循环或选择的同时,还要退出方法,可以直接使用 return <o:p> </o:p>

       continue break 以及 label 的规则: <o:p> </o:p>

       (1). 普通的 continue 会退到内部循环的最开始,然后继续执行内部循环。 <o:p> </o:p>

       (2). 带标签的 continue 会跳转到标签,并且重新进入直接跟在标签后面的循环。 <o:p> </o:p>

       (3).break 会从循环的“底部溜出去”。 <o:p> </o:p>

       (4). 带标签的 break 会从由这个标签标识的循环的“底部溜出去”。 <o:p> </o:p>

       Java 里能使用标签的唯一理由就是,在嵌套循环的同时要用 break continue 退出多层循环。 <o:p> </o:p>

       <o:p> </o:p>

       3.switch<o:p></o:p>

       switch 会根据整数表达式的值(可以是 char )决定应该运行哪些代码。 <o:p> </o:p>

       找到匹配的值后,就会执行相应的 case 语句,不会再进行比较。通常 case 语句应该以 break 结束。否则会直接执行下一个 case 语句,而不会再次进行匹配。如果没有匹配的 case ,则执行 default 语句。 <o:p> </o:p>

       <o:p> </o:p>

       计算细节 <o:p> </o:p>