抽象类同接口
词
- geometric 几何的
- subject 话题
概念
- 一个 superclass(超类) 定义相关 subclasses(子类) 的共同行爲
- 一个 interface(接口) 定义多个类的共同行爲(包括不相关的类)
13.2 Abstract Classes 1493
- abstract class (抽象类) 不能用去创建对象
- abstract class 可以包括 abstract method (抽象方法)
- abstract method (抽象方法) 会被 concrte(真实的) 子类所实现
- perimeter 週长
- are referred to as
- denote
- modifier
- appropriate13.2.2
- is worth noting 是值得注意的
13.51
13.1 Introduction p1492
父类定义相关子类的共同行爲。接口可以用来多个类的共同行爲(包括不相关类)。
你可以使用 java.util.Arrays.sort 方法去排序一个数字数组或者字符数组。你可以依然用 sort 方法去排序一个几何数组?爲了写出这样的代码,你必须知道接口。一个接口定义类的行共同爲。在讨论接口前,我们引入一个相关主题:抽象类。
13.2 Abstract classes
一個抽象類不能去創建對象。一個抽象類可以包含抽象方法,抽象方法會實現於實子類 concrete subclasses。
在 inheritance hierarchy 繼承體系 中,隨着新類的出現,類變得越來越具體,並且變得越來越實。如果你從子類返到父類,類會越來越通用越來越不具體。類的設計應該確保父類包含子類的共同功能。有時候,一個父類係好抽象,抽象到不可以建立具體實例。噉嘅類 被人叫作 is referred to as 抽象類 abstract class。
在 charpter 11 里,GeometricObject 定義成一個父類,Circle 同 Rectangle 的父類。GeometricObject 方法將幾何對象的共同特徵造成模型(model 將...做成模型)。兩者 Circle 同 Recangle 包含咗 getArea() 同 getPerimeter() 方法來計算圓同方型嘅面積和 週長 perimeter。
因爲你可以計算所有幾何圖形的面積同週長,最好定義 getArea() 同 getPerimeter() 方法在幾何對象類之中。但是這些方法不能被實現在幾何對象類中,因爲這些實現要基於特定的幾何對象類型。這樣的方法被稱作抽象類,並且用 abstract 修改器表示。當你定義了多個抽象方法於 GeometricObject 後,個類變成抽象類。
抽象類用 abstract 修改器標識。在 UML 圖上,抽象類同抽象方法的名字都會是斜體。
GeometricObject
|__ getArea(): double
GeometricObject.java
| 1 | public abstract class GeometricObject { | 
抽象類就好似普通的類,但係不可以用 new 來創建抽象類的實例。一個抽象方法只有定義,沒有實現。實現是它的子類的事情。一個類包含抽象方法,就必須定義成抽象類啦!
abstract class 的構建器被定義成 protected ,因爲只會它的子類會使用它。當你創建一個實子類的實例,是包含了它的父類構造器。
GeometricObject 抽象類定義了幾何對象的共同功能,並且提供了適當的構造器。因爲你不知道如何去計算幾何對象的面積和週長,所以 getArea() 同 getPerimeter() 定義成抽象。這些方法會在它的子類實現。 Circle 同 Rectangle 的實現都一樣,除了他們延伸 GeometricObject 類不一樣。
Circle.java
| 1 | public class Circle extends GeometricObject { | 
Rectangle.java
| 1 | public class Rectangle extends GeometricObject { | 
13.2.1 Why Abstract Methods?
你可以奇怪有什麼好處,在 GeometricObject 類裡去定義 getArea() 同 getPerimeter() 抽象方法。下面的例子顯示了定義 GeometricObject 類的好處,包括 equalArea方法檢查是否兩者面積相等,包括 displayGeometricObject 方法去顯示它們。
TestGeometricObject.java
| 1 | 
 | 
方法 getArea() 同 getPerimeter() 定義在 GeometricOjbect 類度,這些方法會被 Circle 同 Rectangle 類所覆蓋。下面 statement表達式:
| 1 | GeometricObject geoObject1 = new Circle(5); | 
創建一個新的圓形同新的長方形,之後 指向到 assign to 變量 geoObject1 同 geoObject2。這兩個變量都是 GeometricObject 類。
當 調用invoke equalArea(geoObject1, geoObject2), getArea() 方法定義在 Recrangle 類中,個類係用於 object2.Area() 裡,因爲 goeObject2 係一個長方形。`
同樣,當提及 displayGeometricObject(geoObject1) ,Circle 的 getArea() 同 getPerimeter 就會被使用。 displayGeometricObject(geoObject2) 就係 Rectangle 相應的類。JVM 動態地決定哪一個方法被調用,具體係基於真實的對象調用了變一個方法。
Note 注意,如果 getArea 方法沒有被定義在 GeometricObject 類,你就不能定義比較兩個幾何對象是否有相同的面積的 equalArea 方法。你已經見到定義個抽象方法係“共同”類的好處。
13.2.2 Interesting Points about Abstract classes
如下幾點關於抽象類 is worth noting 是值得注意的 :
- 抽象方法不能包含在非抽象類度。如果一個子類屬於抽象父類,未能實現所有的抽象方法,那麼子類必須成抽象。換句話說,在一個非抽象子類,個類延伸於抽象父類,所有的抽象方法必須被實現。也要注意抽象方法不能係靜態。
- 使用 new操作符不能初始化一個抽象類,但係你仍然可以定義佢嘅構造器,某某被調用在子類的構造器上。例如,GeometricObject的構造器會被調用在Circle同Rectangle類裡面。
- 一個類包含抽象方法,一定要係抽象。但係可以定義一個抽象類不包含任何抽象方法。這個抽象類可以作爲定義後面子類的基礎類。
- 一個子類可以覆蓋來自父類類的方法,子類定義個方法成抽象。這樣是非常不正常,但是當實現父類的方法成爲無效,就幾有用。這種情況,子類必須定義成抽象。—— 實體方法被覆蓋成抽象
- 一個子類可以是抽象,even if 即使父類是真實方法。例如,object類是實體方法,但是它的子類GeometricObject是抽象。
- 你不能使用 new操作符從抽象類創建一個實例,但是一個抽象類可以作爲一個抽象類。因此,如下的語句,創建一個數組,數組的元素是GeometricObject類。1 GeometricObject[] objects = new GeometricObject[10]; 
- 你可以創建一個實例, GeometricObject的實例 (Circle),並且assign a to b 將a配給b將 Circle 的引配到數組上。1 object[0] = new Circle(); 
13.2 Check Point p1506
1.
13.3 Case Study: the Abstract Number Class
Number 是一个抽象的父类,是数组容器类 BigInteger 和 BigDecimal 的抽象父类。
Section 10.7 引入了數字 wrapper 封裝器/包裝紙 類。 Section 10.9 引入了 BigInteger 和 BigDecimal 類。這些類有共同的方法 byteValue() , shortValue(), intValue(), longValue(), floatValue() 和 doubleValue() 用於返回 byte, short, int, long, float, 和 double 值,返回的這些值都是來自這些類。這些共同方法是定義入 Number 類,這個類是數字封裝類 BigInteger 和 BigDecimal 的父類。
| 1 | doubleValue() <-- Double | 
個 Number 類是一個抽象父類, Double , Float , Long , Integer , Short , Byte , BigInteger 和 BigDecimal 的父類。
因为 intValue() , longValue() , floatValue 和 doubleValue() 方法不能被实现在 Number 类里,所以這些方法在 Number 類裡面定義成抽象方法。 Number 類因此是抽象方法。byteValue() 同 shortValue() 方法由 intValue() 方法實現:
| 1 | public byte byteValue() { | 
Number 定義成數字類的父類,可以定義多個方法去 perform執行 數字的多個共有操作。下面畀出一個程式去找一列 Number 對象中最大的數字。
| 1 | import java.util.ArrayList; | 
个程序创建了一个数组,一个数组有多个 Number 对象。个数组加上一个 Integer 对象, Double 对象,一个 BigInteger 对象,和一个 BigDecimal 对象到个数组。
调用了 getLargestNumber 方法,个方法返回了最大的数子。个 getLargestNumber 方法返回了 null,如果个列表是 null 或者个列表的大细是0。去找出列表最大的数,个数字通过调用 doubleValue() 方法去比较。个 doubleValue 方法是定义在 Number 类里面,并且在 Number 的实现子类里实现。如果一个数是一个 Integer 对象,那么 Integer 的 doubleValue 会被调用。如果数是 BigDecimal 对象,就调用 BigDecimal 的 doubleValue()。
如果 doubleValue() 方法没有被定义在 Number 类里,你就不可以在多个不同类型的数字中找到最大的数。
13.4 Case Study: Calendar and GregorianCalendar
GregorianCalendar 是一个抽象类 Calendar 的 实体子类。
java.util.Date 的实例代表一个特定的实例,实例是以时间的形式,带有 millisecond 毫秒 的精度。 java.util.Calendar 是一个抽象的基础类,提取日历信息的基础类,例如:月,日,小时,分,同秒。 Calendar 的子类能够实现特定的日历系统,例如 Gregorian calendar,阴历,犹太历。目前,Gregorian 日历的 java.util.GregorianCalendar 是在java被支持的。 add 方法 在 Calendar 类中是抽象的,因为它的实现是基于特定实体日历系统。
13.5 Interface 接口
一个接口像一个类构造器,用于定义多个对象的共同操作。
『在多个方面 in many ways』,一个接口类似抽象类,但是 意图intent 是去规定多个相关或不相关类的共同行为。例如,使用多个接口,去规定对象是否可以comparable 比较 、 可食用的 edible [ˈedəbl] 、 cloneable 复制 。
distinguish sth from sth 比较一个接口和类,Java 使用这样的语法去定义接口:
| 1 | 
 | 
Ex.
| 1 | public interface Edible { | 
一个接口在 Java 中就当作「特殊的类」。每个接口编译成独立的二进制文件,和一般类一样。用接口 『more or less 几乎』 同用抽象类差唔多。例如你用接口当引用變量的数据类。『如同一樣 as with…』抽象類,你不能利用 new 從一個接口創建一個實例。
可以使用 Edible 接口去規定一個對象是否可以食。對象『執行Implement』接口類使用 implements 關鍵字。例如,「雞」類同「水果」類都會執行「可食用」接口。類與接口的關係『be know as 畀認爲係』『接口繼成Interface Inheritance』。因爲接口繼成同類繼成基本都一樣,都統一『refer to指的是』繼成。
接口定義了多個對象的共同行爲。
注意:在接口裡,數據場的『首飾器Modifier』public static void 和方法的首飾器 public abstract 都可以忽略。
下面係相等:
| 1 | public interface T { | 
等於
| 1 | public interface T { | 
雖然 public 首飾器可以在接口裡忽略,但是當那個方法在子類實現,那個方法依然要是 public 。
注意:默認方法 Default Method
Java 8 引入默認接口方法,通過使用 default 關鍵字。一個默認方法提供一個默認實現。一個類執行一個接口,可以使用方法的默認實現,或者通過新執行去覆蓋默認。這個功能使你可以添加新方法到已經存在的接口,利用默認實現,不用重寫存在的多個類執行接口的代碼。
Java 8 又允許『公開靜態方法Public Static Method』存在在接口。公開靜態方法在接口中使用和普通方法一樣目的。
| 1 | public interface A { | 
Check Point
- 不能使用 new A()来创建接口。
- 可以用接口来创建参变量 A x;
- 接口正確?不正確?
 正確不正確1 
 2
 3interface A { 
 void print();
 }1 
 2
 3
 4// interface 裡面的方法是抽象,不帶具體實現{}; 
 interface A {
 void print() {};
 }1 
 2
 3abstract interface A { 
 abstract void print() {};
 }1 
 2
 3
 4// 不能直接 print() 而不表明 void 
 abstract interface A {
 print();
 }1 
 2
 3interface A { 
 default void print() { }
 }1 
 2
 3
 4
 5interface A { 
 static int get() {
 return 0;
 }
 }
- 解釋:- All methods defined in an interface are public. 「所有」接口方法是公共
- When a class implements the interface, the method must be declared public. 實現方法必須是公共
- public 可見性不能忽略
 
13.6 The Comparable Interface
这个 Comparable 接口定义了用来比较多个对象的方法 compareTo 。
假设你希望设计一个通用的方法去找相同类的两个对象中更大的一个。例如两个学生、两个日期、两个圆、两个长方形。所以,两个对象必须是可比较,两个对象的共同行为必须是可比较的。 Java 提供了 Comparable 接口去做呢件事。
| 1 | java.lang.Comparable | 
| 1 | // 比较多个对象的接口,这个定义在 java.lang 里面 | 
compareTo 方法决定了一个有对象 o 的对象的顺序,小于 o 会返回负,等于系0,大于系正数。
Comparable 接口是一个通用接口。當實現這個接口時候,通用类 E 係會被實體類去替代。好多 Java 庫的類都實現了 Comparable 去定義對象中的順序。類如 Byte , Short , Integer , Long , Float , Double , Character , BigInteger , BigDecimal , Calendar , String 同 Date 都實現了 Comparable 接口。
例如 Integer , BigInteger , String , Date 類在 API 中定義了如下:
| 1 | // Integer | 
| 1 | // BigInteger | 
| 1 | // String | 
| 1 | // String | 
你可以使用 compareTo 方法去比較兩個數字,兩個字符等等。
Ex:
| 1 | System.out.println(new BigInteger("2312313").compareTo(new BigInteger("5"))); | 
s 是一個 String 對象,下面都是事實:
| 1 | s instanceof String | 
因爲所有的 Comparable 對象都有 compareTo 方法,所以 java.util.Arrays.sort(Object []) 方法使用 compareTo 方法去比較同排序數組的對象。放落去的 object 對象都是 Comparable 接口的實例。
下面是排序字符串數組的例子:
| 1 | // SortComparableObjects.java | 
| 1 | GZ SZ ZH | 
不能用 sort 方法去排序多個長方形的數組。因爲 Rectange 沒有實現 Comparable 。但是,你可以定義一個新的長方形類,個長方形類係實現了 Comparable 。這個新類的實例是可以比較。
這裏建一個新類 ComparableRectangle :
| 1 | // ComparableRectangle.java | 
ComparableRectangle 延伸 Rectangle 並且實施咗 Comparable 。關鍵字 implements 說明了 ComparableRectangle 繼承 Comparable 接口的所以常量和方法。 compareTo 方法比較了兩個長方形的面積。 ComparableRectangle 的實例也是 Rectangle , GeometricObject , Object 和 Comparable 的實例。
注意:
接口和它的方法的名字都是 斜體 。
java.lang.Comparable
compareTo(o: ComparableRectangle): int
用虛線空心箭頭去指向接口
ComparableRectangle 延伸 Rectangle 和 實施了 Comparable
你可以使用 sort 方法去排序多個 ComparableRectangle 對象的數組:
| 1 | 
 | 
- 一个接口提供通用编程的另外一种形式。
- 如果不使用接口,可能会有些困难去使用通用排序 sort方法去排序那些对象。
- 因为多「重继承係」係好必要去繼承 Comparable同另外一些類,例如Rectangle。
- object類包含了- equal方法,這個方法是被子類所繼承,子類能夠覆蓋。
- 這樣就能夠比較是否多個對象是相等的。
- 假設 Object類包含了compareTo方法,『as由於』compareTo定義在Comparable接口裡,所以sort方法能夠被使用,來比較一組對象。
- 是否一個 compareTo方法應該被包含在Object類裡,仍然在爭論中。
- 因爲 compareTo方法在Object類中沒有定義,如果多個對象都繼承Comparable接口,那麼這個Comparable接口使多個對象能夠相互比較。
- compareTo應該同- equals『一樣 be consistent with』。
- 如果 o1.equals(o2)係真,那麼o1.compareTo(o2) == 0。
- 如果兩個有相同面積,你應該覆蓋 ComparableRectangle的equals方法返回true。
Check Point
- 如果一個類 實施implement 咗 Comparable, 那麼這個類的實例可以有compareTo方法。True!
- public int compareTo(String o)is for- compareTomehtod in the- Stringcl
- 如果他們的共同類,或者共同父類,都有 compareTo,先可以比較,否則 error。
- 要 implements 咗 Comparable接口先可以定義compareTo方法。1 
 2
 3
 4
 5
 6
 7
 8
 9// 實施 Comparable<類名> 
 public class ComparableRectangle extends Rectangle
 implements Comparable<ComparableRectangle> {
 
 
 public int compareTo(ComparableRectangle o) {
 // ...
 }
 }
- A: Person類沒有 implementComparable接口,不可以 sort 。
13.7 The Cloneable Interface
- Cloneable接口 規定了 那個 對象 是 可以 複製的。
- 創建 一個 對象 的 副本 是 『desirable想有的』。
- 你需要使用 clone方法 並且 明白Cloneable接口。
- 雖然 一個 接口 包含 常量 同 抽象方法,但是 Cloneable接口 是 一個特殊例子。
- Cloneable接口定義在- java.lang.Cloneable。
| 1 | package java.lang; | 
- 個接口是空的。
- 接口無內容,『被叫做是個 is referred to as a』marker interface標記接口。
- 一個 標記接口 用來『表示denoet』類『擁有 possess [pəˈzes]』特定的並且想有的屬性。
- 一個 類 實施咗 Cloneable接口 就標記成 可複製。
- Clone()方法已經定義在- Object類中,這個類的對象可以被複製,通過- Clone()方法做到。
- Java 許多類,例如 Date,就實施了Cloneable。
- 因此,這些類都是可 複製的。1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26import java.util.*; 
 public class DateClone {
 public static void main(String[] args) {
 Calendar calendar = new GregorianCalendar(2013, 2, 1);
 Calendar calendar1 = calendar;
 Calendar calendar2 = (Calendar)calendar.clone();
 System.out.println("calendar = calendar1 is " +
 (calendar == calendar1));
 System.out.println("calendar = calendar2 is " +
 (calendar == calendar2));
 System.out.println("calendar.equals(calendar2) is " +
 calendar.equals(calendar2));
 }
 }
 /*
 ⇒ java DateClone
 calendar = calendar1 is true
 calendar = calendar2 is false
 calendar.equals(calendar2) is true
 */
- 『前面的preceding』代碼, Calendar calendar1 = calendar;複製了calendar的地址到calendar1。
- 所以 calendar同calendar1都指向相同的Calendar對象。
- Calendar calendar2 = (Calendar)calendar.clone();創建新的對象,個對象是原來- calendar的副本,並且將新的副本的地址分配給- calendar2。
- 所以 calendar2和calendar是不同的對象,雖然有着相同的內容。
| 1 | // ArrayTest.java | 
- 在上面的代码
- ArrayList<Double> list2 = (ArrayList<Double>)list1.clone();中- list1的副本地址去到- list2。
- list1和- list2是不同的对象,虽然内容相同。
- ArrayList<Double> list3 = list1表明 3 同 1 都是指向相同的对象。
- 所以 1 同 3 都会同时小咗 1.5
| 1 | // List2.java | 
- 数组的 clone()的返回類是同複製前一樣。
- list1.clone()的返回類是- int[],因爲- list1是- int[]。
- 去定義一個自定義的類,這個類實施了 Cloneable接口,這個類必須要『覆蓋override』Object類的clone()方法。
| 1 | // House.java | 
- House類實施了- clone方法,個- clone方法原來定義在- Object類中。
- clone方法的 頭部 定義在- Object類中是這樣- 1 - protected native Object clone() throws CloneNotSupportedException; 
- 個關鍵字 native說明了這個方法不是用 Java 寫的,而是用 JVM 去實施的。
- 個關鍵詞 protected限制了這個方法,只可以被相同Package 包或者 子類 去訪問。
- House類必須覆蓋某些方法,並且改變「修改器modifier」的可見度,這樣那個方法先可以用在任何包中。
- 因爲 clone方法實現在Object類裡,去做對象複製,所以House的clone方法簡單就用super.clone()就可以喇。
- 個 clone方法定義在object類裡,如果個對象不是「可複製的cloneable」,就會跳出CloneNotSupportedException。
- 因爲我們已經做了「錯誤」捕捉在原生,所以無必要在這裡做。
- House類實現了- Comparable接口的- compareTo方法。個方法可以比較兩個對象。
- 你現在可以創建一個對象 House,並且創建副本:1 
 2House house1 = new House(1, 1750.50); 
 House house2 = (House)house1.clone();
- house1同- house2是不同兩個對象,是有着一樣的內容。
- Object類的- Clonel方法复制每个域到目标对象。
- 如果個域係「原始的primitive」類,那麼值就會被複製。
- area(double) 的值會從 house1 複製到 house2 。
- 如果個域是一個對象,那麼域的地址會被複製。
- 例如 whenBuilt是屬於Date,它的地址會複製到house2。
- 儘管 house1==house2是錯的,但是house1.whenBuilt == house2.whenBuilt是真的!
- 這就叫『淺Shallow』複製。不是深複製。如果個域是對象,只會複製地址,不是常量。
- 去執行「深度複製」
- 要改下 clone方法。1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21// House.java 
 public class House implements Cloneable, Comparable<House> {
 ....
 
 public Object clone() {
 try {
 House houseClone = (House)super.clone();
 // clone 目標對象是深度複製,對象裡的對象是淺複製
 houseClone.whenBuilt =
 (java.util.Date)(WhenBuilt.clone());
 return houseClone;
 }
 catch
 return null;
 }
 }
 }
用下面的代碼複製 House 對象:
| 1 | House house1 = new House(1, 750.50); | 
house1.whenBuilt == house2.whenBuilt 就是 false 喇。
- 關於 clone方法 和Cloneable接口有多個問題
- 1st, 爲什麼 Object的clone方法是被「保護的protected」,而不是共用「public」。- 不是每個對象都可以被複製。
- 如果子類生成的對象可以複製,Java 設計師專登強制子類要去「覆蓋Override」。
 
- 2nd, 爲什麼 clone方法不定義在Cloneable接口中?- Java 提供一個原生的方法去執行淺複製。
- 因爲接口的方法是「抽象 abstract」,所以原生方法不能在接口中實現。
- 因此,設計師決定定義並且實現個 clone方法在Object中。
 
- 3rd, 爲什麼 Object類不實現Cloneable接口?- 同1st。
 
- 4th, 如果 House類不實現Cloneable,會發生什麼?- house1.clone()會返回- null。
- 因爲 super.clone()會掟出CloneNotSupportedException。
 
- 5th, 你可以在 House類 實現clone方法,但是又唔用 clone 方法。1 
 2
 3
 4
 5
 6public Object clone() { 
 House houseClone = new House(id, area);
 houseClone.whenBuilt = new Date();
 houseClone.getWhenBuilt().setTime(whenBuilt.getTime());
 return houseClone;
 }
- 在這個例子中, house類不需要實現Cloneable接口。
- 你必須確保所有數據都要正確複製。
- 使用 Object類中clone()方法『減輕你從relieve you from』手動複製收據的工作。
- Object的- clone方法會自動地執行淺複製所以收據域。
Check Point
- 如果一个类不实施 java.lang.Cloneable,類能不能用super.clone()。- 不能用 super.clone()
- Date類實施了- Cloneable
 
- 不能用 
- 如果不在類裡面覆蓋 clone(),因爲java.lang.Object是受保護的,直接使用係個語法錯誤。
- 如果不實施 java.lang.Cloneable係一個run time error,意思就係用時候會返回 null 。
 
- 如果不在類裡面覆蓋 
- ==號驗證兩個是否指向一個對象
- xx.equals.aa驗證內容是否相同
 
- =指向同一個對象
- list.clone()意味着全新的對象
 
- 要用 xxx.clone()1)要實施java.lang.Cloneable2)寫override clone()
13.8 Interface vs. Abstract Classes
- 一個類,可以實施多個接口,只可以延伸一個父類。 
- 一個接口同抽象類「幾乎more or less」相同地使用。 
- 但是接口同抽象類的定義不一樣 - X - 變量 - 構建器Constructor - 方法 - 抽象類 - 冇限制 - Constructor 純粹加入給子類,不能初始化 - 冇限制 - 接口 - 所以變量必須public static final - 沒有constructor,不能初始化 - public abstract instance, public default, and public static 
- Java 只允許類延伸的單獨繼承
- 但是允許多重接口多重延伸
| 1 | public class NewClass extends BaseClass | 
- 一個接口可以通過 extends繼承另一個接口。
- 這個接口叫做 子接口subinterface
| 1 | public interface NewInterface extends Interface1, Interface2, Interface3 { | 
- 一個類實施 NewInterface必須實施來自NewInterface,Interface1,Interface2,Interface3的抽象方法。
- 一個接口可以延伸多個接口,但係不能延伸多個類
- 一個類係可以延伸多個類(父類)和實施多個接口。
- 所以的類共享同一個根,叫 Object類
- 但是,沒有多個接口的唯一根
- 一個接口類的變量可以「參考 Reference」任何實施了這個接口的類所生成的實例。
- 如果一個類實施了一個接口,個接口就如同這個類的父類
- 你能把接口當成數據類,接口可以「投射 cast」接口的變量到它的子類。
- 例如 c是最上層class2的實例,那麼也同時是Object,class1,Interface1_2interface1_1,interface1, …. 的實例。
命名規則
類的名字是名詞。接口的名字一般是形容詞或者名詞。
設計說明
- 抽象類 和 接口 都可以用去規定多個對象的共同行爲。
- 如何決定使用 接口 和 類。
- 通常嚟講,「是一個关系 is-a relationship」清楚地描述父子关系
- 父子关系用多个类来展示
- Gregorian calendar 是一个 calendar
- java.util.GregorianCalendar同- java.util.Calendar的关系通过类继承来「展示 model」。
- 一个弱「是一关系」,说明一个对象「possess拥有」一个特定的属性
- 一个弱「是一关系」,可以通过使用接口来表示。
- String类实施了- Comparable接口,所以所有的字符串系可比较的。
接口更推荐使用,而不是抽象类
因为接口可以定义不相关类的共同父类
接口比一般类更灵活
想想 Animal 類, howToEat 方法定義在 Animal 類中如下。
| 1 | abstract class Animal { | 
動物的子類如下:
| 1 | class Chicken extends Animal { | 
| 1 | class Duck extends Animal { | 
「inheritance hierarchy 繼承 層次體系」、「polymorphism多形態性」使你可以有個 Animal 變量指向 Chicken 對象和 Duck 對象的地址。
| 1 | public static void main(String[] args) { | 
基於具體的對象,個對象提及的方法,JVM判斷使用來自哪個對象的 howToEat 。
你可以定義 Animal 的子類。
但是,有個限制。子類必須其它動物。
另外一個問題出現,如果一個動物是不能食,是不能延伸 Animal 類。
接口不會這些問題。
接口有更多靈活性,因爲你不需要成個接口內容連結到特定類。
你可以定義接口 howToEat() 方法,讓它服務多類。
例如:「Edible interface 可食接口」與 「Chicken Class 雞類」
| 1 | // DesignDemo | 
定義一個類,類「represent 代表」可食對象
簡單將類實施 Edible 接口
類現在是 Edible 類的子類, Edible 對象可以用 howToEat 方法。
Check Point
- 接口是編譯成另外獨立的二進制代碼
- 接口不能有靜態方法
- 接口可以延伸多個接口
- 接口不能延伸抽象類
- 接口可以有默認方法
 
- 接口
13.9 Case Study: The Rational有理由的 Class
這個部分顯示了如何設計一個有理類,個類能表達同處理有理數。
一個有理數有「numerator分子」和「denominator分母」,寫成 a/b
有理數分母不能爲0,但係0作爲分子就可以。
整數 1 等於 i/1。
有理數用在準確的計算當中。
意味着, 1/3 = 0.3333333 就不能准确地表达,以 double 或者 float 浮点格式都不能。
去获得准确的结果,我哋必须使用有理数。
Java 提供浮點数据类,但是沒有有理數。
這個部分顯示了如何設計一個類,去表達有理數。
因爲有理數同 Integer 和 float-point 有許多共同特點,
並且 Number 是數字包裹器的根類,比較合適就是定義 Rational 作爲 Number 的子類。
因爲有理數是可以比較的,所以 Rational 類應該實施 Comparable 接口。
| 1 | java.lang.Number <-----------------| Rational | | 
doubleValue() 定義在 java.lang.Number 裡面,並且在 Rational 中重寫。
如果字符串「is concatenated with 接上」一個對象,而且通過 + 號,這個對象的字符串表達式 toString() 就會被用上。
所以 r1 + " + " + r2 + " = " r1.add(r2) 等同於 r1.toString() + " + " + r2.toString() + " = " r1.add(r2).toString()
p1580
- is intended for 是专供
- particular 专门的
p1581
- immutable 不可改变的
- limitation 局限 # 区别limit
- overflow 溢jat出
check point
#2 #3
| 1 | Rational r1 = new Rational(-2, 6); // Rational 有實現 compareTo方法 | 
#4
| 1 | if ((this.subtract((Rational)(other))).getNumerator() == 0) | 
其實就係
| 1 | return ((this.subtract((Rational)(other))).getNumerator() == 0); | 
用 conditional operator 簡化:
| 1 | if (this.subtract(o).getNumerator() > 0) | 
5
- revise 修正
13.10 Class-Design Guidelines 類設計說明
1585
- sound 可靠的 adj
- cohesion 結合 凝聚性
- entity 實體
- coherent 有調理的
- separate 獨立的 adj
- synchronize 同步v
 p1587
- as is the case 一直都係
- encapsulate date field 封裝 數據 域
 p1588
- achieve 實現
- clarity 明確性
- contract 合約
- incorporate 包含
- impose 推行
p1589
- intuitively 直观地 [ɪnˈtjuːɪtɪvli]
- derive 取得
- depend on 基於
1590
- is dependent on 依賴於
錯誤
| 1 | 
 | 
應該
| 1 | private class SomeThing { | 
1591
- integral 必要的
- mistakenly 錯誤地
- overlook 忽略v
- is independent of 獨立於
1592
- aggregation 集合、總量
- possesse 有
1595
- construct 概念、觀念
- in many ways 在好多方面