面向物件程式設計
| 面向物件程式語言 |
|---|
面向物件程式設計(OOP)是一種設計程式和組織程式碼的方式。它不同於您可能一直使用的函數語言程式設計正規化。OOP 正規化允許您定義具有特定行為的物件,以抽象和模擬“現實生活”中的行為。在 OOP 中,我們主要關注“是什麼”,即物件的特性,而不是“如何”,即特定功能的演算法實現。因此,程式設計將首先關注所需的行為,以確保程式結構正確,然後關注實現細節。[1]
Java 是您將在此選修課中學習的程式語言。在紙質考試(考試二)中,您需要閱讀和編寫 Java 程式碼。
D.1.1概述物件的普遍性質
物件表示物理世界中的概念、想法或任何實體。例如,玩家、棋盤、骰子等。這些物件將擁有自己的屬性。例如,骰子可以被擲出並給出數字,但棋盤不能。透過物件屬性及其關係的互動,我們可以在獨立的程式碼結構中更好地模擬複雜問題。
在 Java 中,物件使用 class 關鍵字在類中定義。這裡我們建立了 User 類。
class User {
}
物件由兩部分組成
- 屬性:物件的引數。例如,使用者的姓名、使用者語言、使用者訂閱等…
- 方法:物件的功能和行為。例如,使用者可以向某人打招呼、提問、提出索賠等…
讓我們為我們的“使用者”物件新增一個 name 屬性和一個 greet() 方法。
class User {
// The attribute
private String name;
// The method
public void greet(){
System.out.println("Hello");
}
public 和 private 關鍵字在封裝部分進行了解釋
現在,讓我們看看如何建立和使用我們的物件。但是,在我們開始之前,我們需要定義一個特殊的方法,稱為建構函式。建構函式方法將允許我們建立物件的例項。類的例項意味著一個具有自己的記憶體位置並且可以使用的實際物件。
當我們初始化一個新的物件例項時,會呼叫建構函式方法。它們允許我們為屬性設定初始值。
建構函式方法的名稱始終與我們的類名相同,並且不能具有返回型別。這是一個演示
class User {
// The attribute
private String name;
// The constructor
public User(String name){
this.name = name;
}
// The method
public void greet(){
System.out.println("Hello" + " " + this.name);
}
}
請注意,所有類都預設具有建構函式:如果您沒有自己建立類建構函式,Java 會為您建立一個。但是,在這種情況下,您將無法再為物件屬性設定初始值。這意味著我們可以在此處建立 User(),但我們無法在例項化時設定其名稱。
我們還可以注意到 this 關鍵字的使用。this 關鍵字在方法或建構函式中引用當前物件。(this 關鍵字最常見的用法是消除類屬性和同名引數之間的混淆,例如當類屬性被方法或建構函式引數隱藏時)。[2]
現在讓我們例項化我們的 User 物件
class Main {
public static void main(String[] args) {
// Instantiating a User Object with name "John"
User u = new User("John");
// Using the User's method greet()
u.greet();
}
}
在此程式碼中,我們不在 User 類中。我們在 main() 方法中編寫了程式碼,它充當 Java 程式的入口點,並且是在執行程式時將要執行的方法,位於 Main 類中。
您還可以看到我們使用了 new 關鍵字來建立我們的 User 例項 u。此語法類似於我們在 Java 中例項化引用型別時使用的語法。因此,可以將定義類視為編寫您自己的使用者定義的引用型別。new 關鍵字之後的 User("John") 是對建構函式方法的呼叫,其中名稱引數在此處為“John”。
例項化我們的 User u 後,我們使用點表示法使用了其可用的方法 greet()。
如果我們編譯我們的 User.java 和 Main.java 檔案,然後執行我們編譯的 Main.java 檔案,那麼我們在終端上看到以下結果
Hello JohnD.1.2區分物件(定義、模板或類)和例項化。
要使用物件或類,必須先例項化物件(除非使用靜態類)。例項化一個類意味著為物件建立記憶體中的位置。物件中包含的值將對每個物件的例項都是唯一的。類的每個例項通常都具有相同的功能,但這些功能可以根據屬性的個別值而表現出不同的行為。
D.1.10 描述如何將資料項作為引數傳遞給操作和從操作傳遞資料項。
在我們之前的示例中,我們使用構造方法傳遞了一個值 'John',將其設定為 User 類中的屬性 name。
但是,如果我們想稍後修改該名稱怎麼辦?(也許我們拼寫錯誤了。)為了輕鬆修改屬性,我們通常定義訪問器和修改器方法(這些方法有時也稱為 getter 和 setter 方法)。
它們看起來像這樣
class User {
// The attribute
private String name;
// The constructor
public User(String name) {
this.name = name;
}
// The accessor method
public String getName() {
return this.name;
}
// The mutator method
public void setName(String newName) {
this.name = newName;
}
// The greet method
public void greet() {
System.out.println("Hello" + " " + name);
}
}
按照慣例,我們通常將訪問器方法名稱定義為“get”+ 我們想要獲取的屬性的名稱。類似地,對於定義修改器方法名稱,我們使用“set”+ 我們想要更改的屬性的名稱。但是,如果存在使程式碼更易於閱讀和理解的命名方式,我們可以偏離該命名約定。
我們可以像這樣在 Main 類上使用訪問器和修改器方法
class Main {
public static void main(String[] args) {
// Instantiating a User Object with name "John"
User u = new User("John");
// Checking our current name attribute
System.out.println(u.getName());
// Changing our current name attribute
u.setName("Jonathan");
// Using our greet() method
u.greet();
}
}
這將輸出
John
Hello Jonathan在 OOP 中,建構函式、訪問器和修改器等方法是修改物件屬性的首選方式。與刪除和重新建立例項相比,它們提供了更大的靈活性,並且還允許更好的封裝,我們將在後續章節中看到這一點。
D.1.8 為給定問題構建相關的物件。
練習
假設您想編寫一個數字時鐘應用程式
- Clock 物件將有哪些屬性?
- Clock 物件將有哪些方法?
- 開啟 IDE 並嘗試編寫此 Clock 物件的程式碼。
- 標準 Java 庫中是否已存在 Clock 物件?
D.1.5 描述分解成幾個相關物件的流程。
計算機科學中的分解,也稱為分解,是指將複雜問題或系統分解成更易於構思、理解、程式設計和維護的部分的過程。面向物件的分解將大型系統分解成越來越小的類或物件,這些類或物件負責問題域的某些部分。
對於您的問題,沒有“一種”方法可以實現最佳的 OOP 結構,但有一些可以應用的設計流程來提供幫助。大多數這些流程都可以在主題 1 中看到,例如迭代開發、敏捷開發、測試驅動開發……
使用 UML 來表示您的物件及其關係也是設計過程的重要組成部分。(見下文)
D.1.6 描述給定問題中物件之間的關係。
為了能夠開發出解決複雜問題的解決方案,我們將需要在專案期間定義不同的物件,並且這些物件將相互互動。
物件主要有三種關係
- “has-a”關係,表示類的屬性將是另一個類的例項。例如,Book 物件將包含 Author 物件,或者 HighSchoolClass 物件將包含 Students 和 Teacher。
- “is-a”關係,也稱為繼承,表示一個物件是另一個物件的子類別。它是對上層類別的更精確的定義。例如,Student 物件擴充套件了 Human 物件,Car 物件擴充套件了 Vehicle 物件,或者 Dog 物件擴充套件了 Animal 物件。
- “uses-a”關係,表示一個物件將在其方法之一中使用一個類的例項。例如,Student 物件在閱讀時可能會使用 Book 物件,Shelf 物件在構建時可能會使用鑽頭,而 Human 物件在游泳時可能會使用 Swimsuit 物件和 Towel 物件。
讓我們看一些這三種關係的程式碼示例。
讓我們以 Book 物件為例,它將 Author 物件作為屬性。首先讓我們定義我們的 Author 類
class Author {
private String firstName;
private String lastName;
public Author(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getName(){
return firstName + " " + lastName;
}
}
現在讓我們定義我們的 Book 類
class Book {
private String title;
private int year;
private Author author; //has-a relationship
public Book(String title, int year, Author author) {
this.title = title;
this.year = year;
this.author = author; // the Auhtor instance will be given in the constructor method
}
public void getBookInfos(){
String infos = String.format("The book \"%s\" was written by %s" + " in %d",
this.title, this.author.getName(), this.year); // we use the Authors's method getName() here
System.out.println(infos);
}
public static void main(String[] args) {
//We directly construct our author instance while constructing the book instance
Book b = new Book("Nineteen Eighty-Four", 1949, new Author("George", "Orwell"));
b.getBookInfos();
}
}
如果我們編譯我們的 Book.java 和 Author.java,然後執行我們的 Book.class 檔案(因為它包含 main() 方法),我們將獲得以下輸出
The book "Nineteen Eighty-Four" was written by George Orwell in 1949練習:嘗試在 HighSchoolClass 物件、Students 物件和 Teachers 物件之間定義“has-a”關係。提示:您可能希望定義一個包含多個 Student 物件的 Students 物件。這稱為聚合類(對於 Students)。
讓我們以 Student 類擴充套件 Human 類為例。
為此,讓我們定義一個非常簡單的 Human 類。此 Human 類具有一個屬性 name 和一個方法 greet()。
class Human {
protected String name;
public Human(String name) {
this.name = name;
}
public void greet(){
System.out.printf("Hello I am %s%n",this.name);
}
}
現在,如果我們將 Student 類定義為 Human 的子類(因為所有學生都是人類),這意味著 Student 類將能夠訪問 name 屬性和 greet() 方法,而無需重新定義它們。Student 類還可以具有其他屬性或方法。
為了表示從 Human 到 Student 的“is-a”關係,我們在定義子類時使用 extends 關鍵字。
因此,我們的 Student 類將如下所示
class Student extends Human {
private String school;
public Student(String name, String school) {
super(name); // we refer to the superclasse's constructor
this.school = school;
}
public void studentGreet(){
System.out.printf("Hello I am student %s from %s.%n",this.name, this.school);
}
public void transfers(String newSchool){
this.school = newSchool;
}
public static void main(String[] args) {
Human h = new Human("Lisa");
h.greet();
Student s = new Student("Zara", "H4");
s.greet(); //uses the Human method greet()
s.transfers("EJM");
s.studentGreet(); // uses the Student method studentGreet();
}
}
當我們編譯然後執行我們的 Student.java 程式碼時,我們得到
Hello I am Lisa
Hello I am Zara
Hello I am student Zara from EJM.請注意,我們也可以選擇將我們的 Student 方法命名為 studentGreet(),而不是 greet()。在這種情況下,Student 物件將始終執行 greet() 方法的學生版本,而不是 Human 版本。這稱為覆蓋。我們將在專門的部分中學習繼承的更多方面。
練習:嘗試在 Animal 類和 Bird 類之間定義“is-a”關係。
讓我們研究一個 Student 物件在其方法 reading() 中使用 Book 物件的示例。首先,讓我們定義 Book 類
class Book {
String title;
int currentPage = 1;
Book(String title) {
this.title = title;
}
String getTitle(){
return this.title;
}
int getCurrentPage(){
return this.currentPage;
}
void setCurrentPage(int newPageNumber) {
this.currentPage = newPageNumber;
}
}
Book 物件非常簡單,它儲存書名,我們可以訪問書名和當前所在的頁碼。現在讓我們定義 Student 類。Student 將有一個方法 reading(),它將使用 Book 物件來工作。
class Student {
String name;
Student(String name) {
this.name = name;
}
void reading(Book b){
System.out.printf("Currently reading \"%s\" at page %d.%n", b.getTitle(), b.getCurrentPage());
b.setCurrentPage(b.getCurrentPage() + 1);
}
public static void main(String[] args) {
Book b = new Book("Clean Code");
Student s = new Student("Lisa");
s.reading(b);
s.reading(b);
s.reading(b);
}
}
因此,現在如果我們編譯並執行我們的 Student.java 程式碼,我們將獲得以下輸出
Currently reading "Clean Code" at page 1.
Currently reading "Clean Code" at page 2.
Currently reading "Clean Code" at page 3.但是為什麼 Book 物件是 reading() 方法的引數而不是作為屬性儲存?好吧,Book 不是 Student 的必要組成部分,它沒有定義 Student 的屬性。它偶爾用於特定任務,因此最好將其作為引數傳遞。
還需要注意的是,b.setCurrentPage(b.getCurrentPage() + 1); 在它正在做什麼方面不是很明確。定義一個 turnPage() 方法在這裡可能更容易閱讀,並且是更好的“整潔程式碼”實踐。
練習:嘗試在 Human 類和 Bike 類之間定義“uses-a”關係,在 commuting() 方法中。
UML 的建立最初是為了標準化不同的符號系統和軟體設計方法。它是先前物件建模語言(Booch、OMT、OOSE)的綜合,主要源於 Grady Booch、James Rumbaugh 和 Ivar Jacobson 的工作成果。它於 1994 年至 1995 年在 Rational Software 開發,並在 1996 年由他們領導進一步開發。1997 年,UML 被物件管理組 (OMG) 採用為標準,並從那時起一直由該組織管理。2005 年,UML 也由國際標準化組織 (ISO) 釋出為經批准的 ISO 標準。從那時起,該標準定期修訂以涵蓋 UML 的最新修訂版
統一建模語言 (UML) 是一種基於象形圖和視覺元素的圖形建模語言。它旨在成為軟體開發和麵向物件設計領域中標準化的視覺化方法。
UML 旨在在整個軟體開發生命週期中支援軟體開發過程。因此,它提供了許多不同的圖表模板,例如部署圖、用例圖、時序圖等......我們對 OOP 和 IB 文憑感興趣的是類圖。它透過顯示系統的類、它們的屬性、方法以及物件之間的關係來描述系統的結構。
讓我們看看類圖中使用的不同圖形元素。

在圖中,類用包含三個隔間的框表示
- 頂部隔間包含類的名稱。它以粗體居中列印,並且第一個字母大寫。
- 中間隔間包含類的屬性。它們左對齊,第一個字母小寫。
- 底部隔間包含類可以執行的操作。它們也左對齊,第一個字母小寫。

要指定類成員(即任何屬性或方法)的可見性,必須在成員名稱前放置以下這些符號。
+
|
公有(Public) |
-
|
私有(Private) |
#
|
受保護(Protected) |
~
|
包級(Package) |
上面的 UML 圖是 "Book" 類,有兩個私有屬性:"title" 型別為 String,"currentPage" 型別為 int,預設為 0。類中包含兩個方法 "turnPage" 和 "getTitle",均不接受引數。

UML 定義了以下關係
- 關聯(Association): 表示一個類正在使用另一個類的例項。它是一種 "has-a" 關係。當看到一個屬性是另一個類的例項時,就可以識別出關聯關係。例如,一個 Music 物件將有一個 Guitar 物件的例項作為屬性,以便它可以在其方法中使用吉他來產生音樂。它用一個從使用另一個類的類發出的簡單黑色箭頭表示。
- 聚合(Aggregation): 表示一個類包含了另一個類的多個例項。它是一種 "has-a" 關係。例如,一個 Class 將包含多個 Student 例項。當有一個屬性是另一個類的例項的集合時,就可以識別出聚合關係。UML 中用一個指向包含另一個類多個例項的類的空心菱形表示聚合關係。
- 繼承(Inheritance): 表示正在發生超類/子類關係。它是一種 "is-a" 關係。請參閱下面的部分以瞭解更多關於繼承的資訊。它用一個指向超類並起源於子類的白色箭頭表示。
- 依賴(Dependency): 表示一個類依賴於另一個類來執行特定操作。它是一種 "uses-a" 關係。例如,一個 Student 物件需要一個 Swimsuit 例項才能去游泳。在程式碼中,當另一個類的例項被用作方法的引數時,可以識別出依賴關係。它用一個從使用另一個類的類發出的帶虛線的簡單黑色箭頭表示。
D.1.3 構建統一建模語言 (UML) 圖以表示物件設計。
D.1.4 解釋 UML 圖。

class Bike{
private String model;
private float speed;
public Bike(String model, float speed) {
this.model = model;
this.speed = speed;
}
public String getModel() {
return model;
}
public float getSpeed() {
return speed;
}
}
class Human {
private String name;
public Human(String name){
this.name = name;
}
// this method is our "uses-a" relationship (or association in UML)
public void commuting(Bike myBike){
System.out.printf("Currently riding a %s bike at %f km/h !%n", myBike.getModel(), myBike.getSpeed());
}
public void greet(){
System.out.printf("Hi I'm %s !", this.name);
}
}
public class Main {
public static void main(String[] args) {
// instance 1 of Bike class
Bike myBike = new Bike("electric", 25);
// instance 2 of Bike class
Bike rental_bike = new Bike("velib", 18.2f);
// instance of Human
Human h = new Human("Lisa");
h.greet();
// using a first bike to commute
h.commuting(myBike);
System.out.println("Arrived at work ! Catching my breath ...");
// using another bike to commute
h.commuting(rental_bike);
System.out.println("Arrived home! Catching my breath ...");
}
}
輸出
Hi I'm Lisa !Currently riding a electric bike at 25,000000 km/h !
Arrived at work ! Catching my breath ...
Currently riding a velib bike at 18,200001 km/h !
Arrived home! Catching my breath ...
D.1.7 概述在給定問題中減少物件之間依賴性的必要性。
- 它增加了維護開銷。
- 維護開銷是指如果對元件進行更改,則需要對整個系統進行的更改。
例如,如果更改 B,則會影響 C、D 和 E 的工作方式,這意味著您必須花費時間修復它們以與“新的”B 協同工作。
D.1.9 解釋表示資料項需要不同資料型別的原因。
- char:機器可定址的最小單元,可以包含基本字元集。它是一種整數型別。實際型別可以是有符號或無符號的,具體取決於實現。
- int:基本的帶符號整數型別。至少在 [−32767,+32767] 範圍內,因此大小至少為 16 位。
- float:單精度浮點型別。實際屬性未指定(除了最小限制),但在大多數系統上,這是 IEEE 754 單精度二進位制浮點格式。
- string:儲存從 0 到 65535 範圍內的無符號 16 位(2 位元組)程式碼點的序列。每個程式碼點或字元程式碼都表示單個 Unicode 字元。字串可以包含 0 到大約 20 億 (2 ^ 31) 個 Unicode 字元。
D.2.1 定義封裝術語。
封裝被定義為“將程式碼和資料封裝到一個單元中的過程”。但這意味著什麼呢?從實際意義上講,封裝是透過設定屬性和方法的正確訪問級別來實現的。您可以將其視為物件的保護盾:我們保護內部機制,並且只公開公眾可以使用的某些方法。這就像啟動計算機時一樣,“開機”按鈕隱藏了使用者看不到的後臺所有啟動過程。終端使用者不關心實現的細節,也不應該被這些細節打擾。
為了實現封裝,我們有以下訪問修飾符供我們使用。這些可以為屬性和方法設定,並且應該明確指定,而不是使用預設訪問修飾符。
- 私有(Private): 最嚴格的關鍵字;只能在宣告的類中訪問。
- 受保護(Protected): 當宣告時,只能被另一個包中的子類或成員類中的任何類訪問。
- 公有(Public): 可以從任何其他類訪問。它是限制最少的關鍵字。
- 預設(Default): 如果您沒有指定任何訪問修飾符,則程式碼只能被同一包中的類訪問。如果您沒有宣告任何包,則意味著您的程式碼只能在當前專案中訪問。
在大多數情況下,我們希望將屬性設定為私有,並將訪問器和修改器設定為公有。(實際上,這允許更好地控制對屬性進行的修改(無直接修改),並有助於除錯、管理不需要的行為以及更清晰易讀的程式碼。)
讓我們使用我們的第一個User示例來檢查這些訪問修飾符的行為。
公有屬性
class User {
public String name;
public User(String name){
this.name = name;
}
public void greet(){
System.out.println("Hello" + " " + this.name);
}
}
class Main {
public static void main(String[] args) {
User u = new User("Lily");
u.name = "Joshua";
u.greet();
}
}
編譯並執行我們的Main.java時,我們得到以下輸出
Hello Joshua擁有一個public屬性意味著我們可以從另一個類直接更改屬性u.name = "Joshua"的值。
私有屬性
如果我們嘗試編譯並執行相同的Main.java,但在User.java中使用屬性private String name;,則會收到以下錯誤
java: name has private access in User實際上,如果屬性是私有的,則意味著我們不能從另一個類直接修改它。如果可用,我們將不得不使用公有的訪問器和修改器方法。但是,我們仍然可以在其類內部使用該屬性,就像我們在greet()方法中所做的那樣。
私有方法
如果我們在Student.java中將我們的greet()方法設為私有,並嘗試在我們的Main.java檔案中呼叫u.greet(),則會收到以下錯誤
java: greet() has private access in User實際上,如果greet()方法是私有的,則意味著任何外部類都無法訪問它。我們使用私有方法的唯一方法是在同一類中的另一個方法中,或者如果main()方法是從該類執行的。
公有方法 公有方法可從外部類訪問,並按“預期方式”執行;
D.2.4 解釋封裝的優點。
封裝提供了幾個優點
- 它提供了資料隱藏,這意味著對某些資訊的訪問受到控制和限制。這樣,使用者(其他類)只能看到其級別的可用操作,而不必擔心實現細節。因此,屬性的資料管理被隱藏起來。
- 它提供了對資料管理的更好控制,因為如果使用者操作受到限制,則可能出現較少的意外行為。
- 它透過保持資料私有並提供公共定義良好的服務方法來提高可用性,物件的職責對於其他物件變得清晰。
- 它提供了靈活性,因為我們可以根據需要和用例更改訪問修飾符。
- 它有助於我們擁有易於透過單元測試進行測試的程式碼。
- 它使程式碼更易於重用,因為我們本質上關心的是存在哪些方法,而不是實現。我們可以在不更改程式碼結構的情況下更改方法的實現。它促進了維護,因為程式碼更改可以獨立進行。
D.2.2 定義繼承術語。
繼承是一個概念,其中子類(也稱為子類或派生類)繼承自超類(也稱為父類或基類)。子類是一個類,它將描述比超類更精確的物件型別。子類可以訪問超類的方法和屬性。
讓我們使用我們之前的超類Human和子類Student。
class Human {
protected String name;
public Human(String name) {
this.name = name;
}
public void greet(){
System.out.printf("Hello I am %s%n",this.name);
}
}
class Student extends Human {
private String school;
public Student(String name, String school) {
super(name); // we refer to the superclasse's constructor
this.school = school;
}
public void studentGreet(){
System.out.printf("Hello I am student %s from %s.%n",this.name, this.school);
}
public void transfers(String newSchool){
this.school = newSchool;
}
public static void main(String[] args) {
Human h = new Human("Lisa");
h.greet();
Student s = new Student("Zara", "H4");
s.greet(); //uses the Human method greet()
s.transfers("EJM");
s.studentGreet(); // uses the Student method studentGreet();
}
}
當我們編譯然後執行我們的 Student.java 程式碼時,我們得到
Hello I am Lisa
Hello I am Zara
Hello I am student Zara from EJM.這裡,Student 類是 Human 的子類(因為所有學生都是人類)。由於訪問修飾符的存在,Student 類無需重新定義即可訪問 name 屬性和 greet() 方法。實際上,子類不會繼承其父類的 private 成員。只有 public 或 protected 成員會被繼承。但是,如果超類具有用於訪問其 private 屬性的 public 或 protected 方法,則子類也可以使用這些方法。
Student 類還可以具有其他屬性或方法。這裡 Student 有一個額外的 schoolName 屬性和兩個額外的方法:transfers() 和 studentGreet()
要定義子類,我們使用 extends 關鍵字。該關鍵字僅在子類中使用,而不是在超類中使用。這裡 class Student extends Human
建構函式不是類的成員,因此不會被子類繼承,但可以從子類中呼叫超類的建構函式。為了實現這一點,我們使用了 super 關鍵字。super 關鍵字允許我們訪問超類的屬性、方法和建構函式。這裡,在我們的 Student 建構函式中,我們透過呼叫 super(name) 來引用 Human 的建構函式。
要了解更多關於 super 關鍵字的資訊:https://www.programiz.com/java-programming/super-keyword
子類也可以成為另一個子類的超類。這稱為**多級繼承**。例如,我們可以有:Student 擴充套件 Human,Human 擴充套件 Mammal,Mammal 擴充套件 Animal。這裡 Human 是 Mammal 的子類,但 Human 也是 Student 的超類。**在 Java 中,類僅支援單一繼承**,因此我們一次只能擴充套件一個類(我們將編寫 class Student extends Human 而不是 class Student extends Mammal extends Animal。要檢視全域性繼承模式,UML 圖非常有用。
一個超類可以被多個類擴充套件。這稱為**層次繼承**。例如,Human 類可以被 Student 類擴充套件,但 Human 類也可以同時被 Teacher 類擴充套件。同樣,要檢視全域性繼承模式,UML 圖非常有用。
在重寫方法時,使用 @Override 註解是一種良好的程式碼規範,因為它使重寫變得明顯且不隱蔽。
當我們在子類中定義一個屬性或方法,且其**名稱**與超類中的相同,就會發生重寫。如果發生這種情況,則超類的屬性或方法將被**隱藏**,並且子類的例項將無法再訪問它。
例如,如果我們在 Student 類中將 studentGreet() 定義為 greet(),那麼每次我們在 Student 例項上呼叫 greet() 方法時,都會收到一條包含學生姓名和學校的資訊。從 Student 例項中,我們將無法再獲得僅包含學生姓名的問候語訊息。但是,從 Human 例項中,當我們呼叫 greet() 時,我們將獲得僅包含姓名的問候語訊息。
當子類需要比超類更精確地定義某種行為時,重寫非常有用。
要了解更多關於 Java 中註解的資訊:https://www.programiz.com/java-programming/annotations
**練習:**將 studentGreet() 方法重新命名為 greet(),然後嘗試從 Student 例項和 Human 例項呼叫此方法。會發生什麼情況?
所有 Java 物件都源自 Object 型別。
由於 Student 物件也是 Human 物件,因此當需要 Human 物件時可以使用 Student 物件。另一方面,不能將 Human 物件作為 Student 物件來使用。沒有什麼可以阻止我們編寫:Human n = (Human) s,其中 s 是 Student 例項。這裡甚至不需要顯式強制轉換。從子類到超類的強制轉換稱為**向上轉型**。
**練習:**嘗試實現 Teacher 類作為 Human 的子類。
**D.2.5** 解釋繼承的優點。
繼承的主要優點是它允許**程式碼重用**。超類的程式碼不需要在子類中重寫,從而節省了大量時間並避免了程式碼重複和錯誤。
**重寫**也是一個很大的優點,因為它提供了**模組化**來涵蓋更多繼承案例。實際上,可以隱藏超類的細節,以便只關注子類當前更具體的行為。方法重寫也稱為執行時多型。
**D.2.3** 定義多型這個術語。
多型是以相同的方式訪問不同型別多個物件的方法。為此,您將使用一個多型型別,該型別可以以也適用於所有其他物件型別的方式訪問。這通常與繼承結合使用,其中多個不同的子類可以作為父類型別訪問,並提供對父類中所有功能或子類過載的功能的訪問。多型子類不允許訪問子類中新增的功能。
**D.2.6** 解釋多型的優點。
- 可以使用相同的介面建立具有不同實現的方法。
- 減少了區分和處理各種物件的工作量。
- 支援構建可擴充套件的系統。
- 可以使用相同的方法簽名替換完整的實現。
**D.2.7** 描述物件庫的優點。
可以匯入物件庫以避免“重新發明輪子”。應用程式執行的許多常見任務(例如排序)已經編寫了經過良好測試的庫來執行它們。在獲得許可的情況下,可以將其他開發人員的程式碼與您的程式碼一起交付,以節省開發時間。這也減少了測試範圍,因為經過良好測試的庫不太可能出現錯誤。
**D.2.8** 描述 OOP 的缺點。
面向物件程式的檔案大小往往比其他程式大得多。這在早期儲存空間有限的時代尤其重要,或者在儲存空間仍然非常有限的嵌入式系統中。面向物件程式往往比線性程式慢,因為計算機需要遍歷不同的類並理解它們之間的關係。OO 程式語言往往具有陡峭的學習曲線。最後,面向物件程式的建立往往需要付出更多努力,因為它們需要仔細的計劃和概念化。
**D.2.9** 討論程式設計團隊的使用。
團隊的建立是為了作為一個團隊完成更大的任務 團隊使用的優點
- 更多成員意味著更多想法,包括如果沒有團隊可能不會產生的想法。
- 一些人的優勢可以彌補其他人的不足。
- 隨著解決問題“人力”的增加,可以承擔更大規模的問題和專案。
團隊使用的缺點
- 如果處理不當,一些成員的弱點可能會破壞整個團隊。
- 不同的程式設計和工作風格必須學會協調並一起工作。
- 成員之間的溝通必然成為團隊的首要任務。
**D.2.10** 解釋模組化在程式開發中的優勢。
- 如果開發了一個單獨的過程,它可以多次重複使用,而無需重新鍵入程式碼。
- 由於將整個程式碼劃分為多個部分,程式可以更容易、更有效地設計,因為一個小團隊只處理整個程式碼的一小部分。
- 模組化程式設計允許許多程式設計師協作開發同一個應用程式。
- 程式碼儲存在多個檔案中;程式碼也簡短、簡單且易於理解。
- 變數的作用域可以輕鬆控制。
- 當錯誤侷限於子程式或函式時,可以輕鬆識別它們。
**D.3.1** 定義以下術語:類、識別符號、基本型別、例項變數、引數變數、區域性變數。
**類**:類是建立單個物件的藍圖。
**識別符號**:識別符號是變數、方法、類、包和介面的名稱。它們是引用特定事物的途徑。
**基本型別**:由語言預定義並命名為保留關鍵字的值。
**D.3.2** 定義以下術語:方法、訪問器、修改器、建構函式、簽名、返回值。
**方法**:方法是執行 Java 程式碼的程式的一部分。不要將其與構造方法混淆。
**訪問器**:訪問器方法是用於獲取有關物件的資訊並用於訪問該物件中的資料的方法。
**修改器**:修改器方法是用於設定無法公開訪問的私有欄位的值的方法。
**建構函式**:構造方法是建立類的一個例項的方法。
**簽名**:指的是方法名稱及其引數的數量和型別。返回型別和丟擲的異常不被視為簽名的一部分。
**返回值**:它是程式執行後返回的值或資料型別。
**D.3.3** 定義以下術語:private、protected、public、extends、static。
私有(Private): 最嚴格的關鍵字;只能在宣告的類中訪問。
受保護(Protected): 當宣告時,只能被另一個包中的子類或成員類中的任何類訪問。
**Public**:可以從任何其他類訪問。
**Extends**:當您希望一個類或物件從另一個類或物件繼承時,將使用此 Java 關鍵字。
**Static**:此關鍵字表示成員變數或方法可以在不需要例項化其所屬的類的情況下訪問。
**D.3.4** 描述基本資料型別和引用類字串的使用。
在考試問題中,基本型別將限於 int、long、double、char 和 Boolean。
基本資料型別最常用於儲存簡單值。它們也用作更復雜抽象資料型別的構建塊。
雖然 String 不是基本資料型別,但它被認為是一種“基本”型別,因為它用於儲存簡單值。
**D.3.5** 構建程式碼以實現評估語句 D.3.1 - D.3.4。
**D.3.6** 構建與選擇語句相關的程式碼示例。
IF/ELSE 布林條件,例如 WHILE list.hasNext()
D.3.7 構建與迴圈語句相關的程式碼示例。
FOR迴圈 WHILE迴圈
D.3.8 構建與靜態陣列相關的程式碼示例。
- 從陣列中讀取資料
- 將資料移入/移出陣列
- 打印出陣列中的選定部分……等等。
D.3.9 討論現代程式語言中支援國際化的特性。
- 專門的文字啟用
- 排序行為
- 日期和時間格式
- 鍵盤佈局
- UTF-8 編碼
- 在許多平臺和語言中使用通用字元集,例如 UNICODE
- 平臺無關的高階語言(如 Java)使程式碼能夠在許多平臺上執行
D.3.10 討論程式設計師的倫理和道德義務。
- 對產品進行充分的測試,以防止可能造成的商業或其他損害
- 承認其他程式設計師的工作(避免剽竊)
- 開源運動
- 機器人和人工智慧
- 對產品進行充分的測試,以防止可能造成的商業或其他損害
- 承認其他程式設計師的工作(避免剽竊)
- 開源運動
- 機器人和人工智慧
D.4.1 定義遞迴的含義。
D.4.2 描述遞迴演算法的應用。
D.4.3 構建使用遞迴的演算法。
D.4.4 追蹤遞迴演算法。
D.4.5 定義物件引用的含義。
D.4.6 構建使用引用機制的演算法。
D.4.7 識別抽象資料型別 (ADT) 列表的特徵。
D.4.8 描述列表的應用。
D.4.9 使用列表的靜態實現構建演算法。
D.4.10 使用物件引用構建列表演算法。
D.4.11 使用 JETS 中包含的標準庫集合構建演算法。
D.4.12 追蹤使用評估陳述 D.4.9 - D.4.11 中描述的實現的演算法。
D.4.13 解釋使用庫集合的優勢。
D.4.14 概述 ADT 棧、佇列和二叉樹的特徵。
D.4.15 解釋程式碼中樣式和命名規範的重要性。
- ↑ Java OOP 做得好 使用現代 Java 建立您可以引以為豪的面向物件程式碼 Alan Mellor https://leanpub.com/javaoopdoneright
- ↑ https://w3schools.tw/java/ref_keyword_this.asp
- ↑ https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html