本節講學習ADT的具體實現技術:OOPjava
【對象】編程
【類】數組
【接口】安全
一個接口的實例:編程語言
/** MyString represents an immutable sequence of characters. */ public interface MyString { // We'll skip this creator operation for now // /** @param b a boolean value // * @return string representation of b, either "true" or "false" */ // public static MyString valueOf(boolean b) { ... } /** @return number of characters in this string */ public int length(); /** @param i character position (requires 0 <= i < string length) * @return character at position i */ public char charAt(int i); /** Get the substring between start (inclusive) and end (exclusive). * @param start starting index * @param end ending index. Requires 0 <= start <= end <= string length. * @return string consisting of charAt(start)...charAt(end-1) */ public MyString substring(int start, int end); }
一種實現:ide
1 public class FastMyString implements MyString { 2 3 private char[] a; 4 private int start; 5 private int end; 6 7 /** Create a string representation of b, either "true" or "false". 8 * @param b a boolean value */ 9 public FastMyString(boolean b) { 10 a = b ? new char[] { 't', 'r', 'u', 'e' } 11 : new char[] { 'f', 'a', 'l', 's', 'e' }; 12 start = 0; 13 end = a.length; 14 } 15 16 // private constructor, used internally by producer operations. 17 private FastMyString(char[] a, int start, int end) { 18 this.a = a; 19 this.start = start; 20 this.end = end; 21 } 22 23 @Override public int length() { return end - start; } 24 25 @Override public char charAt(int i) { return a[start + i]; } 26 27 @Override public MyString substring(int start, int end) { 28 return new FastMyString(this.a, this.start + start, this.end + end); 29 } 30 }
客戶端如何使用此ADT?這是一個例子:函數
MyString s = new FastMyString(true); System.out.println("The first character is: " + s.charAt(0));
但其中有問題,這麼實現接口打破了抽象邊界,接口定義中沒有包含constructor,也沒法保證全部實現類中都包含了一樣名字的constructor。 故而,客戶端須要知道該接口的某個具體實現類的名字。由於Java中的接口不能包含構造函數,因此它們必須直接調用其中一個具體類的構造函數。該構造函數的規範不會出如今接口的任何地方,因此沒有任何靜態的保證,即不一樣的實現甚至會提供相同的構造函數。性能
在Java 8中,咱們能夠用valueof的靜態工廠方法 代替構造器。學習
public interface MyString { /** @param b a boolean value * @return string representation of b, either "true" or "false" */ public static MyString valueOf(boolean b) { return new FastMyString(true); } // ...
此時,客戶端使用ADT就不會破壞抽象邊界:ui
MyString s = MyString.valueOf(true); System.out.println("The first character is: " + s.charAt(0));
總結:接口的好處
Safe from bugs
ADT是由其操做定義的,接口就是這樣作的。
當客戶端使用接口類型時,靜態檢查確保他們只使用由接口定義的方法。
若是實現類公開其餘方法,或者更糟糕的是,具備可見的表示,客戶端不會意外地看到或依賴它們。
當咱們有一個數據類型的多個實現時,接口提供方法簽名的靜態檢查。
Easy to understand
客戶和維護人員確切知道在哪裏查找ADT的規約。
因爲接口不包含實例字段或實例方法的實現,所以更容易將實現的細節保留在規範以外。
Ready for change
經過添加實現接口的類,咱們能夠輕鬆地添加新類型的實現。
若是咱們避免使用靜態工廠方法的構造函數,客戶端將只能看到該接口。
這意味着咱們能夠切換客戶端正在使用的實現類,而無需更改其代碼。
【抽象類】
【封裝】
public class Person { private String name; private int age; }
1 public class Person{ 2 private String name; 3 private int age; 4 5 public int getAge(){ 6 return age; 7 } 8 9 public String getName(){ 10 return name; 11 } 12 13 public void setAge(int age){ 14 this.age = age; 15 } 16 17 public void setName(String name){ 18 this.name = name; 19 } 20 }
採用 this 關鍵字是爲了解決實例變量(private String name)和局部變量(setName(String name)中的name變量)之間發生的同名的衝突。
【繼承與重寫】
super
調用超類方法。例子以下:
1 class Animal{ 2 public void move(){ 3 System.out.println("動物能夠移動"); 4 } 5 } 6 7 class Dog extends Animal{ 8 public void move(){ 9 super.move(); // 應用super類的方法 10 System.out.println("狗能夠跑和走"); 11 } 12 } 13 14 public class TestDog{ 15 public static void main(String args[]){ 16 17 Animal b = new Dog(); // Dog 對象 18 b.move(); //執行 Dog類的方法 19 20 } 21 }
【多態與重載】
1 public class OverloadExample { 2 public static void main(String args[]) { 3 System.out.println(add("C","D")); 4 System.out.println(add("C","D","E")); 5 System.out.println(add(2,3)); 6 } 7 public static String add(String c, String d) { 8 return c.concat(d); 9 } 10 public static String add(String c, String d, String e){ 11 return c.concat(d).concat(e); 12 } 13 public static int add(int a, int b) { 14 return a+b; 15 } 16 }
public class Pair<E> { private final E first, second; public Pair(E first, E second) { this.first = first; this.second = second; } public E first() { return first; } public E second() { return second; } } Client: Pair<String> p = new Pair<>("Hello", "world"); String result = p.first();
子類型多態
子類型的規約不能弱化超類型的規約。
子類型多態:不一樣類型的對象能夠統一的處理而無需區分,從而隔離了「變化」。
【重寫與重載的區別】
區別點 | 重載方法 | 重寫方法 |
---|---|---|
參數列表 | 必須修改 | 必定不能修改 |
返回類型 | 能夠修改 | 必定不能修改 |
異常 | 能夠修改 | 能夠減小或刪除,必定不能拋出新的或者更廣的異常 |
訪問 | 能夠修改 | 必定不能作更嚴格的限制(能夠下降限制) |
調用狀況 | 引用類型決定選擇哪一個重載版本(基於聲明的參數類型)。 在編譯時發生。 | 對象類型(換句話說,堆上實際實例的類型)決定選擇哪一種方法在運行時發生。 |
方法的重寫(Overriding)和重載(Overloading)是java多態性的不一樣表現,重寫是父類與子類之間多態性的一種表現,重載能夠理解成多態的具體表現形式。
【泛型】(參數多態)
ublic interface Set<E> { /** * Test for membership. * @param e an element * @return true iff this set contains e */ public boolean contains(E e); /** * Modifies this set by adding e to the set. * @param e element to add */ public void add(E e); } public class CharSet1 implements Set<Character> { private String s = ""; @Override public boolean contains(Character e) { checkRep(); return s.indexOf(e) != -1; } @Override public void add(Character e) { if (!contains(e)) s += e; checkRep(); } }
public interface Set<E> { // ... public class HashSet<E> implements Set<E> { // ...
Map<E, F>, Map<String, Integer>
List<?> list = new ArrayList<String>();
Pair<String>[] foo = new Pair<String>[42]; // won't compile
toString()
,hashCode()
,clone()
,equals()
等。