結構化編程
在程序設計的早期,程序用流程圖和自頂向下的方法設計。採用這種設計方法,程序員會將一個大的問題分解成更小的任務,然後爲每個更小的任務編寫一個過程(或函數)。最後,程序員會編寫一個主過程來啓動程序流程,隨後根據程序流程走向,調用想要的其它過程。這種類型的程序設計被稱爲結構化編程。現在有很多結構化編程語言被廣泛使用,最突出的就是C語言。
在結構化編程中,程序圍繞着要解決的任務來設計。編寫程序就是編寫執行特定任務的過程,過程中需要用到的數據通過過程參數傳遞到過程中。過程可以查看以及改變傳遞進來的數據,並可以將值返回給調用它的過程。
面向對象編程
OOP採用了一種完全不同的方法來開發計算機應用程序。在這種方法中,程序不是圍繞着要解決的任務來設計,而是圍繞着要解決的問題中的對象來設計。對於每個對象,我們會編寫一個類來描述對象的屬性和行爲。類是對象的描述。同樣,對象是類的實例。對象由屬性和行爲組成。屬性是對象所具有的特徵,而行爲是對象可以做的動作。對象的每個屬性被表示爲類中的一個成員變量。對象的每個行爲成爲類中的一個方法。
結構化與面向對象的區別
面向過程(結構化):數據和處理數據的方法(函數)是分開的
面向對象(OOP):數據和處理數據的方法整合在一起
Java中的類
- 類是具有相同屬性和行爲的一組對象的抽象
- 在軟件系統中,我們用類來模擬現實生活中的實體
Java中的類用關鍵字class聲明。Java源代碼文件中只能包含一公用(public)類,文件名必須與公用類的類名相同,文件擴展名爲“.java”。
注:在一個.java文件中我們可以聲明多個類,但是隻有一個類可以爲聲明爲public。源代碼文件的文件名必須與公用類的類名匹配。如果在源代碼文件中沒有公用類,文件名可以是任意的。
例:public class Employee {
}
向類中添加成員變量
- 一個類的成員變量和方法出現在類聲明的大括號中
對象的屬性成爲相關類中的成員變量。類中的一個成員變量由如下部分組成:
- 訪問修飾符。可以是public、private或protected;如果省略了訪問修飾符,將使用默認訪問修飾符。
- 數據類型。
- 成員變量名稱。成員變量名稱必須是一個有效的標識符,後面用分號結束。
public class Employee {
public String name; //姓名
public String address; //郵寄地址
public int number; //員工號
public int SSN; //社保號
public double salary; //員工的工資
}
向類中添加方法
一個對象的行爲成爲相關類中的方法。類中的一個方法典型地由如下部分組成:
- 訪問修飾符
- 返回值
- 方法名稱,必須是一個有效的標識符
- 參數列表,在括號中出現
- 方法的定義
例:
public class Employee {
public String name;
public String address;
public int number;
public int SSN;
public double salary;
public void mailCheck() {
System.out.println("郵寄支票到" + name + ",地址爲:\n" + address);
}
public double computePay() {
return salary/52;
}
}
最後,我們可以看到Employee類中包含如下內容:
- 類的名稱是Employee。
- 類有五個public成員變量。
- 類有兩個public方法。
實例化對象
在Java中,new關鍵字用於實例化一個對象。new運算符在內存中創建一個對象,並返回對新創建的對象的一個引用。只要我們的程序保留對該對象的一個引用,那麼這個對象將一直保留在內存中。
下面的語句聲明瞭一個Employee引用,並使用new關鍵字將該引用賦值給一個新的Employee對象:
|
Employee e; e = new Employee(); |
引用e指向內存中的Employee對象。運算符new爲該對象分配內存,然後將該對象的所有成員變量賦以初始值,這樣,這些成員變量就不會包含垃圾數據。
表1 一個對象的成員變量的初始值 |
|
成員變量的數據類型 |
初始值 |
byte |
0 |
short |
0 |
int |
0 |
long |
0 |
float |
0.0 |
double |
0.0 |
char |
空字符 |
boolean |
false |
任何類型的引用 |
null |
實例化對象的兩條語句可以合併爲一條語句來實現。例如:
|
Employee e = new Employee(); |
例:
Employee e1, e2;
e1 = new Employee();
e2 = e1; //有效
如圖可看出:
- e1,e2指向同一個對象,因爲實例化在堆空間中的對象只new了一下。
- 在e1中存放的是實例化 employee對象的地址
- e2 = e1就是將e1中的地址賦值給e2,所以e1和e2指向了堆中同一片地址
訪問對象的屬性和方法
當我們使用new關鍵字實例化一個對象時,系統爲會該類中的每個成員變量和方法分配內存。如果要訪問該對象的成員變量和方法,就需要使用點運算符來。
例如,如下語句聲明瞭一個Employee對象,然後修改該對象的name成員變量:
|
Employee e = new Employee(); e.name = "張三"; |
操作e.name是訪問e引用的Employee對象的name成員變量的方法。同樣,下面的語句使用點運算符調用這個特定Employee對象的mailCheck()方法:
|
e.mailCheck(); |
This引用
每個對象可以使用this關鍵字引用它本身。如果一個類的方法需要訪問該類本身的成員變量或其它方法,就應該使用this引用。
This指針在你調用本身對象裏的數據和方法的時候是默認使用this指針的,不管你寫不寫
如:
public double computePay() {
return this.salary/52;
}
這裏我們是自己添上後的代碼,實際上你不寫,在編譯的時候編譯器會給你自動添上
- 我們可以將this應用作爲參數給一個方法,通過這種方式,一個對象可以將它本身的引用傳給其它對象。
例如:
public class Pay{
public int salary;
public double computePay(int salary) {
this.salary = salary;
return this.salary;
}
}
上述代碼的意思是將傳進函數的參數salary賦值給本類中定義的salary
Java中的包
項目開發中,我們通常會編寫數目衆多的類。如果不對這些類進行分門別類的使用和存放,就像我們不使用文件夾去管理衆多的文件一樣,在使用時會很困難和不方便,也很容易出現類的命名衝突問題。Java通過引入包(package)的機制,以解決這兩個問題。
在Java中,每個類屬於一個包。包有兩個基本的用途:
- 提供了一個組織類的機制;
- 爲包中的類提供了一個命名空間。
- 在Java中,通過使用關鍵字package,可以將一個類聲明在一個包中。
- 在Java中,包不僅僅是組織類的一種機制,更重要的一個特色是包所創建的命名空間。
在同一個文件夾和包下,我們不能聲明文件名相同的文件,在我們使用包後,可以在不同包中聲明和其他包中相同類名的類,來實現不同功能。
將類添加到包中
在創建類時,使用關鍵字package就可以將類添加到包中。包聲明必須是源代碼文件中除註釋以外的第一條語句。
包創建的命名空間
包爲所有類創建了一個命名空間。如果類在一個包含中,那麼包名就成爲類名的一部分,包名作爲類名的前綴,用點運算符分隔。
例如,Employee類在payroll包中聲明。現在Employee類的全名爲:
|
payroll.Employee |
如果payroll包外的其它類想要使用Employee類,就必須在加上包名payroll。
包創建了命名空間,包名成爲類名的前綴。命名空間的用途是爲了避免兩個同名類的命名衝突。
使用import關鍵字導入其它包中的類
如果一個類要使用同一包中的其它類,就不需要使用包名。同一個包中的類可以不需要特定的語法而相互找到。
但是,如果定義的Boss類不在定義的payroll包中會怎麼樣呢?在這種情況下,Boss類必須使用如下幾種技術之一來引用位於不同包中的類:
- 使用類的全名。例如,payroll.Employee。
- 使用關鍵字import以及通配符(*)導入包。例如,"import payroll.*;"。
- 使用關鍵字import導入類本身。例如"import payroll.Employee;"。
當使用另一個包中的類時,第三種用法是直接導入類本身。代碼清單4.8中的Boss類中分別導入了另一個包中的類。
|
/* 代碼清單4.8 Boss類 演示import關鍵字的用法 */
package management; import payroll.Employee;
public class Boss{ public void payEmployee(Employee e){ e.mailCheck(); } } |
分別導入每個類要鍵入更多字,但是這種用法比使用通配符的import語句更佳。在導入通配符時,某些特殊情況下會出現不能運行或者導致命名衝突。這種情況在本書所有代碼中都不會出現,所以我們還是習慣性地使用通配符import語句。
分別導入類相對於導入整個包,沒有任何大小或者性能上的好處。二者編譯後的字節碼是相同的,因爲編譯器會移除導入語句,並且用全限定名替換所有的類名。
迄今爲止,我們已經在示例中始終使用了諸如String、System、Math和 Object等類。但是爲什麼我們沒有用import關鍵字呢?這個因爲這幾個類都是在java.lang包中,而這個包是所有源代碼文件中都要隱式導入的。
包目錄結構
將類放在一個包中時,出現兩個主要的結果:
- 包名成爲類名的一部分。
- 包名必須與相關字節碼存放的目錄一致。
換句話說,包名會影響字節碼存放的位置。例如,假如包com.lovoinfo.hr中存放了代表運輸工具型號的類,其中有個名爲Employee的類。那麼,該類的全限定名就是com.lovoinfo.hr.Employee。
- Java是對大小寫敏感的。因爲包名com.lovoinfo.hr都是小寫,所以即使操作系統對大小寫不敏感,目錄名也必須是小寫。
所需的文件結構可以用兩種方式創建:
- 我們可以手動創建目錄,並將*.java文件保存在與*.class文件相同的目錄中。然後,就可以按照常用的方式編譯*.java文件,而編譯產生的*.class文件都會放在*.java文件相同目錄中。
- 在編譯時,使用javac編譯器的-d標誌,來指定字節碼的輸出目錄。如果所需的包目錄不存在,-d標記會創建目錄,並將*.class文件放在恰當的文件夾。
這兩種用法各有優點。第一種用法方便管理硬盤上的源代碼;第二種用法在我們想把源代碼和字節碼分開的時候很方便,這在Java中部署應用程序時比較常見。
無論我們採用哪種方式,創建目錄的過程都是很容易讓人糊塗的,特別是當類不能相互找到時。
本章總結:
本章涉及的知識點總結如下:
- 結構化編程圍繞程序需要完成的任務來設計程序,而面向對象編程圍繞問題域中的對象設計程序。
- 面向對象分析和設計是判斷問題域中的對象、決定這些對象之間的關係以及每個對象的屬性和行爲的過程。
- 類是對象的描述,對象是類的實例。
- 在Java中,關鍵字class用於聲明一個類。類由成員變量和方法組成。
- 關鍵字new用於實例化一個對象。new運算符返回對新創建的對象的一個引用。對象 在內存中,直到不再有任何引用指向它。此時,對象就符合垃圾回收的條件。
- 點運算符用於與對象的一個引用一起訪問對象的成員變量和方法。
- 每個對象有一個對自身的引用,這個引用稱爲this引用。
- 包是Java中組織和管理類的一種機制,同時可以防止類命名衝突。
- 類中可以使用關鍵字import導入其他包中的類。
當我們要編譯或者執行的類引用了其它的類,但是被引用類的.class文件不在當前目錄下的時候,就需要設置環境變量CLASSPATH。