### 复用代码是Java 众多引人注目的功能之一。
》》组合语法:
### toString() 方法,每一个非基本类型的对象都
有一个 toString() 方法
》》继承语法:
### extends 关键字
子类继承父类中的内容,会的得到父类中的
所有域和方法。
### 当创建一个类的时候,总是在继承,因此,
除非已明确指出要从其他类中继承,否则就是在
隐式地从 Java 的标准根类 Object 进行继承。
### 在每个类中都设置一个 main() 方法可使每个
类的单元测试都变得简单易行。而且在单元测试
完成以后,也无需删除 main() 方法,可以将其留
待下次测试。
### 为了继承,一般的规则是将所有的数据成员都
指定为 private ,将所有的方法指定为 public 。当然,
特殊情况下,必须做出调整。
### 继承是对类的复用
###Java 用 super 关键字表示超类的意思,当前类
就是从超类继承来的。
### 在继承过程中,并不一定是非得使用基类的方法。
也可以在导出类中添加新的方法,其添加方式与类中
添加任意方法一样,即对其加以定义即可。
--------初始化基类
### 对基类子对象的正确初始化也是至关重要的,而且
也仅有一种方法来保证 这一点:
在构造器中调用基类构造器来执行初始化,而基类
构造器会有具有执行基类初始化所需要的所有知识和能
力。Java 会自动在导出类的构造器中插入对基类构造器
的调用。
### 构建过程是从基类“向外”扩散的,所以基类在导出类
构造器可以访问它之前,就已经完成了初始化。
### 在导出的子类中,即使你不创建任何构造器,编译器
也会为你合成一个默认的构造器,该构造器将调用基类的
构造器。
@@@@ 带参数的构造器
### 如果没有默认的基类构造器,或者想调用一个带有
参数的基类构造器,就必须使用关键字 super 显式地编写
调用基类构造器的语句,并且配以适当的参数列表。
例如:super(合适的参数)
### 而且,调用基类构造器必须是你在导出类构造器中要
做的第一件事。
》》代理:
### 第三种关系称为代理,Java 并没有提供对它的直接支持。
这是继承与组合之间的中庸之道,因为我们将一个成员对象
置于所要构造的类中(就像组合),但与此同时我们在新类
中暴露了该成员对象的方法(就像继承)。
### 我们使用代理时可以拥有更多的控制力,因此我们可以
选择只提供在成员对象中的方法的某个子集。
### 尽管Java 语句不直接支持代理,但是很多开发工具却
支持代理。例如,使用 JetBrains Idea IDE 就可以自动生成。
》》结合使用组合和继承:
### 同时使用组合和继承是很常见的事。
### 虽然编译器强制你去初始化基类,并且要求你在构造器
起始处就要这么做,但是它并不监督你必须将成员对象也初
始化,因此在这一点上你自己必须时刻注意。
--------确保正确清理
### 有时类可能要在其生命周期内执行一些必需的清理
活动。
### 如果你想在某个类清理一些东西,就必须显式地编
写一个特殊的方法来做这件事,并要客户端程序员知晓他们
必须要调用这一方法。
首要任务就是,必须将这一清理动作置于 finally
子句中,以预防异常的出现。
### 关键字 try 表示,下面的块(用一组大括号括起来的
范围)是所谓的保护区,这意味着它需要被特殊处理。其中一
项特殊处理就是无论 try 块是怎样退出的,保护区后的 finally
子句中的代码总是要被执行的。
### 执行类的所有特定的清理动作,其顺序同生成顺序相反
(通常这就要求基类元素仍旧存活)。
###许多情况下,清理并不是问题,仅需让垃圾回收器完成
该动作就行。但当必须亲自处理清理时,就得多努力并多加小心。
因为,一旦涉及垃圾回收,能够信赖的事就不会很多了。垃圾回收
器可能永远也无法被调用,即使被调用,它也可能以任何它想要的
顺序来回收对象。最好的办法是除了内存以外,不能依赖垃圾回收
器去做任何事。如果需要进行清理,最好是编写你自己的清理方法,
但是不要使用 finalize() 。
-------名称屏蔽
### 如果 Java 的基类拥有某个已经被多次重载的方法名称,那
么在导出类中重新定义该方法的名称并不会屏蔽其在基类中的任何
版本。无论是在该层或是它的基类中对方法进行定义,重载机制(
方法名相同,而返回值不同)都可以正常工作。
### @Override 注解,它并不是关键字,但是可以把它当作关键
字使用。当你想要覆写(或称覆盖)某个方法时,可以选择添加这个
注解,在你不留心重载而并非覆写该方法时,编译器就会生成一条
错误消息。
### @Override 注解可以防止你在不想重载时而意外地进行了重载。
》》在组合和继承之间选择
### 组合和继承都允许在新的类中放置子对象,组合是显式地这样做,
而继承是隐式地做。
### 组合技术通常用于想在新类中使用现有类的功能而非它的接口
这种情形。即,在新类中嵌入某个对象,让其实现所有的功能,但
新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。
为取得此效果,需要在新类中嵌入一个现有类的 private 对象。
### (特例)有时,允许类的用户直接访问新类中的组合成分是极具
意义的;也就是说,将成员对象声明为 public 。如果成员对象自身都
隐藏了具体的实现,那么这种做法是安全的。当用户能够了解到你正在
组装一组部件时,会使得端口更加易于理解。
### “is -- a” (是一个)的关系是用继承来表达的;
而 " has -- a"(有一个)的关系是用组合来表达的。
》》protected 关键字
### protected 关键字,它指明“就类用户而言,这是private 的,但对于
任何继承于此类的导出类或其他任何处于同一个包内的类来说,它
却是可以访问的。”(protected 也提供了包访问权限)。
### 尽管可以创建 protected 域,但是最好的方式还是将域保持为 private ,
你应当一直保留”更改底层实现“的权利。然后通过 protected 方法来
控制类的继承者的访问权限。
》》向上转型:
### ”为新的类提供方法“并不是继承技术中最重要的方面,其最重要的方面
是用来表现新类和基类之间的关系。这种关系可以用”新类是现有类的
一种类型“这句话加以概括。
------为什么称为向上转型
### 由于向上转型是从一个较专用类型向较通用类型转换,所以总是很安全的。
### 导出类是基类的一个超集,它可能比基类含有更多的方法,但它必须至少
具有基类中的所含有的方法。
### 在向上转型过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取
它们。
------再论组合与继承
### 在面向对象编程中,生成和使用程序代码最有可能采用的方法是直接将
数据和方法包装进一个类中,并使用该类的对象。也可以运用组合技术
使用现有类来开发新的类;而继承技术其实是不太常用的。
### 到底是该使用组合技术还是使用继承技术,一个最清晰的判断办法就是
问一问自己是否需要从新类向基类进行向上转型。如果必须向上转型,则
继承是必要的;但如果不需要,则应当好好考虑自己是否需要继承。
》》final 关键字:
### 根据上下文环境,Java 的关键字 final 的含义存在着细微的区别,但是
通常它指的是“这是无法改变的。”不想做改变可能出于两种理由:
设计或效率。由于这两个原因相差很远,所以关键字 final 很可能被误用。
### 可能使用 final 的三种情况:数据、方法和类。
------final 数据
### 在 Java 中,编译期常量必须是基本数据类型,并且以关键字 final 表示。
在对这个常量进行定义的时候,必须对其进行赋值。
### 一个既是 static 又是 final 的域指占据一段不能改变的存储空间。
### 对用于对象的引用,final 使 引用恒定不变。一旦引用被初始化指向一个对象,
就无法再把它改为指向另一个对象。然而,对象其自身是可以被修改的。这一
限制也适用数组,它也是对象。
### 根据惯例,既是 static 又是 final 的域(即编译期常量)将用大写表示,并
使用下划线分隔各个单词。
### 例如: public static final int VALUE_THREE = 39;
说明:上面的例子是典型的对常量进行定义的方式
public , 则可被用于包之外;
static ,则强调只有一份;
final , 则表示它是一个常量。
### 将 final 数值定义为静态的和非静态的区别,只有当数值在运行时内被初始化
时才会显现。
@@@@ 空白 final
### Java 允许生成“空白final”,所谓空白 final 是指被声明为 final 但又未给定初值
的域。无论什么情况,编译器都确保空白 final 在使用前必须被初始化。但是,
空白 final 在关键字 final 的使用上提供了更大的灵活性,为此,一个类中的
final 就可以做到根据对象的而有所不同,却又保持其恒定不变的特性。
### 必须在域的定义处或者每个构造器中用表达式对 final 进行赋值,这正是 final
域在使用前总是被初始化的原因所在。
@@@@ final 参数
###Java 允许在参数列表中以声明的方式将参数指明为 final 。这意味着你无法在
方法中更改参数引用所指向的对象。
### 你可以读参数,但却无法修改参数。这一特性主要用来向匿名内部类传递
数据
------final 方法
### 使用 final 方法的原因有两个:
第一:把方法锁定,以防止任何继承类修改它的含义。这是出于设计的考虑:
想要在继承中使方法行为保持不变,并且不会被覆盖。
第二:效率。
在使用 Java SE 5/6 时,应该让编译器和JVM 去处理效率问题,只有在
想要明确禁止覆盖时,才将方法设置为 final 。
@@@@ final 和 private 关键字:
### 类中所有的 private 方法都是隐式地指定为 final 的。由于无法取用 private
方法,所以也就无法覆盖它。
### “覆盖”只有在某方法是基类的接口的一部分才会出现。即,必须能将一个对象
向上转型为它的基本类型并调用相同的方法。
### 如果某方法为 private ,它就不是基类的接口的一部分。它仅是一些隐藏于类
中的程序代码,只不过是具有相同的名称而已。
### 由于 private 方法无法触及而且能有效隐藏,所以除了把它看成是因为它所
归属的类的组织结构的原因而存在外,其他任何事物都不需要考虑到它。
------final 类
### 当将某个类的整体定义为 final 时(通常将关键字 final 置于它的定义之前),
就表明了你不打算继承该类,而且也不允许别人这样做。换句话说,出于某种考虑,
你对该类的设计永不需要做任何变动,或者出于安全的考虑,你不希望它有子类。
### 由于 final 类禁止继承,所以 final 类中所有的方法都隐式指定为 final 的。
------有关 final 的忠告
### 现代 Java 的容器库用 ArrayList 替代了 Vector
### 现代 Java 的容器库用 HashMap 替代了 Hashtable
》》初始化及类的加载
### 在Java 中,每个类的编译代码都存在于它自己独立的文件中。该文件只在
需要使用程序代码时才会被加载。
### 一般来说,可以说:“类的代码在初次使用时才加载”。这通常是指在加载发生
于创建类的第一个对象之时, 但是当访问 static 域或 static 方法时,也会发生加
载。
### 初次使用之处也是 static 初始化发生之处。所有的 static 对象和static 代码
段都会在加载时依程序中的顺序(即,定义时的书写顺序)而依次初始化。当然,
定义为 static 的东西只会被初始化一次。
-----继承与初始化
### 了解包括继承在内的初始化全过程,以对所发生的一切有个全局性的把握。
》》总结:
### 组合和继承都能从现有的类型生成新类型。组合一般是将现有的类型作为新类型
底层实现的一部分来加以复用,而继承复用的是接口。
### 在使用继承时,由于导出类具有基类接口,因此它可以向上转型至基类,这对多态
来讲是至关重要的。
### 尽管面向对象编程对继承极力强调,但在开始一个设计时,一般应优先使用组合
(或者可能是代理),只在确实必要时才使用继承。因为组合更具有灵活性。
### 在设计一个系统时,目标应该是找到或创建某些类,其中每个类都有具体的用途,
而且既不会太大(包含太多的功能而难以复用),也不会太小(不添加其他功能就
无法使用)。如果你的设计变得过于复杂,通过将现有类拆分为更小的部分而添加
更多的对象,通常会有所帮助。
### 当你开始设计一个系统时,应该认识到程序开发是一种增量过程,犹如人类的学习
一样,这一点很重要。程序开发依赖于实验,你可以尽己所能去分析,但当你开始执行
一个项目时,你仍然无法知道所有的答案。如果将项目视作是一种有机的、进化着的
生命体而去培养,而不是打算像盖摩天大楼一样快速见效,就会获得更多的成功和更
快速的回馈。继承与组合正是在面向对象程序设计中使得你可以执行这种实验的最基本
的两个工具。