原文位址
複用代碼是 Java 衆多引人注目的功能之一。但要想成為極具革命性的語言,僅僅能夠複制diamante并對之加以改變是不夠的,它還必須能夠做更多的事情。
組合用法
這個使用者最為常用,即在建立的類中,持有别的對象的引用。假設你需要某個對象,它要具有多個 String 對象,幾個基本類型資料,以及另一個了類的對象,這種使用在開發中最為常見。對于非基本類型的對象,必須将其引用置于新的類中。
繼承用法
組合的用法比較平實,但是繼承使用的是一種特殊的文法。在繼承過程中,需要先聲明新類與舊類相似。
class Main {
public static void main(String[] args) {
Student student = new Student();
}
}
class People {
People() {
System.out.println("People");
}
People(String name) {
System.out.println("People" + name);
}
}
class Worker extends People{
Worker() {
System.out.println("Worker");
}
Worker(String name) {
super(name);
System.out.println("Worker" + name);
}
}
class Student extends Worker {
Student() {
System.out.println("Student");
}
Student(String name) {
super(name);
System.out.println("Student" + name);
}
}
運作結果:
People
Worker
Student
這種繼承關系的又叫做父子關系,子類繼承了所有父類的特點,即公開成員變量和公開的方法,當調初始化子類構造函數的時候,會預設調用父類的無參構造函數。當然你也可以通過
super
的方式主動選擇調用父類的某個構造函數。
組合加繼承的方式
同時使用組合和繼承也是非常常見的事。
class Shape {
public static void main(String[] args) {
CADSystem system = new CADSystem();
try {
// ..
} finally {
system.dispose();
}
}
private int age;
Shape(int i) {
System.out.println("Shape construct");
age = i;
}
void dispose() {
System.out.println("Shape dispose");
}
@Override
public String toString() {
return "age:" + age;
}
}
class CADSystem extends Shape {
private line[] lines = new line[];
private Circle circle;
private Rect rect;
CADSystem(int i) {
super(i);
for (int j = ; j < lines.length; j++) {
lines[j] = new line(j);
}
circle = new Circle(i);
rect = new Rect(i);
System.out.println("CADSystem construct");
}
@Override
void dispose() {
for (line line : lines) {
line.dispose();
}
circle.dispose();
rect.dispose();
super.dispose();
}
}
class line extends Shape {
line(int i) {
super(i);
System.out.println("Line construct " + i);
}
@Override
void dispose() {
System.out.println("line dispose");
super.dispose();
}
}
class Circle extends Shape {
Circle(int i) {
super(i);
System.out.println("Circle construct");
}
@Override
void dispose() {
System.out.println("Circle dispose");
super.dispose();
}
}
class Rect extends Shape {
Rect(int i) {
super(i);
System.out.println("Rect construct");
}
@Override
void dispose() {
System.out.println("Rect dispose");
super.dispose();
}
}
其實有點像類的擴充卡模式,模拟這樣的一種行為,平時畫畫結束的時候,需要對資源進行清理。
Line
Circle
和
Rect
都是畫圖工具,同時繼承了
Shape
這個基類,并繼承了
dispose
釋放方法。
CADSystem
也繼承了
Shape
,并同時用三種工具的引用。在建立
CADSystem
的時候也完成了工具的初始化,釋放資源的時候,周遊所有工具并釋放資源。
在組合和繼承之間選擇
組合和繼承都允許在新的類中放置子對象,組合是顯示地這樣做,而繼承是隐式的做。
組合技術通常用于想在新的類中使用現有類的功能而非它的接口這種情況。即在新的類中嵌入某個對象,讓其實作所需要的功能,但新的類使用者看到的隻是為新類所定義的接口,而非所嵌入對象的接口。
繼承側重的是新類和基類之間的關系,這種關系可以用新類是現有類的一種類型這句話加以概括。
這個時候要提到一個用語「向上轉型」,在繼承圖中可以看出,基類位于上端,子類位于下端,子類轉成基類就是「向上轉型」,是以向上轉型是安全的。到這也可以這麼說,一個最清晰的判斷是用繼承還是組合的辦法:問一問自己是否需要從新類向基類進行向上轉型,如果必須向上轉型,則繼承是必須的,但如果不需要,則應當好好考慮是否需要繼承。
final
指無法改變的,不想做改變可能出于兩種理由:設計或效率。
final
修飾基本類型時,數值恒定不變;修飾對象引用,引用恒定不變。修飾方法,子類不能重寫該方法,修飾類,該類不能被繼承。
總結
繼承群組合都能從現有類型生成新類型,組合一般是将現有類型作為新類型底層實作的一部分加以複用,二繼承複用的是接口。
在使用繼承時,由于導出類具有基類接口,是以它可以向上轉型,這對多态來講至關重要。
盡管面向對象程式設計對繼承極力強調,但在開始一個設計時,一般優先選擇使用組合,隻在确實必要時才使用繼承。因為組合更具有靈活性,此外,通過對成員類型使用繼承技術的添加技巧,可以在運作時改變那些成員對象的類型和行為。
當你開始設計一個系統時,應該認識到程式開發是一個增量過程,猶如人類的學習一樣,這一點很重要。