Java自動的“無用單元收集”預防儲存漏洩和其它有關動態儲存分配和解除分配的有害錯誤。Java解釋程式也執行許多執行時的檢查,諸如驗證所有陣列和串訪問是否在界限之內。下面是小編整理的關於Java語言中物件導向的特性,希望大家認真閱讀!
Java物件導向
物件導向是一種程式設計方法,或者是程式設計規範,其基本思想是使用物件、類、繼承、封裝、多型等基本概念來進行程式設計。 物件導向是一種符合人們思考習慣的思想,可以將複雜的事情簡單化,將程式設計師從執行者轉換成了指揮者
完成需求時:
• 先要去找具有所需的功能的物件來用。
• 如果該物件不存在,那麼建立一個具有所需功能的物件。
• 這樣簡化開發並提高程式碼的複用。
物件導向的開發過程其實就是不斷的建立物件,使用物件,指揮物件做事情。設計的過程其實就是在管理和維護物件之間的關係。
物件導向的特徵:
• 封裝(encapsulation)
• 繼承(inheritance)
• 多型(polymorphism)
1.封裝
概念:是指隱藏物件的屬性和實現細節,僅對外提供公共訪問方式。
好處:• 將變化隔離。• 便於使用。• 提高重用性。• 提高安全性。
封裝原則:
• 將不需要對外提供的內容都隱藏起來。
• 把屬性都隱藏,提供公共方法對其訪問。
Java中可以通過對類的成員設定一定的訪問許可權,實現類中成員的資訊隱藏。
private:類中限定為private的成員,只能被這個類本身訪問。如果一個類的構造方法宣告為private,則其它類不能生成該類的一個例項。
default:類中不加任何訪問許可權限定的成員屬於預設的(default)訪問狀態,可以被這個類本身和同一個包中的類所訪問。
protected:類中限定為protected的成員,可以被這個類本身、它的子類(包括同一個包中以及不同包中的子類)和同一個包中的所有其他的類訪問。
public:類中限定為public的成員,可以被所有的類訪問。
如下面的這個student類,就是使用了封裝,將類中的屬性name 、age和score私有化,使外部不能直接訪問他們,只能通過public型別的對他們方法進行操作。
class Student {
private String name;//宣告屬性 ,並設為私有型別,起到封裝的作用
private int age;
private int score;
public Student(String name,int age ,int score) { //建構函式,分別給name、age、score賦值
= name;// :this代本類物件的引用
= age;
e= score;
}
public String getName() { //設定getter方法,因為變數設為了私有,物件無法訪問類中的屬性,需要用getter方法獲取變數
return name;
}
public void setName(String name) { //設定setter方法,因為變數設為了私有,物件無法訪問類中的屬性,需要用setter方法給變數賦值
= name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
= age;
}
public int getScorre() {
return score;
}
public void setScorre(int score) {
e = score;
}
}
2.繼承
繼承是一種聯結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。物件的一個新類可以從現有的類中派生,這個過程稱為類繼承。
新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的`基類那裡繼承方法和例項變數,並且類可以修改或增加新的方法使之更適合特殊的需要。
子類可以直接訪問父類中的非私有的屬性和行為。通過 extends 關鍵字讓類與類之間產生繼承關係。如下:class SubDemo extends Demo{}
繼承提高了程式碼的複用性。
繼承的出現讓類與類之間產生了關係,提供了多型的前提
繼承的特點:
Java只支援單繼承,不支援多繼承。
• 一個類只能有一個父類,不可以有多個父類。
• class SubDemo extends Demo{} //這是對的
• class SubDemo extends Demo1,Demo2...//這是錯的
Java支援多層繼承(繼承體系)
• class A{}
• class B extends A{}
• class C extends B{}
定義繼承需要注意:
• 不要僅為了獲取其他類中某個功能而去繼承
• 類與類之間要有所屬關係,xx1是xx2的一種。
如:
class Ren { //父類
int age=20;
String name="wk";
public void show() {
tln("姓名:"+name+" 年齡:"+age);
}
}
class Sudents extends Ren {//子類Sudents繼承了父類Ren
int score=90;//增加了新的屬性
int age= +1;//使用super標記父類中的元素,修改了Ren中age的值
public void show() {//重寫了父類中的方法( 覆蓋時,子類方法許可權一定要大於等於父類方法許可權,靜態只能覆蓋靜態。)
tln("姓名:"+name+" 年齡:"+age+" 分數:"+ score);// Sudents繼承了Ren,所以Ren中的屬性name和age在Sudents可以直接使用
}
}
public class Preson {
public static void main(String[] args) {
Ren ren = new Ren();//宣告一個Ren物件
Sudents sudents = new Sudents();//宣告一個Sudents物件
();
();
}
}
程式執行結果是:
super和this的用法相同:this代表本類應用 ;super代表父類引用 。當子父類出現同名成員時,可以用super進行區分 ,子類要呼叫父類建構函式時,可以使用super語句。
在子類覆蓋方法中,繼續使用被覆蓋的方法可以通過super.函式名獲取。
注意:
1. 子類中所有的建構函式預設都會訪問父類中空引數的建構函式,因為每一個建構函式的第一行都有一條預設的語句 super();子類會具備父類中的資料,所以要先明確父類是如何對這些資料初始化的。當父類中沒有空引數的建構函式時,子類的建構函式 必須通過this或者super語句指定要訪問的建構函式。
2. 覆蓋時,子類方法許可權一定要大於等於父類方法許可權
靜態只能覆蓋靜態。
父類中的私有方法不可以被覆蓋。
3.被final修飾的類是一個最終類,不可以被繼承。
被final修飾的方法是一個最終方法,不可以被覆蓋。
被final修飾的變數是一個常量,只能賦值一次
內部類只能訪問被final修飾的區域性變數。
4. 繼承與過載:一是子類與父類的關係,二是過載方法的呼叫問題。
3.多型
方法的重寫、過載與動態連線構成多型性。Java只允許單繼承,這樣做雖然保證了繼承關係的簡單明瞭,但是功能上有很大的限制,所以,Java引入了多型性的概念。此外,抽象類和介面也是解決單繼承規定限制的重要手段。同時,多型也是物件導向程式設計的精髓所在。
多型性:傳送訊息給某個物件,讓該物件自行決定響應何種行為。
通過將子類物件引用賦值給超類物件引用變數來實現動態方法呼叫。
java 的這種機制遵循一個原則:當超類物件引用變數引用子類物件時,被引用物件的型別而不是引用變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。
1. 如果a是類A的一個引用,那麼,a可以指向類A的一個例項,或者說指向類A的一個子類。
2. 如果a是介面A的一個引用,那麼,a必須指向實現了介面A的一個類的例項。
要理解多型性,首先要知道什麼是“向上轉型”。
子類Cat繼承了Animal類,那麼後者就是前者是父類。
Cat c = new Cat();//例項化一個Cat的物件,
Animal a = new Cat();//定義了一個Animal型別的引用,指向新建的Cat型別的物件
由於Cat是繼承自它的父類Animal,所以Animal型別的引用是可以指向Cat型別的物件的。那麼這樣做的什麼意義是:因為子類是對父類的一個改進和擴充,所以一般子類在功能上較父類更強大,屬性較父類更獨特,
定義一個父類型別的引用指向一個子類的物件既可以使用子類強大的功能,又可以抽取父類的共性。
所以,父類型別的引用可以呼叫父類中定義的所有屬性和方法,但是對於子類中定義而父類中沒有的方法,它是無可奈何的;
同時,父類中的一個方法只有在在父類中定義而在子類中沒有重寫的情況下,才可以被父類型別的引用呼叫;
對於父類中定義的方法,如果子類中重寫了該方法,那麼父類型別的引用將會呼叫子類中的這個方法,這就是動態連線。
如這段程式:
class Father{
public void func1(){
func2();
}
public void func2(){//這是父類中的func2()方法,因為下面的子類中重寫了該方法
//所以在父類型別的引用中呼叫時,這個方法將不再有效
//取而代之的是將呼叫子類中重寫的func2()方法
tln("AAA");
}
}
class Child extends Father{
//func1(int i)是對func1()方法的一個過載
//由於在父類中沒有定義這個方法,所以它不能被父類型別的引用呼叫
//所以在下面的main方法中1(68)是不對的
public void func1(int i){
tln("BBB");
}
//func2()重寫了父類Father中的func2()方法
//如果父類型別的引用中呼叫了func2()方法,那麼必然是子類中重寫的這個方法
public void func2(){
tln("CCC");
}
}
public class PolymorphismTest {
public static void main(String[] args) {
Father child = new Child();
1();//列印結果將會是什麼?
}
}
這是個很典型的多型的例子。子類Child繼承了父類Father,並重載了父類的func1()方法,重寫了父類的func2()方法。過載後的func1(int i)和func1()不再是同一個方法,由於父類中沒有func1(int i),那麼,父類型別的引用child就不能呼叫func1(int i)方法。而子類重寫了func2()方法,那麼父類型別的引用child在呼叫該方法時將會呼叫子類中重寫的func2()。
所以程式執行結果應該是“CCC”。
實現多型,有二種方式,覆蓋(override),過載(overload)。
覆蓋,是指子類重新定義父類的虛擬函式的做法。它是覆蓋了一個方法並且對其重寫,以求達到不同的作用。在覆蓋要注意以下的幾點:
1、覆蓋的方法的標誌必須要和被覆蓋的方法的標誌完全匹配,才能達到覆蓋的效果;
2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
3、覆蓋的方法所丟擲的異常必須和被覆蓋方法的所丟擲的異常一致,或者是其子類;
4、被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,並沒有對其進行覆蓋。
過載,是指允許存在多個同名函式,而這些函式的引數表不同(或許引數個數不同,或許引數型別不同,或許兩者都不同)。它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入引數來區分這些方法,然後再呼叫時,在使用過載要注意以下的幾點:
1、在使用過載時只能通過不同的引數樣式。例如,不同的引數型別,不同的引數個數,不同的引數順序(當然,同一方法內的幾個引數型別必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));
2、不能通過訪問許可權、返回型別、丟擲的異常進行過載;
3、方法的異常型別和數目不會對過載造成影響;
4、對於繼承來說,如果某一方法在父類中是訪問許可權是priavte,那麼就不能在子類對其進行過載,如果定義的話,也只是定義了一個新方法,而不會達到過載的效果。
多型也有弊端:當父類引用指向子類物件時,雖然提高了擴充套件性,但是隻能訪問父類中具備的方法,不可以訪問子類中特有的方法。(前期不能使用後期產生的功能,即訪問的侷限性)