首頁 Java java教程 Java中的繼承實例分析

Java中的繼承實例分析

Apr 20, 2023 pm 05:19 PM
java

  介面(Interface)和類別(Class)?
  一次,我參加一個Java使用者群組的會議。在會議中,Jams Gosling(Java之父)做發起人講話。在那令人難忘的Q&A部分中,有人問他:「如果你重新構造Java,你想改變什麼?」。 「我想拋棄classes」他回答。在笑聲平息後,它解釋說,真正的問題不是由於class本身,而是實現繼承(extends) 關係。介面繼承(implements關係)是更好的。你應該盡可能的避免實現繼承。
  失去了彈性
  為什麼你應該避免實現繼承呢?第一個問題是明確的使用具體類別名稱將你固定到特定的實現,為底層的改變增加了不必要的困難。
  在目前的敏捷程式設計方法中,核心是並行的設計和開發的概念。在你詳細設計程式前,你開始程式設計。這個技術不同於傳統方法的形式----傳統的方式是設計應該在編碼開始前完成----但是許多成功的項目已經證明你能夠更快速的開發高質量代碼,相對於傳統的按部就班的方法。但是在並行開發的核心是主張靈活性。你必須以某一種方式寫你的程式碼以至於最新發現的需求能夠盡可能沒有痛苦的合併到現有的程式碼中。
  勝於實現你也許需要的特徵,你只需實現你明確需要的特徵,而且適度的對變化的包容。如果你沒有這種靈活,並行的開發,那簡直不可能。

  對於Inteface的程式設計是靈活結構的核心。為了說明為什麼,讓我們來看看當使用它們的時候,會發生什麼。考慮下面的程式碼:

  f()
  {
  LinkedList list = new LinkedList();
  //...
  g(#list );##  //...
  g(#list );##  //...
  g(#list );##  }
##  g( LinkedList list )
  {
  list.add( ... );
  g2( list )
  }
##  被提出,以至於這個LinkedList不能夠解決。你需要用HashSet來取代它。在已有程式碼中,變化不能夠局部化,因為你不僅需要修改f()也需要修改g()(它帶有LinkedList參數),並且還有g()把列表傳遞給的任何程式碼。像下面這樣重寫程式碼:

  f()
  {
  Collection list = new LinkedList();
  //...
  g( list );
}

  g( Collection list )
  {
  list.add( ... );
  g2( list )
  }

  這樣修正成list hash,可能只是簡單的用new HashSet()取代new LinkedList()。就這樣。沒有其他的需要修改的地方。

  作為另一個例子,比較下面兩段程式碼:

  f()
  {
  Collection c = new HashSet();
  //...
  g( c );
  }

  g( Collection c )
  {
  for( Iterator i = c.iterator(); i.has_Next()  for( Iterator i = c.iterator(); i.has_with) 〬)#do〭withthing。 ( i.next() );
  }

  和

  f2()
  {
  Collection c = new HashSet();##   Collection c = new HashSet();##    /##/#. .
  g2( c.iterator() );
  }

  g2( Iterator i )
  {
  while( i.hasNext(#  {
  while( i.hasNext(#  {
  while( i.hasNext(#  {
  』_ next() );
  }
  g2()方法現在能夠遍歷Collection的派生,就像你能夠從Map中得到的鍵值對。事實上,你能夠寫iterator,它產生數據,取代遍歷一個Collection。你能夠寫iterator,它從測試的框架或文件中得到資訊。這會有巨大的彈性。

  
耦合  對於實現繼承,一個更關鍵的問題是耦合---令人煩躁的依賴,就是那種程式的一部分對於另一部分的依賴。全域變數提供經典的例子,證明為什麼強耦合會造成麻煩。例如,如果你改變全域變數的類型,那麼所有用到這個變數的函數也許都被影響,所以所有這些程式碼都要被檢查,變更和重新測試。而且,所有用到這個變數的函數都透過這個變數相互耦合。也就是,如果一個變數值在難以使用的時候被改變,一個函數也許就不正確的影響了另一個函數的行為。這個問題顯著的隱藏於多執行緒的程式。
  身為一個設計者,你應該努力最小化耦合關係。你不能一併消除耦合,因為從一個類別的物件到另一個類別的物件的方法呼叫是一個鬆散耦合的形式。你不可能有一個程序,它沒有任何的耦合。然而,你能夠透過遵守OO規則,最小化一定的耦合(最重要的是,一個物件的實作應該完全隱藏於使用他的物件)。例如,一個物件的實例變數(不是常數的成員域),應該總是private。我意思是某段時期的,無例外的,不斷的。 (你能夠偶爾有效地使用protected方法,但是protected實例變數是可憎的事)同樣的原因你應該不用get/set函數---他們對於是一個域公用只是使人感到過於復雜的方式(儘管返回修飾的物件而不是基本類型值的存取函數是在某些情況下是由原因的,那種情況下,傳回的物件類別是一個在設計時的關鍵抽象)。

  這裡,我不是書生氣。在我自己的工作中,我發現一個直接的相互關係在我OO方法的嚴格之間,快速程式碼開發和容易的程式碼實作。無論何時我違反中心的OO原則,如實現隱藏,我結果重寫那個程式碼(一般因為程式碼是不可調試的)。我沒有時間重寫程式碼,所以我遵循那些規則。我關心的完全實用?我對乾淨的原因沒有興趣。

   脆弱的基底類別問題

  現在,讓我們應用耦合的概念到繼承。在一個用extends的繼承實作系統中,衍生類別是非常緊密的和基底類別耦合,當且這種緊密的連接是不期望的。設計者已經應用了綽號「脆弱的基類問題」來描述這個行為。基礎類別被認為是脆弱的是,因為你在看起來安全的情況下修改基類,但是當從衍生類別繼承時,新的行為也許會造成衍生類別出現功能失調。你不能透過簡單的在隔離下檢查基底類別的方法來分辨基底類別的變化是安全的;而是你也必須看(和測試)所有衍生類別。而且,你必須檢查所有的程式碼,它們也用在基底類別和衍生類別物件中,因為這個程式碼也許被新的行為所打破。一個對於基礎類別的簡單變更可能導致整個程式不可操作。

  讓我們一起檢查脆弱的基底類別和基底類別耦合的問題。下面的類別extends了Java的ArrayList類別去使它像一個stack來運轉:

  class Stack extends ArrayList
  {
#  private int stack_pointer = 0;##\
  private int stack_pointer = 0;##oid
#。 ( Object article )
  {
  add( stack_pointer , article );
  }

#  public Object pop()
 point  #  }

  public void push_many( Object[] articles )
  {
  for( int i = 0; i < articles.length; i )
artic ;
  }
  }

  甚至一個像這樣簡單的類別也有問題。思考當一個使用者平衡繼承和用ArrayList的clear()方法去彈出堆疊時:

  Stack a_stack = new Stack();
  a_stack.push("1");
  a_stack. push("2");
  a_stack.clear();

  這個程式碼成功編譯,但是因為基底類別不知道關於stack指標堆疊的情況,這個stack物件目前在一個未定義的狀態。下一個對於push()呼叫把新的項目放入索引2的位置。 (stack_pointer的目前值),所以stack有效地有三個元素-下邊兩個是垃圾。 (Java的stack類別正是有這個問題,不要用它).

  對這個令人討厭的繼承的方法問題的解決辦法是為Stack覆蓋所有的ArrayList方法,那能夠修改數組的狀態,所以覆蓋正確的操作Stack指針或拋出例外。 (removeRange()方法對於拋出一個例外一個好的候選方法)。

  這個方法有兩個缺點。第一,如果你覆寫了所有的東西,這個基底類別應該真正的是一個interface,而不是一個class。如果你不用任何繼承方法,在實作繼承中就沒有這一點。第二,更重要的是,你不能讓一個stack支援所有的ArrayList方法。例如,令人煩惱的removeRange()沒有什麼作用。唯一實現無用方法的合理的途徑是使它拋出一個例外,因為它應該永遠不會被呼叫。這個方法有效的把編譯錯誤變成運行錯誤。不好的方法是,如果方法只是不定義,編譯器會輸出一個方法找不到的錯誤。如果方法存在,但是拋出一個例外,你只有在程式真正的運行時,你才能夠發現呼叫錯誤。

  對於這個基底類別問題的一個更好的解決方案是封裝資料結構代替用繼承。這是新的、改進的Stack的版本:
  class Stack
  {
  private int stack_pointer = 0;
  private ArrayList the_data = new ArList();
  private ArrayList the_data = new ArList();
  private ArrayList the_data = new ArList();
 有用Hoid  ( );
  }

  public void push_many( Object[] articles )
  {
  for( int i = 0; i < o.length; i#  for( int i = 0; i < o.length; i )##  [i] );
  }
  }

  到現在為止,一直都不錯,但是考慮脆弱的基類問題,我們說你想要在stack創建一個變量, 用它在一段週期內追蹤最大的堆疊尺寸。一個可能的實作也許像下面這樣:

  class Monitorable_stack extends Stack
  {
  private int high_water_mark = 0;
  article )
  {
  if( current_size > high_water_mark )
   high_water_mark = current_size;
      
  {
  --current_size;
  return super.pop();
  }

#  public int maximum_size_far

  public int maximum_size_far_
##  #  }
  這個新類別運作的很好,至少是一段時間。不幸的是,這個程式碼發掘了一個事實,push_many()透過呼叫push()來運作。首先,這個細節看起來不是一個壞的選擇。它簡化了程式碼,而且你能夠得到push()的衍生類別版本,甚至當Monitorable_stack透過Stack的參考來存取的時候,以至於high_water_mark能夠正確的更新。

以上是Java中的繼承實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1653
14
CakePHP 教程
1413
52
Laravel 教程
1306
25
PHP教程
1251
29
C# 教程
1224
24
突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

See all articles