《Java從小白到大牛》紙質版已經上架了!!!html
面向對象是Java最重要的特性。Java是完全的、純粹的面嚮對象語言,在Java中「一切都是對象」。本章將介紹面向對象基礎知識。java
面向對象的編程思想:按照真實世界客觀事物的天然規律進行分析,客觀世界中存在什麼樣的實體,構建的軟件系統就存在什麼樣的實體。sql
例如:在真實世界的學校裏,會有學生和老師等實體,學生有學號、姓名、所在班級等屬性(數據),學生還有學習、提問、吃飯和走路等操做。學生只是抽象的描述,這個抽象的描述稱爲「類」。在學校裏活動是學生個體,即:張同窗、李同窗等,這些具體的個體稱爲「對象」,「對象」也稱爲「實例」。編程
在現實世界有類和對象,面向對象軟件世界也會有,只不過它們會以某種計算機語言編寫的程序代碼形式存在,這就是面向對象編程(Object Oriented Programming,OOP)。做爲面向對象的計算機語言——Java,具備定義類和建立對象等面向對象能力。安全
面向對象思想有三個基本特性:封裝性、繼承性和多態性。網絡
在現實世界中封裝的例子處處都是。例如:一臺計算機內部極其複雜,有主板、CPU、硬盤和內存,而通常用戶不須要了解它的內部細節,不須要知道主板的型號、CPU主頻、硬盤和內存的大小,因而計算機制造商將用機箱把計算機封裝起來,對外提供了一些接口,如鼠標、鍵盤和顯示器等,這樣當用戶使用計算機就變很是方便。多線程
那麼,面向對象的封裝與真實世界的目的是同樣的。封裝可以使外部訪問者不能隨意存取對象的內部數據,隱藏了對象的內部細節,只保留有限的對外接口。外部訪問者不用關心對象的內部細節,使得操做對象變得簡單。ide
在現實世界中繼承也是無處不在。例如:輪船與客輪之間的關係,客輪是一種特殊輪船,擁有輪船的所有特徵和行爲,即數據和操做。在面向對象中輪船是通常類,客輪是特殊類,特殊類擁有通常類的所有數據和操做,稱爲特殊類繼承通常類。在Java語言中通常類稱爲「父類」,特殊類稱爲「子類」。工具
提示 在有些語言如C++支持多繼承,多繼承就是一個子類可有多個父類,例如,客輪是輪船也是交通工具,客輪的父類是輪船和交通工具。多繼承會引發不少衝突問題,所以如今不少面向對象的語言都不支持多繼承。Java語言是單繼承的,即只能有一個父類,但Java能夠實現多個接口,能夠防止多繼承所引發的衝突問題。學習
多態性是指在父類中成員變量和成員方法被子類繼承以後,能夠具備不一樣的狀態或表現行爲。有關多態性詳細解釋,請參考12.4節,這裏再也不贅述。
類是Java中的一種重要的引用數據類型,是組成Java程序的基本要素。它封裝了一類對象的數據和操做。
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前的關鍵字都是成員變量修飾符,它們說明以下:
下面看一個聲明成員變量示例:
// Animal.java public class Animal extends Object { //動物年齡 int age = 1; //動物性別 public boolean sex = false; //動物體重 private double weight = 0.0; }
上述代碼中沒有展現靜態變量聲明,有關靜態變量稍後會詳細介紹。
聲明類體中成員方法語法格式以下:
class className { [public | protected | private ] [static] [final | abstract] [native] [synchronized] type methodName([paramList]) [throws exceptionList] { //方法體 } }
其中type是方法返回值數據類型,methodName是方法名。type前的關鍵字都是方法修飾符,它們說明以下:
方法聲明中還有([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包中。
在Java中爲了防止類、接口、枚舉和註釋等命名衝突引用了包(package)概念,包本質上命名空間(namespace)[^9]。在包中能夠定義一組相關的類型(類、接口、枚舉和註釋),併爲它們提供訪問保護和命名空間管理。
在前面提到的Date類名稱衝突問題,很好解決,將不一樣Date類放到不一樣的包中,咱們自定義Date,能夠放到本身定義的包com.a51work6中,這樣就不會與java.util包和java.sql包中Date發生衝突問題了。
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編譯器把包對應於文件系統的目錄管理,不只是源文件,編譯以後的字節碼文件也採用文件系統的目錄管理的。
爲了可以使用一個包中類型(類、接口、枚舉和註釋),須要在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); } }
注意 當前源文件與要使用的類型(類、接口、枚舉和註釋)在同一個包中,能夠不用引入包。
Java SE提供一些經常使用包,其中包含了Java開發中經常使用的基礎類。這些包有:java.lang、java.io、java.net、java.util、java.text、java.awt和javax.swing。
java.lang包含中包含了Java語言的核心類,如Object、Class、String、包裝類和Math等,還有包裝類Boolean、Character、Integer、Long、Float和Double。使用java.lang包中的類型,不須要顯示使用import語句引入,它是由解釋器自動引入。
java.io包含中提供多種輸入/輸出流類,如InputStream、OutputStream、Reader和Writer。還有文件管理相關類和接口,如File和FileDescriptor類以及FileFilter接口。
java.net包含進行網絡相關的操做的類,如URL、Socket和ServerSocket等。
java.util包含一些實用工具類和接口,如集合、日期和日曆相關類和接口。
java.text包中提供文本處理、日期式化和數字格式化等相關類和接口。
java.awt和javax.swing包提供了Java圖形用戶界面開發所須要的各類類和接口。java.awt提供是一些基礎類和接口,javax.swing提供了一些高級組件。
[^9]: 命名空間,也稱名字空間、名稱空間等,它表示着一個標識符(identifier)的可見範圍。一個標識符可在多個命名空間中定義,它在不一樣命名空間中的含義是互不相干的。這樣,在一個新的命名空間中可定義任何標識符,它們不會與任何已有的標識符發生衝突,由於已有的定義都處於其餘命名空間中。 ——引自於 維基百科 https://zh.wikipedia.org/wiki/命名空間
在第10章介紹字符串時就已經用到過方法重載,這一節詳細介紹一下重載。出於使用方便等緣由,在設計一個類時將具備類似功能的方法起相同的名字。例如String字符串查找方法indexOf有不少不一樣版本,如圖10-3所示:
這些相同名字的方法之因此可以在一個類中同時存在,是由於它們的方法參數列表,調用時根據參數列表調用相應重載方法。
提示 方法重載中參數列表不一樣的含義是:參數的個數不一樣或者是參數類型不一樣。另外,返回類型不能用來區分方法重載。
方法重載示例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