Java 學習筆記(4)——面向對象
現在一般的語言都支持面向對象,而java更是將其做到很過分的地步,java是強制使用面向對象的寫法,簡單的寫一個Hello Word都必須使用面向對象,這也是當初我很反感它的一點,當然現在也是很不喜歡它這一點。但是不得不說它設計的很優秀也很流行。
面向對象
面向對象一般是將一些獨立有相似功能的模塊封裝起來組成一個類,然後調用者不必關註實現細節而只需要關註調用某個類方法即可。面向對象簡化了程序設計。與之相對應的是面向過程,而C就是典型的面向過程的程序設計語言。
面向對象一般有3種特性:封裝、繼承、多態。這次主要講述的是java中的封裝型。
在java中類的定義與C++中類的定義類似,只是在java中每定義一個方法或者成員變量都需要在前面添加一個訪問的權限修飾符,比如下面的定義
class Student { private String name; private int age; public Student(){ } public Student(String name, int age){ this.name = name; this.age = age; } public int getAge(){ return this.age; } public String getName(){ return this.name; } public void setAge(int age){ this.age = age; } public void setName(String name){ this.name = name; } }
而C++中只需要將具有相同訪問屬性的放到一塊,用一次修飾符即可。比如上面java代碼對應的C++代碼如下:
class Student { private: string name; int age; public: Student(){ } Student(string name, int age){ this->name = name; this->age = age; } int getAge(){ return this->age; } String getName(){ return this->name; } void setAge(int age){ this->age = age; } void setName(String name){ this->name = name; } }
訪問權限
在C++中類中的成員如果不給訪問權限,默認是private, 而java中默認的訪問權限是friendly,但是這個friendly在java中並不是關鍵字,而且java中的public、private、protected 都必須明確指定,在java中這些關鍵字對應的訪問權限如下:
訪問權限 | 當前類 | 同一個package | 子孫類 | 其他package |
---|---|---|---|---|
public | yes | yes | yes | yes |
protected | yes | yes | yes | no |
firendly | yes | yes | no | no |
private | yes | no | no | no |
從上一個表中可以看到public 對於類成員的訪問完全沒有限制、而protected僅僅保護類成員不被其他包訪問,默認的friendly只允許同一個包或者同一個類的成員訪問,最後的private僅允許同一個類的成員訪問,它們的訪問權限是遞增的,也就是public > protected > friendly > private
封裝性
面向對象的封裝性就體現在僅僅允許通過類方法訪問類成員。這有助於保護類成員不被其他代碼隨意的篡改,而且如果類成員在進行修改時如果會涉及到其他變化,我們只需要在get/set方法中控制即可,不需要外部使用人員了解這個細節。
假設現在有一個教務系統,裏面需要存儲學生的信息,那麽如果不采用封裝的方式而直接在類代碼外進行訪問的話,而且成員被訪問的位置較多,一旦發現數據庫中存儲的數據發生錯誤,那麽將無法確定是在哪給定了錯誤的值,而且要對輸入值進行判斷的時候,每個被訪問的位置都要添加這些判斷的代碼,修改量較大,而且無法保證每個位置都正常修改了。如果後續業務邏輯修改,那麽這些工作又得重新做一遍。如果我們將成員變量使用set和get方法進行封裝,查看數據錯誤的問題只需要關註get/set方法,而且業務邏輯變更時只需要修改get/set方法。這點體現了封裝性對數據的保護作用。
在假設這裏我們采用多線程的方式來訪問數據,那麽為了保護數據,就需要添加相應的同步代碼,如果直接訪問,那麽每當訪問一次數據,就需要添加保護代碼。這樣就為使用人員添加了不必要的麻煩,如果我們將這些進行封裝,然後告訴使用人員,這個類是線程安全的,那麽使用人員直接調用而不用管其中的細節,後續如果我們換一種同步的方式,也不影響其他人的使用。
this關鍵字
C++中this關鍵字就是一個指針,通過eax寄存器傳入到類的成員函數中,在成員函數中,通過this + 偏移地址來定位類中所有成員。而java中this除了能像c++中那樣用於表示訪問類成員外,還有另外兩個作用
- 使用this表示調用類其他的構造函數,比如下面的代碼:
class Student {
private String name;
private int age;
public Student(){
}
public Student(String name){
this(); //調用無參構造
this.name = name;
}
public Student(String name, int age){
this(name); // 調用有一個參數的構造方法
this.age = age;
}
public int getAge(){
return this.age;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
}
- 用來表示類的對象,其實這個作用與C++中this指針的作用相同,而且二者本質也一樣,只是Java中不能直接訪問內存地址,所以這裏與C++有些許不同。
class Student {
private String name;
private int age;
public Student(){
}
public Student(String name){
this(); //調用無參構造
this.name = name;
}
public Student(String name, int age){
this(name); // 調用有一個參數的構造方法
this.age = age;
}
public int getAge(){
return this.age;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
public boolean compare(Student stu){
return this == stu; //這裏簡單實用二者的地址進行比較
}
}
構造函數與析構函數
java中的構造函數與C++中的相同。是在new對象的時候調用的函數。註意這裏只是說它在new的時候調用的函數,並不是在使用類的時候第一次調用的函數。
Java 中的構造方法必須與該類具有相同的名字,並且沒有方法的返回類型。每個類至少有一個構造方法。如果不寫一個構造方法,Java 編程語言將提供一個默認的,該構造方法沒有參數,而且方法體為空。如果一個類中已經定義了構造方法則系統不再提供默認的構造方法。
java中不能直接訪問內存,雖然它的類都是new出來的,但是資源的回收由垃圾回收機制來完成,那麽它有析構函數嗎?答案是肯定的,java中也是有析構函數的。在C++中進行棧資源回收或者手工調用delete的時候才會進行析構函數的調用。而在java中,當垃圾回收器將要釋放無用對象的內存時,先調用該對象的finalize()方法。這個finalize方法就是類的析構函數,這個方法是由Object這個基類提供的一個方法,Object子類可以選擇重寫它或者就用默認的。這個方法嚴格上應該是一個接口函數,與C++的析構並不相同。
Java 虛擬機的垃圾回收操作對程序完全是透明的,因此程序無法預料某個無用對象的finalize()方法何時被調用。
類的靜態代碼塊
上面說構造函數並不是使用類時第一個調用的函數,第一個調用的函數應該是靜態代碼塊(這個代碼塊應該不能被稱之為函數)。靜態代碼塊是第一次使用類的時候被調用,而且僅僅只調用這一次。它的定義如下:
class Student{
staic {
System.out.println("調用靜態代碼塊");
}
}
Java 學習筆記(4)——面向對象