Thinking in Java笔记

来源:互联网 发布:批量查询域名是否备案 编辑:程序博客网 时间:2024/05/16 14:39
第一章 对象入门
1.1抽象的进步
所有编程语言的最终目的都是提供一种抽象的方法。
OOP允许我们根据问题来描述问题,而不是根据方案。
Alan Kay总结了Smalltalk的五大特征:
(1)所有东西都是对象。(2)程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。(3)每个对象都有自己的存储空间,可容纳其他对象。(4)每个对象都有一种类型。(5)同一类所有对象都能接受相同的消息。


1.2对象的接口
我们向对象发出的请求是通过它的接口定义的,对象的类规定了它的接口形式。类与接口的等价或对应关系是面向对象程序设计的基础。


1.3实现方案的隐藏
有两方面原因促使我们控制对成员的访问:(1)防止程序员接触他们不该接触的东西。(2)允许库设计人员修改内部结构,不同担心他会对客户程序员造成什么影响。


1.4方案的重复使用
1.5继承:重新使用接口
“等价”:若继承只改善原基础类的函数。
“类似”:为衍生类型加入新的借口元素。


1.6多形对象的互换使用
将衍生类的对象当作基础类的一个对象对待。它意味着我们只需编写单一的代码,令其忽略类型的特定细节,只与基础类打交道。
将一条消息发给对象时,如果并不知道对方的具体类型是什么,但采取的行动同样是正确的,这种情况就叫做“多形性”。
抽象方法只能在一个抽象类里创建。继承了一个类后,那个方法必须实现,否则继承的类也会变成“抽象”类。


1.7对象的创建和存在时间
集合与继承器
单根结构中的所有对象都有一个通用接口,所以他们最终都属于相同的类型。
由于集合只能容纳Object,所以在我们向集合里添加对象句柄时,他会上溯造型成Object。调用时“下塑造型”和运行期检查都要求花额外的时间运行程序,而且程序员必须付出额外的精力。为此采用“参数化类型”(java未采用),他们是编译器能自动定制的类,可与特定的类型配合。
在Java中,垃圾收集器在设计时已经考虑了内存的释放问题。垃圾收集器“知道”一个对象在什么时候不再使用,然后会自动释放那个对象占据的内存空间。代价就是运行期的开销。
1.8违例控制:解决错误
利用违例能够可靠的从一个糟糕的环境中恢复。


1.9多线程
1.10永久性
“有限永久性”,可以将对象简单的保存在磁盘上。


1.11Java和因特网
1.12分析和设计


第二章 一切都是对象
2.1用句柄(引用、指针)操纵对象


2.2所有对象都必须创建
有留个地方可以保存数据:
(1)寄存器。最快的区域,对其没有直接的控制权。
(2)堆栈。驻留与常规RAM区域,对象句柄保存在堆栈里。
(3)堆(Heap)。也在RAM区域,保存了Java对象。和堆栈不同,堆最吸引人的地方在于编译器不必要知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。获得更大的灵活性,但在堆里分配存储空间是会花掉更长的时间。
(4)静态存储。静态指位于固定位置(也在RAM里)。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间。
(5)常数存储。通常直接置于代码内部。
(6)非RAM存储。
Java可以保证被初始化,而且不可在他的范围之外访问。


2.3绝对不要清除对象
Java有一个特别的“垃圾收集器”,它会查找用new创建的所有对象,并辨别其中哪些不再被引用。随后,它会自动释放由那些闲置对象占据的内存。这意味着我们根本不必操心内存的回收问题,只需简单地创建对象,一旦不再需要他们,他们就会自动离去。


2.4新建数据类型:类
若某个主数据类型属于一个类成员,那么即使不明确(显式)进行初始化,也可以保证他们获得一个默认值。然而这种保证却并不适用于“局部”变量,这一保证通过编译期的出错提示表现出来。


2.5方法、自变量和返回值
2.6创建Java程序


第三章 控制程序流程
3.1使用Java运算符
3.2执行控制


第四章 初始化和清除
4.1用构造器自动初始化
4.2方法过载
若数据类型“小于”方法中使用的自变量,就会对那种数据类型进行“转型”处理。若“大于”,编译器会报告出错。
不能根据返回值类型来区分过载的方法,例:f();
如果已经定义了一个构造器,编译程序不会帮我们自动合成一个。
在一个构造器中,若为this赋予一个自变量列表,那么this关键字会具有不同的含义:他会对与那个自变量列表相符的构造器进行明确的调用。但不可调用两个。
static意味着一个特定的方法没有this。不可以从一个static方法内部发出对非static方法的调用。


4.3清除:收尾和垃圾收集
垃圾收集器只知道释放那些由new分配的内存,所以不知道如何释放对象的“特殊”内存。为解决这个问题,Java提供了一个名为finalize()的方法,可为我们的类定义它。他的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存。所以如果使用finalize(),就可以在垃圾收集期间进行一。
垃圾收集并不等于破坏!它意味着在我们不再需要一个对象之前,有些行动是必须采取的,而且必须由自己来采取这些行动。
我们的对象可能不会当作垃圾被收掉!
垃圾收集只跟内存有关!


4.4成员初始化
在创建了第一个对象以后,static对象不会重新初始化。
Java允许我们将其他static初始化工作划分到类内一个特殊的“static构建从句”。
class Spoon{
    static int i;
    static {
        i = 47;
    }
}
4.5数组初始化


第五章 隐藏实施过程
5.1包:库单元
5.2Java访问指示符
5.3接口与实现
5.4类访问
(1)每个编译单元都只能有一个public类。否则编译出错。
(2)public类的名字必须与包含了编译单元的文件名完全相符。
(3)可能有一个编译单元没有任何公共类。此时,可按自己的意愿任意指定文件名。


第六章 类再生
6.1合成的语法
只需在新类里简单地置入对象句柄即可。


6.2继承的语法
如果类没有默认的自变量,或者想调用含有一个自变量的某个基础类构建器,必须明确地编写对基础类的调用代码。这是用super关键字以及适当的自变量列表实现的。


6.3合成与继承的结合
6.4到底选择合成还是继承
如果想利用新类内部一个现有类的特性,而不想使用它的接口,通常应选择合成。但新类的用户会看到我们已定义的接口,而不是来自嵌入对象的接口。考虑到这种效果,我们需要在新类里嵌入现有类的private对象。
如选择继承,就需要取得一个现成的类,并制作它的一个特殊版本。


6.5protected
6.6积累开发
继承的一个好处是它支持“积累开发”,允许我们引入新的代码,同时不会为现有代码造成错误。


6.7上溯造型
判断自己到底应该选用合成还是继承,一个最简单的办法就是考虑是否需要从新类上溯造型回基础类。


6.8final关键字
空白final具有最大的灵活性。例如,位于类内部的一个final字段对每个对象都可以有所不同,同时依然保持其“不变”的本质。
之所以要使用final方法,可能是出于两方面理由的考虑。第一个是希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写。第二个理由是程序执行的效率。讲一个方法设成final后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。
final类不允许继承。


6.9初始化和类的装载


第七章 多形性
面向对象的三种最基本的特征:数据抽象、继承和多形性。
7.1上溯造型
7.2深入理解
讲一个方法调用同一个方法主体连接到一起称为“绑定”。
Java中绑定的所有方法都采用后期绑定,除非一个方法已被声明称final。将一个方法声明成final可以有效地关闭动态绑定,从而让编译器生成效率更高的代码。
Shape s = new Circle();
s.draw();实际调用的是Circle.draw(),因为后期绑定已经介入(多形性)。
将发生改变的东西同没有发生改变的东西区分开。


7.3覆盖与过载
7.4抽象类和方法
抽象方法只含有一个声明,没有方法主体。
包含了抽象方法的类为抽象类。
继承抽象类必须为所有抽象方法提供方法定义,如果不这样做,则衍生类也是抽
象的。


7.5接口
接口的基本数据类型的数据成员都默认为static和final。
接口方法默认为public,实现接口的方法默认为protected。
使用接口最重要的原因:能上溯造型至多个基础类。
利用继承,可以方便地为一个接口添加新的方法声明,也可以将几个接口合并成一个新的接口。


7.6内部类
内部类被设为private。意味着客户程序员对这些成员的认识与访问将会受到限制。
两方面原因使用内部类:(1)准备实现某种形式的接口,使自己能创建和返回一个句柄。(2)创建一个类,同时不愿意把他公开。
匿名内部类不能有构造器。
若试图定义一个匿名内部类,并想使用匿名内部类外部定义的一个对象,则编译器要求外部对象为final属性。
内部类的对象同时拥有指向封装对象的一个链接。
内部类的对象默认持有创建它的那个封装类的一个对象的句柄。
static内部类意味着:(1)不需要一个外部类对象。(2)不能从static内部类的一个对象中访问一个外部类对象。
限制:由于static成员只能位于一个类的外部级别,所以内部类不可能有static数据或static内部类。
static内部类可以成为接口的一部分。由于类是“静态”的,所以它不会违反接口的规则——static内部类只位于接口的命名空间内部。
可考虑用一个static内部类容纳自己的测试代码。
若想生成外部类对象的句柄,就要用一个点号以及一个this来命名外部类。
从内部类继承。//TODO
当从外部类继承的时候,没有任何额外的内部类继承下去。
仍然可能“明确”地从内部类继承:BigEgg2.Yolk明确地扩展了Egg2.Yolk,而且覆盖了它的方法。方法insertYolk允许BigEgg2将他自己的某个Yolk对象上溯造型至Egg2的y句柄。所以当g()调用y.f的时候,就会使用f()被覆盖版本。
内部类标识符:$
一个应用程序框架是指一个或一系列类,他们专门设计用来解决特定类型的问题。设计的关键:“将发生变化的东西同没有变化的东西区分开”,这正是内部类大显身手的地方。他们允许我们做两件事情:(1)在单独一个类里表达一个控制框架应用的全部实施细节,从而完整地封装与那个实施有关的所有东西。内部类用于表达多种不同类型的action(),他们用于解决实际的问题。除此以外,使用private内部类,所有实施细节会完全隐藏起来,可以安全地修改。(2)内部类使我们具体的实施变得更加巧妙,因为能方便地访问外部类的任何成员。


7.7构建器和多形性
只有基础类的构建器在初始化自己的元素时才知道正确的方法以及拥有适当的权限。所以,必须令所有构建器都得到调用。
0 0
原创粉丝点击