《Java從小白到大牛》之第10章 面向對象基礎(上)

《Java從小白到大牛》紙質版已經上架了!!!
Java從小白到大牛書皮

面向對象是Java最重要的特性。Java是徹底的、純粹的面嚮對象語言,在Java中“一切都是對象”。本章將介紹面向對象基礎知識。

面向對象概述

面向對象的編程思想:按照真實世界客觀事物的自然規律進行分析,客觀世界中存在什麼樣的實體,構建的軟件系統就存在什麼樣的實體。

例如:在真實世界的學校裏,會有學生和老師等實體,學生有學號、姓名、所在班級等屬性(數據),學生還有學習、提問、吃飯和走路等操作。學生只是抽象的描述,這個抽象的描述稱爲“類”。在學校裏活動是學生個體,即:張同學、李同學等,這些具體的個體稱爲“對象”,“對象”也稱爲“實例”。

在現實世界有類和對象,面向對象軟件世界也會有,只不過它們會以某種計算機語言編寫的程序代碼形式存在,這就是面向對象編程(Object Oriented Programming,OOP)。作爲面向對象的計算機語言——Java,具有定義類和創建對象等面向對象能力。

面向對象三個基本特性

面向對象思想有三個基本特性:封裝性、繼承性和多態性。

封裝性 {#-0}

在現實世界中封裝的例子到處都是。例如:一臺計算機內部極其複雜,有主板、CPU、硬盤和內存,而一般用戶不需要了解它的內部細節,不需要知道主板的型號、CPU主頻、硬盤和內存的大小,於是計算機製造商將用機箱把計算機封裝起來,對外提供了一些接口,如鼠標、鍵盤和顯示器等,這樣當用戶使用計算機就變非常方便。

那麼,面向對象的封裝與真實世界的目的是一樣的。封裝能夠使外部訪問者不能隨意存取對象的內部數據,隱藏了對象的內部細節,只保留有限的對外接口。外部訪問者不用關心對象的內部細節,使得操作對象變得簡單。

繼承性 {#-1}

在現實世界中繼承也是無處不在。例如:輪船與客輪之間的關係,客輪是一種特殊輪船,擁有輪船的全部特徵和行爲,即數據和操作。在面向對象中輪船是一般類,客輪是特殊類,特殊類擁有一般類的全部數據和操作,稱爲特殊類繼承一般類。在Java語言中一般類稱爲“父類”,特殊類稱爲“子類”。

提示 在有些語言如C++支持多繼承,多繼承就是一個子類可有多個父類,例如,客輪是輪船也是交通工具,客輪的父類是輪船和交通工具。多繼承會引起很多衝突問題,因此現在很多面向對象的語言都不支持多繼承。Java語言是單繼承的,即只能有一個父類,但Java可以實現多個接口,可以防止多繼承所引起的衝突問題。

多態性 {#-2}

多態性是指在父類中成員變量和成員方法被子類繼承之後,可以具有不同的狀態或表現行爲。有關多態性詳細解釋,請參考12.4節,這裏不再贅述。

類是Java中的一種重要的引用數據類型,是組成Java程序的基本要素。它封裝了一類對象的數據和操作。

類聲明 {#-0}

Java語言中一個類的實現包括:類聲明和類體。類聲明語法格式如下。

[public][abstract|final] class className [extends superclassName] [implements interfaceNameList] {

//類體

}

其中,class是聲明類的關鍵字,className是自定義的類名;class前面的修飾符public、abstract、final用來聲明類,它們可以省略,它們的具體用法後面章節會詳細介紹;superclassName爲父類名,可以省略,如果省略則該類繼承Object類,Object類所有類的根類,所有類都直接或間接繼承Object;interfaceNameList是該類實現的接口列表,可以省略,接口列表中的多個接口之間用逗號分隔。

提示 本書語法表示符號約定,在語法說明中,括號([])部分表示可以省略;豎線(|)表示“或關係”,例如abstract|final,說明可以使用abstract或final關鍵字,兩個關鍵字不能同時出現。


聲明動物(Animal)類代碼如下:

// Animal.java

public class Animal extends Object {

//類體

}

上述代碼聲明瞭動物(Animal)類,它繼承了Object類。繼承Object類extends Object代碼可以省略。

類體是類的主體,包括數據和操作,即成員變量和成員方法。下面就來展開介紹一下。

### 成員變量 {#-1}

聲明類體中成員變量語法格式如下:
```java
class className {

[public | protected | private ] [static] [final] type variableName; //成員變量

}

其中type是成員變量數據類型,variableName是成員變量名。type前的關鍵字都是成員變量修飾符,它們說明如下:

  1. public、protected和private修飾符用於封裝成員變量。
  2. static修飾符用於聲明靜態變量,所以靜態變量也稱爲“類變量”。
  3. final修飾符用於聲明變量,該變量不能被修改。

下面看一個聲明成員變量示例:

// Animal.java

public class Animal extends Object {

//動物年齡

int age = 1;

//動物性別

public boolean sex = false;

//動物體重

private double weight = 0.0;

}

上述代碼中沒有展示靜態變量聲明,有關靜態變量稍後會詳細介紹。

成員方法 {#-2}

聲明類體中成員方法語法格式如下:

class className {

[public | protected | private ] [static] [final | abstract] [native] [synchronized]

type methodName([paramList]) [throws exceptionList] {

//方法體

}

}

其中type是方法返回值數據類型,methodName是方法名。type前的關鍵字都是方法修飾符,它們說明如下:

  1. public、protected和private修飾符用於封裝方法。
  2. static修飾符用於聲明靜態方法,所以靜態方法也稱爲“類方法”。
  3. final | abstract不能同時修飾方法,final修飾的方法不能在子類中被覆蓋;abstract用來修飾抽象方法,抽象方法必須在子類中被實現。
  4. native修飾的方法,稱爲“本地方法”,本地方法調用平臺本地代碼(如:C或C++編寫的代碼),不能實現跨平臺。
  5. synchronized修飾的方法是同步的,當多線程方式同步方法時,只能串行地執行,保證是線程安全的。

方法聲明中還有([paramList])部分,它是方法的參數列表。throws exceptionList是聲明拋出異常列表。

下面看一個聲明方法示例:

public class Animal {// extends Object {

//動物年齡

int age = 1;

//動物性別

public boolean sex = false;

//動物體重

private double weight = 0.0;

public void eat() { ①

// 方法體

return; ②

}

int run() { ③

// 方法體

return 10; ④

}

protected int getMaxNumber(int number1, int number2) { ⑤

// 方法體

if (number1 > number2) {

return number1; ⑥

}

return number2;

}

}

上述代碼第①、③、⑤行聲明瞭三個方法。方法在執行完畢後把結果返還給它的調用者,方法體包含“return 返回結果值;”語句,見代碼第④行的“return 10;”,“返回結果值”數據類型與方法的返回值類型要匹配。如果方法返回值類型爲void時,方法體包含“return;”語句,見代碼第②行,如果“return;”語句是最後一行則可以省略。

提示 通常return語句通常用在一個方法體的最後,否則會產生編譯錯誤,除非用在if-else語句中,見代碼第⑥行。

在程序代碼中給類起一個名字是非常重要的,但是有時候會出現非常尷尬的事情,名字會發生衝突,例如:項目中自定義了一個日期類,我爲它取名爲Date,但是會發現Java SE核心庫中還有兩個Date,它們分別位於java.util包和java.sql包中。

包作用 {#-0}

在Java中爲了防止類、接口、枚舉和註釋等命名衝突引用了包(package)概念,包本質上命名空間(namespace)[^9]。在包中可以定義一組相關的類型(類、接口、枚舉和註釋),併爲它們提供訪問保護和命名空間管理。

在前面提到的Date類名稱衝突問題,很好解決,將不同Date類放到不同的包中,我們自定義Date,可以放到自己定義的包com.a51work6中,這樣就不會與java.util包和java.sql包中Date發生衝突問題了。

包定義 {#-1}

Java中使用package語句定義包,package語句應該放在源文件的第一行,在每個源文件中只能有一個包定義語句,並且package語句適用於所有類型(類、接口、枚舉和註釋)的文件。定義包語法格式如下:

package pkg1[.pkg2[.pkg3…]];

pkg1~ pkg3都是組成包名一部分,之間用點(.)連接,它們命名應該是合法的標識符,其次應該遵守Java包命名規範,即全部小寫字母。

定義包示例代碼如下:

// Date.java文件

package com.a51work6;

public class Date {

}

com.a51work6是自定義的包名,包名一般是公司域名的倒置。

提示 我們公司的域名是51work6.com,倒置後是com.51work6,其中51work6是非法標識符(不能用數字開頭),所以com.51work6包名是非法的,於是將包名改爲com.a51work6。

如果在源文件中沒有定義包,那麼類、接口、枚舉和註釋類型文件將會被放進一個無名的包中,也稱爲默認包。

定義好包後,包採用層次結構管理這些類型(類、接口、枚舉和註釋),如圖10-1所示是在Eclipse包資源視圖中查看包,可見有默認包和com.a51work6包。如果文件系統中查看這些包,會發現如同10-2所示的層次結構,源文件目錄是根目錄,也是默認包目錄,可見其中有一個HelloWorld.java文件。com是文件夾,a51work6子文件夾,在a51work6中包含:Animal.java和Date.java兩個文件。Java編譯器把包對應於文件系統的目錄管理,不僅是源文件,編譯之後的字節碼文件也採用文件系統的目錄管理的。

圖10-1 Eclipse包資源視圖中查看包

圖10-2 文件系統目錄與包

包引入 {#-2}

爲了能夠使用一個包中類型(類、接口、枚舉和註釋),需要在Java程序中明確引入該包。使用import語句實現引入包,import語句應位於package語句之後,所有類的定義之前,可以有0~n條import語句,其語法格式爲:

import package1[.package2…].(類型名|*);

“包名.類型名”形式只引入具體類型,“包名.*”採用通配符,表示引入這個包下所有的類型。但從編程規範的角度提倡明確引入類型名,即“包名.類型名”形式可以提高程序的可讀性。

如果需要在程序代碼中使用com.a51work6包中Date類。示例代碼如下:

// HelloWorld.java文件

import com.a51work6.Date; ①

public class HelloWorld {

public static void main(String[] args) {

Date date = new Date(); ②

System.out.println(date);

}

}

上述代碼第②行使用了Date類,需要引入Date所在的包,見代碼第①行,import是關鍵字,代碼第①行的import語句採用“包名.類型名”形式。

提示 如果在一個源文件中引入兩個相同包名+類型名,見如下代碼,代碼第②行會發生編譯錯誤。爲避免這個編譯錯誤,可以在沒有引入包的類型名前加上包名,詳見如下代碼第②行中的java.util.Date。

// HelloWorld.java文件

import com.a51work6.Date;

//import java.util.Date; ①

public class HelloWorld {

public static void main(String[] args) {

Date date = new Date();

System.out.println(date);

java.util.Date now = new java.util.Date(); ②

System.out.println(now);

}

}

注意 當前源文件與要使用的類型(類、接口、枚舉和註釋)在同一個包中,可以不用引入包。

常用包 {#-3}

Java SE提供一些常用包,其中包含了Java開發中常用的基礎類。這些包有:java.lang、java.io、java.net、java.util、java.text、java.awt和javax.swing。

  1. java.lang包

java.lang包含中包含了Java語言的核心類,如Object、Class、String、包裝類和Math等,還有包裝類Boolean、Character、Integer、Long、Float和Double。使用java.lang包中的類型,不需要顯示使用import語句引入,它是由解釋器自動引入。

  1. java.io包

java.io包含中提供多種輸入/輸出流類,如InputStream、OutputStream、Reader和Writer。還有文件管理相關類和接口,如File和FileDescriptor類以及FileFilter接口。

  1. java.net包

java.net包含進行網絡相關的操作的類,如URL、Socket和ServerSocket等。

  1. java.util包

java.util包含一些實用工具類和接口,如集合、日期和日曆相關類和接口。

  1. java.text包

java.text包中提供文本處理、日期式化和數字格式化等相關類和接口。

  1. java.awt和javax.swing包

java.awt和javax.swing包提供了Java圖形用戶界面開發所需要的各種類和接口。java.awt提供是一些基礎類和接口,javax.swing提供了一些高級組件。

[^9]: 命名空間,也稱名字空間、名稱空間等,它表示着一個標識符(identifier)的可見範圍。一個標識符可在多個命名空間中定義,它在不同命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,因爲已有的定義都處於其他命名空間中。 ——引自於 維基百科 https://zh.wikipedia.org/wiki/命名空間

方法重載(Overload) {#overload}

在第10章介紹字符串時就已經用到過方法重載,這一節詳細介紹一下重載。出於使用方便等原因,在設計一個類時將具有相似功能的方法起相同的名字。例如String字符串查找方法indexOf有很多不同版本,如圖10-3所示:

圖10-3 indexOf方法重載

這些相同名字的方法之所以能夠在一個類中同時存在,是因爲它們的方法參數列表,調用時根據參數列表調用相應重載方法。

提示 方法重載中參數列表不同的含義是:參數的個數不同或者是參數類型不同。另外,返回類型不能用來區分方法重載。

方法重載示例MethodOverloading.java代碼如下:

// MethodOverloading.java文件

package com.a51work6;

class MethodOverloading {

void receive(int i) { ①

System.out.println("接收一個int參數");

System.out.println("i = " + i);

}

void receive(int x, int y) { ②

System.out.println("接收兩個int參數");

System.out.printf("x = %d, y = %d \r", x, y);

}

int receive(double x, double y) { ③

System.out.println("接收兩個double參數");

System.out.printf("x = %f, y = %f \r", x, y);

return 0;

}

}

// HelloWorld.java文件調用MethodOverloading

package com.a51work6;

public class HelloWorld {

public static void main(String[] args) {

MethodOverloading mo = new MethodOverloading();

//調用void receive(int i)

mo.receive(1); ④

//調用void receive(int x, int y)

mo.receive(2, 3); ⑤

//調用void receive(double x, double y)

mo.receive(2.0, 3.3); ⑥

}

}

MethodOverloading類中有三個相同名字的receive方法,在HelloWorld的main方法中調用MethodOverloading的receive方法。運行結果如下:

接收一個int參數

i = 1

接收兩個int參數

x = 2, y = 3

接收兩個double參數

x = 2.000000, y = 3.300000

調用哪一個receive方法是根據參數列表決定的。如果參數類型不一致,編譯器會進行自動類型轉換尋找適合版本的方法,如果沒有適合方法,則會發生編譯錯誤。假設刪除代碼第②行的void receive(int x, int y)方法,代碼第⑤行的mo.receive(2, 3)語句調用的是void receive(double x, double y)方法,其中int類型參數(2和3)自動會轉換爲double類型(2.0和3.0)再調用。

配套視頻

http://edu.51cto.com/topic/1246.html

配套源代碼

http://www.zhijieketang.com/group/5

與本書免費版對應的還有一個收費版本:

  1. 進入百度閱讀電子書

  2. 進入圖靈社區電子書
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章