1. 程式人生 > >哈工大 軟件構造課程 考點復習總結(第三章)

哈工大 軟件構造課程 考點復習總結(第三章)

rac ima 編譯錯誤 boolean sub sign opera dispatch 規模

  1. 數據類型

Primitive types 基本數據類型(8種)

  1. Object types 對象數據類型(reference types 引用數據類型)

Short、int 、long、float、double、boolean、char、byte

如:String、BigInteger

只有值,沒有ID(無法與其他值區分),不能賦值為null

immutable

有值,也有ID;

部分mutable,部分immutable

在棧中分配內存,代價低

在堆中分配內存,代價高

  1. 靜態類型檢查&動態類型檢查

靜態類型檢查

動態類型檢查

(靜態類型語言 如java)

(動態類型語言 如python)

提高程序的正確性和健壯性

關於"類型"的檢查,不考慮值(不知道運行時會是什麽值)

關於"值"的檢查

  1. Mutable & Immutable

    Immutable 不可變數據類型

    Immutable 不可變數據類型

    優點

    優點:安全

    優點:最少化拷貝以提高效率獲得更好的性能,適合於在多個模塊之間共享數據

    缺點

    缺點:頻繁修改產生大量臨時拷貝,需要垃圾回收·

    缺點:不安全

    其他

    一旦被創建,其值不能改變

    對於引用類型,加final限制不能改變引用

    安全地使用可變類型:局部變量(不涉及共享,且只有一個引用)

    如果有多個引用(別名),不安全

    Defensively copy 防禦式拷貝:返回全新的對象

    盡可能用immutable!

  1. 技術分享圖片

    Snapshot Diagram 畫法:

  2. 基本類型:單獨一個常量

    引用類型:圈住!

  3. 技術分享圖片重分配:

    不可變類型(用雙線橢圓),修改引用

    可變類型:修改值

  4. 技術分享圖片引用:

    可變引用:單線箭頭

    不可變引用:雙線箭頭

  1. Specification

  1. 作用
    1. 規約可以隔離"變化",無需通知客戶端
    2. 規約可以提高代碼效率
    3. 規約扮演"防火墻"角色
    4. 解耦,不需要了解具體實現
  2. 內容:只講"能做什麽",而不講"怎麽實現"
  3. Behavior equivalence 行為等價性

    是否可以相互替換

    1. 站在客戶端的視角看行為等價性,不同的行為,對用戶來說(根據用戶需求)可能等價!
    2. 根據規約判斷行為等價,兩個方法符合同一個規約,則等價
  4. 規約的結構:
    1. Pre-condition
    2. Post-condition
    3. Exceptional behavior 異常行為,如果違背了前置條件,會發生什麽
  5. 規約的強度與替換

    Spec變強:更放松的前置條件(前置條件更弱)+更嚴格的後置條件(後置條件你更強),

    兩條件同時變強或變弱則無法比較。

    若規約強度S2>=S1,則可以用S2替換S1。

  6. deterministic spec & undetermined spec 確定的規約和欠定的規約
    1. 確定的規約:給定一個滿足前置條件的輸入,其輸出唯一、明確
    2. 欠定的規約:同一個輸入可以有多個輸出(多次執行輸出可能不同)
  7. Declarative spec & operational spec 聲明式規約和操作式規約
    1. 操作式規約:如 偽代碼
    2. 聲明式規約:沒有內部實現的描述,只有"初-終"狀態

    聲明式規約更有價值!

    內部實現的細節不在規約裏呈現,而放在代碼實現體內部註釋裏呈現。

  8. 技術分享圖片Diagraming specification

    規約定義一個區域,該區域包含所有可能的實現方式。

    空間中的每個點表示一種方法的實現。

    對於某個具體實現,若滿足規約,則落在其區域內。

    更強的規約表達為更小的區域。

  9. Quality of specification 規約質量
    1. 內聚性:spec描述的功能應單一、簡單、易理解
    2. 運行結果信息豐富(可能的改變,以及返回值等),不能讓客戶端產生理解上的歧義
    3. 足夠強(如postcondition中充分闡述各種情況)
    4. 適當弱(太強的規約,在很多特殊情況下難以達到)
    5. 在規約裏使用抽象類型(在java中,經常使用interface,如Map、List,而不是HashMap、ArrayList),可以給方法的實現體和客戶端更大的自由度
    6. 使用前置條件和後置條件?

      客戶端不喜歡太強的pre-condition,不滿足precondition的輸入會導致失敗

      So:不限定太強的precondition,而在postcondition中拋出異常:輸入不合法,

      fail fast,避免fail大規模擴散

是否使用前置條件取決於:

  1. check(檢查參數合法性)的代價
  2. 方法的使用範圍:
    1. 如果只在類內部使用(private),則可以不使用precondition,在使用該方法的各個位置進行check
    2. 如果在其他地方使用(public),則必須使用precondition,若client不滿足則拋出異常

  1. Pre-condition and post-condition 前置條件和後置條件

Pre-condition 前置條件(requires)

Post-condition 後置條件(effects)

@param

@return @throws

對客戶端的約束

在使用方法時必須滿足的條件

對開發者的約束

方法結束時必須滿足的條件

契約:如果前置條件滿足了,後置條件必須滿足

除非在後置條件中聲明,否則方法內部不應該改變輸入參數。

盡量不設計mutating的spec,否則容易引發bugs。

盡量避免使用mutable對象。

避免使用可變的全局變量。

ADT

  1. ADT及其四種操作

    抽象類型:強調"作用於數據上的操作",程序員和client無需關心數據如何具體存儲,只需設計/使用操作即可。

    ADT由操作定義,與其內部實現無關。

    可變數據類型:提供了可改變其內部數據值的操作;

    不可變數據類型:其操作不改變內部值,而構造新的對象。(沒有mutators

ADT操作分類:

  1. Creators 構造器:

    不利用該類型對象產生一個新的對象

    可能實現為構造函數或靜態函數(factory method)

  2. Producers 生產器:

    用已有該類型對象產生新對象

    如string.concat()(連接兩個字符串,產生一個新的字符串)

  3. Observers 觀察器

    如list.size()返回int(不同於原類型)

  4. Mutators 變值器(改變對象屬性的方法)

    通常範圍void,如果返回void,則必然意味著它改變了某些對象的內部狀態

    也可能範圍非空類型(如容器類的put、add方法)

    1. Representation Independence 表示獨立性

表示獨立性:client使用ADT時無需考慮其內部如何實現,ADT內部表現的變化不應該影響外部spec和客戶端。

  1. Representation exposure 表示泄漏

如client能直接接觸類成員變量。

表示泄漏影響表示不變量,也影響表示獨立性:無法在不影響客戶端的情況下改變其內部表示。

避免方法:private、final、defensive copy

  1. Invariants 不變量 & Representation Invariant 表示不變量

ADT應保持其不變量在任何時候總是true;

ADT負責其不變量,與client的任何行為無關。

作用:保持程序的"正確性",容易發現錯誤。

  1. Abstraction Function 抽象函數

技術分享圖片

表示空間R

抽象空間A

值的實際實現本質

抽象表示(client看到和使用的值)

ADT實現者關註表示空間R

用戶關註抽象空間A

R到A的映射

一定是滿射:A中元素總有R中具體的實現

未必是單射:A中一個元素在R中可能有多重實現方式

未必是雙射:R中表示不符合A中需求(如圖中"abbc")

抽象函數AF:R和A之間映射關系的函數

AF:R->A

對於RI :R-> Boolean

RI:某個具體的"表示"是否合法;表示值的一個子集,包含所有合法的表示值;一個條件,描述了什麽是"合法"表示值。

  1. 技術分享圖片

    Documenting AF 、RI、Safety from Rep Exposure

選擇某種特定的表示方式R

進而指定某個子集是"合法"的(RI)

並為該子集中的每個值做出"解釋"(AF)

即 如何映射

Safety from Rep Exposure

證明代碼並未對外泄露其內部表示

技術分享圖片

保證不變量為true,不變量:

  1. 通過creators和producers創建
  2. 受mutators和observers保護
  3. 無表示泄漏發生

OOP

  1. Interface 接口

接口的成員變量默認用final關鍵字修飾,故必須有初值,可用public,default修飾,可用static修飾。

接口的方法只能被public、default、abstract、static、strictfp(嚴格浮點運算)修飾。

  1. Inheritance、override 繼承和重寫

Strict inheritance 嚴格繼承:子類只能添加新方法,無法重寫超類(父類)中的方法(final限制)。

考慮final修飾類、方法、屬性時的不同作用。

Override 方法:具有一致的signature,復用的基本機制。

  1. Polymorphism ,subtyping and overloading 多態,子類型化,重載

三種多態:

  1. Ad hoc polymorphism (特殊多態)

    用於function overloading(功能重載),即重載

  2. Parametric polymorphism (參數化多態)

    泛型

  3. Subtyping (subtype polymorphism / inclusion polymorphism )(子類型多態、包含多態)

  1. Overloading 重載
    1. 重載條件:
      1. 方法名相同
      2. 參數列表不同,即參數類型、個數、類型順序至少有一項不相同
      3. 返回值類型可以不同
      4. 方法的修飾符可以不同
      5. 可以拋出不同的異常
      6. 可以在類內重載,也可以在子類重載
    2. 重載是一種靜態多態,靜態類型檢查

      (static dispatch 靜態分派)並在編譯階段決定具體執行哪個方法(即對方法的調用取決於編譯時聲明的引用的類型)

      重寫(dynamic dispatch 動態分派)則進行動態類型檢查,根據運行時堆中的實例類型選擇方法。

  2. Generic 泛型
    1. 通配符 <?> :只有使用泛型的時候出現,不能在定義中出現。
    2. 技術分享圖片類型擦除:編譯後、運行時類型擦除

      List<Integer> -> List

      註意可能引起重載編譯錯誤。

      技術分享圖片運行時不能用 instanceof 檢查泛型。

    3. 不能創建泛型數組

      不能用在靜態變量

      不能創建對象(不能new)

  3. Subtypes

    超類的子類型,如:ArrayList和LinkedList是List的子類型。

    子類型的規約不能弱化超類型的規約。

    1. 子類型多態:不同類型的對象可以統一處理而無需區分(不加區分地調用同樣的方法等),從而隔離變化
    2. LSP(Liskov Substitution Principle) 如果S是T的子類型,那麽T的對象可以被S的對象替換。
    3. Type casting 類型轉換

      避免向下類型轉換。

  4. Dispatch 分派

Static dispatch 靜態分派

Dynamic dispatch 動態分派

將調用的名字與實際方法的名字聯系起來(可能有多個)

決定具體執行哪一個操作

重載,在編譯階段即可確定執行哪個具體操作

重寫,在運行時決定

Early/static binding

Lade/dynamic binding

綁定static、private、final方法時發生

重寫父類子類的同樣方法

技術分享圖片

技術分享圖片

  1. equals()

  1. 引用等價性 ==

    比較內存地址ID

    用於比較基本數據類型

  2. 對象等價性 equals()

    驗證正確性:reflexive 自反性、symmetric 對稱性、transitive 傳遞性、非空(a.equals(null) return false)

    1. hashCode()

      等價的對象必須有相同的hashCode

      Rule:重寫equals時重寫hashcode

    1. Equality of Mutable Types 可變對象的等價性

Observational equality 觀察等價性

Behavioral equality 行為等價性

在不改變狀態的形況下,兩個mutable看起來是否一致

調用對象的任何方法都展示出一致的結果

調用observer,producer,creator

調用任何方法,包括mutator

當前情況下,看起來(如成員變量)相同

經過改變後,依然相同(只是別名引用)

對不可變類型,觀察等價性和行為等價性完全等價。

對可變類型,往往傾向於實現嚴格的觀察等價性。(但有時觀察等價性可能導致bug,甚至破壞RI)

對可變類型,應當實現行為等價性,即只有指向內從空間中同樣的objects才相等(即equals比較引用,如==而hashcode把引用映射為一個值)。

所以對可變類型,無需重寫equals和hashcode,直接繼承object。(比較引用)

若一定要判斷兩個可變對象是否一致,最好定義一個新的方法。

哈工大 軟件構造課程 考點復習總結(第三章)