內部類與內部類Java 中的子類
一、簡介
在本教程中,我們將仔細研究 Java 中的兩個重要結構:內部類和子類。它們是用 Java 編寫類的兩種不同方式,並且用法也不同。
2.Java中的子類
面向對象編程的核心原則之一是繼承。它引入了一個類繼承另一個類(父類)的屬性和行為的想法。繼承和子類的使用提高了代碼的可重用性和層次結構中類的組織。
子類定義與其父類的“is-a”關係,即子類的對像是其父類的對象。這支持多態性的概念,並允許我們通過公共父類處理不同子類的實例,從而促進更通用的編碼。
定義和使用子類還允許我們創建高度專業化的類,這些類可以擴展和覆蓋其父類的特定功能。這支持 SOLID 原則的開閉原則。
3.Java中的內部類
內部類是 Java 中嵌套類的一種形式,在另一個宿主類的邊界內定義。
Java中的內部類有很多種類型,例如嵌套內部類、靜態內部類、方法本地內部類和匿名內部類。雖然每個內部類彼此略有不同,但內部類的中心思想保持不變。這種安排促進了更緊密的封裝並增強了可讀性,因為該內部類在外部類之外沒有其他用途。因此,這種方法提供了一種改進的類分組方法。
內部類始終與外部類保留在同一文件中。除非我們定義了靜態內部類,否則我們無法在不使用外部類實例的情況下實例化內部類。
4. 子類的需要
在本節中,我們將以通知系統為例來演示子類的屬性。通知模塊中的主要組件是Notifier
類,其目的是發送通知:
public class Notifier {
void notify(Message e) {
// Implementation details of sending the message via email
}
}
Message
類封裝了要傳遞的消息的相關內容。
這個Notifier
類太通用了,沒有定義發送不同類型通知的方法。如果我們的系統只能發送一封電子郵件,那麼這個類就可以正常工作。然而,如果我們想將系統的功能擴展到其他通信渠道,例如短信或電話,我們就達到了極限。
實現此目的的方法之一是在此類中定義多個方法,並為每個方法分配通過特定通道進行通知的責任:
public class Notifier {
void notifyViaEmail(Message e) {
// Implementation details of sending the message via email
}
void notifyViaText(Message e) {
// Implementation details of sending the message via text message
}
void notifyViaCall(Message e) {
// Implementation details of making an outgoing call
}
}
這種方法有太多的缺點:
-
Notifier
類有太多職責並且對不同渠道了解太多 - 每增加一個新頻道,班級規模就會成倍增加
- 該設計沒有考慮某些通信渠道本身的不同實現要求,例如RCS、SMS/MMS
為了解決這些問題,我們藉助面向對象編程中的繼承範式,提出了重構。
我們將Notifier
指定為系統中的基類或父類,並使其abstract
:
public abstract class Notifier {
abstract void notify(Message e);
}
通過此更改, Notifier
類不知道通知邏輯或通道。它依賴其子類來定義行為。我們所有的通信渠道都與Notifier,
表現出is-a
關係,例如EmailNotifier
是一個Notifier
:
public class EmailNotifier extends Notifier {
@Override
void notify(Message e) {
// Provide email specific implementation here
}
}
public class TextMessageNotifier extends Notifier {
@Override
void notify(Message e) {
// Provide text message specific implementation here
}
}
public class CallNotifier extends Notifier {
@Override
void notify(Message e) {
// Provide phone call specific implementation here
}
}
通過這種方法,我們可以根據需要將我們的系統擴展到任意數量的特定於渠道的實現。我們可以根據需要定義具體子類實現的實例並使用它:
void notifyMessages() {
// Sending a Text Message
Message textMessage = new Message();
Notifier textNotifier = new TextMessageNotifier();
textNotifier.notify(textMessage);
// Sending an Email Message
Message emailMessage = new Message();
Notifier emailNotifier = new EmailNotifier();
emailNotifier.notify(emailMessage);
}
我們發現 Java JDK 中繼承和子類的使用非常豐富。我們以Java的Collection
API為例。我們在 Collections API 中有一個AbstractList
類,它通過具體實現進行了擴展,例如LinkedList
、 ArrayList,
和Vector
,它們都是它的子類。
5. 內部類的必要性
內部類有助於本地化重要的代碼構造,同時仍然以類的形式封裝它們。在我們前面的示例中,通知程序使用不同的底層通知邏輯,這些邏輯可能彼此非常不同。
例如,電子郵件通知程序可能需要有關 SMTP 服務器和其他邏輯的信息來發送電子郵件。另一方面,短信通知者需要發送短信的電話號碼。在所有這些通知程序中,共享代碼最少。它們也僅在其自己的通知程序的上下文中有用。
我們的EmailNotifier
實現需要信息並訪問 SMTP 服務器來發送電子郵件。我們可以將與連接和發送電子郵件相關的樣板代碼編寫為內部類:
class EmailNotifier extends Notifier {
@Override
void notify(Message e) {
// notify method implementation
}
// Inner class for email connection
static class EmailConnector {
private String emailHost;
private int emailPort;
// Getter Setters
private void connect() {
// connect to the smtp server
}
}
}
因此,我們可以在外部類的notify()
方法中使用內部類來發送電子郵件:
@Override
void notify(Message e) {
// connect to the email connector and send email
EmailConnector emailConnector = new EmailConnector();
emailConnector.connect();
// send email
}
Java JDK中內部類的用法可以在List
接口的LinkedList
實現中找到。 Node
類被創建為靜態內部類,因為它在LinkedList
之外的使用是沒有意義且不必要的。 HashMap
類的設計也採取了類似的做法,它使用Entry
作為內部類。
6. 子類和內部類的區別
我們可以將Java中子類和內部類的區別總結如下:
- 內部類始終與外部類位於同一文件中,而子類可以分開
- 一般情況下,內部類不能訪問外部類的成員變量或方法,而子類可以從父類訪問
- 我們不能直接實例化內部類(除非它們是靜態內部類),而子類可以
- 我們創建內部類主要是為了將它們用作小型輔助類;然而,子類有助於覆蓋父類的功能
七、結論
在本文中,我們討論了子類、內部類以及它們在編寫模塊化面向對象代碼中的作用。我們還研究了它們之間的差異以及何時選擇其中一種。
與往常一樣,本教程的完整實現可以在 GitHub 上找到。