代码复用是面向对象编程(OOP)最具魅力的原因之一。
代码复用的两种实现方式:组合和继承
组合语法
把对象的引用(object references)放置在一个新的类里,这就使用了组合
编译器不会为每个引用创建一个默认对象,这是有意义的,因为在许多情况下,这会导致不必要的开销。初始化引用有四种方法:
- 当对象被定义时。这意味着它们总是在调用构造函数之前初始化。比如:生声明类的属性时:private String s1 = “Happy”
- 在该类的构造函数中。
- 在实际使用对象之前。这通常称为延迟初始化。在对象创建开销大且不需要每次都创建对象的情况下,它可以减少开销。
- 使用实例初始化。使用构造代码块,构造代码块总是在构造函数之前执行。(代码块详解https://blog.csdn.net/abc67509227/article/details/102328042)
继承语法
继承是所有面向对象语言的一个组成部分。事实证明,在创建类时总是要继承,因为除非显式地继承其他类,否则就隐式地继承 Java 的标准根类对象(Object)。使用关键字 extends 后跟基类的名称
- 初始化基类
继承并不只是复制基类的接口。当你创建派生类的对象时,它包含基类的子对象。这个子对象与你自己创建基类的对象是一样的。只是从外部看,基类的子对象被包装在派生类的对象中。
必须正确初始化基类子对象:通过调用基类构造函数在构造函数中执行初始化,Java 自动在派生类构造函数中插入对基类构造函数的调用(无参构造函数)。 - 带参数的构造函数
如果没有无参数的基类构造函数,或者必须调用具有参数的基类构造函数,则必须使用 super 关键字和适当的参数列表显式地编写对基类构造函数的调用。
委托
Java不直接支持的第三种重用关系称为委托(c语言中支持)。这介于继承和组合之间,因为你将一个成员对象放在正在构建的类中(比如组合),但同时又在新类中公开来自成员对象的所有方法(比如继承)
委托简单的模式:
//A接受消息,委托了给B做事
//委托类
public class A{
被委托类
private b= new B();
public void back(int velocity) {
b.back(velocity);
}
}
委托模式详解:http://www.uml.org.cn/j2ee/200411036.htm#22
组合与继承的选择
组合和继承都允许在新类中放置子对象(组合是显式的,而继承是隐式的)。
“是一个”的关系是用继承来表达的,而“有一个“的关系则用组合来表达
protected
它表示“就类的用户而言,这是 private 的。但对于任何继承它的子类或在同一包中的类,它是可访问的。”(protected 也提供了包访问权限)
尽管可以创建 protected 属性,但是最好的方式是将属性声明为 private 以一直保留更改底层实现的权利。然后通过 protected 控制类的继承者的访问权限(setter和getter)。
向上转型
继承图中派生类转型为基类是向上的,所以通常称作向上转型。因为是从一个更具体的类转化为一个更一般的类,所以向上转型永远是安全的。也就是说,派生类是基类的一个超集。它可能比基类包含更多的方法,但它必须至少具有与基类一样的方法。在向上转型期间,类接口只可能失去方法,不会增加方法。这就是为什么编译器在没有任何明确转型或其他特殊标记的情况下,仍然允许向上转型的原因。
向上转型后,子类和父类的属性和方法关系 :https://blog.csdn.net/Hurricane_m/article/details/89006463
final关键字
在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)
- 修饰基本类型后,数据初始化后不可变,修饰对象类型后,对象地址不可变,对象内容可变。
- 修饰方法,方法不可被继承子类重写。
- 修饰类,不可被继承。
详解:https://www.cnblogs.com/xuelisheng/p/11158110.html
类初始化和加载
每个类的编译代码都存在于它自己独立的文件中。该文件只有在使用程序代码时才会被加载。一般可以说“类的代码在首次使用时加载“。这通常是指创建类的第一个对象,或者是访问了类的 static 属性或方法。构造器也是一个 static 方法尽管它的 static 关键字是隐式的。因此,准确地说,一个类当它任意一个 static 成员被访问时,就会被加载。
首次使用时就是 static 初始化发生时。所有的 static 对象和 static 代码块在加载时按照文本的顺序(在类中定义的顺序)依次初始化。static 变量只被初始化一次。
继承和初始化
先初始化父类,再初始化子类
本章小结
继承和组合都是从已有类型创建新类型。组合将已有类型作为新类型底层实现的一部分,继承复用的是接口。
使用继承时,派生类具有基类接口,因此可以向上转型为基类,这对于多态至关重要,在下一章你将看到。
尽管在面向对象编程时极力强调继承,但在开始设计时,优先使用组合(或委托),只有当确实需要时再使用继承。组合更具灵活性。另外,通过对成员类型使用继承的技巧,可以在运行时改变成员的类型和行为。因此,可以在运行时改变组合对象的行为。
在设计一个系统时,目标是发现或创建一系列类,每个类有特定的用途,而且既不应太大(包括太多功能难以复用),也不应太小(不添加其他功能就无法使用)。如果设计变得过于复杂,通过将现有类拆分为更小的部分而添加更多的对象,通常是有帮助的。
当开始设计一个系统时,记住程序开发是一个增量过程,正如人类学习。它依赖实验,你可以尽可能多做分析,然而在项目开始时仍然无法知道所有的答案。如果把项目视作一个有机的,进化着的生命去培养,而不是视为像摩天大楼一样快速见效,就能获得更多的成功和更迅速的反馈。继承和组合正是可以让你执行如此实验的面向对象编程中最基本的两个工具。