java面向對象三大特徵:封裝、繼承、多態

目錄

 

一、封裝(encapsulation)

封裝要點

二、繼承

三、多態(polymorphism)

多態要點


一、封裝(encapsulation)

       什麼是封裝?舉個例子,比如一臺電視機,電視機內部有複雜的各種器械,而展現在外部的只有開關和幾個按鍵。封裝可以抽象的理解爲就是那個電視機殼子,它將複雜的東西“包”起來,只保留簡單的對外接口。

       專業一點來說,封裝就是將對象的屬性和方法儘可能隱藏內部的複雜性,只保留有限的簡單的對外接口便於外界的調用。封裝的特性使得對象以外的部分不能隨意存取對象的內部數據(屬性),保證了程序和數據不受外部干擾且不被誤用,從而提高系統的可擴展性、可維護性。我們的程序設計要追求“高內聚,低耦合”,高內聚 :就是類的內部數據操作細節自己完成,不允許外部干涉;低耦合 :僅暴露少量的方法給外部使用

       那麼我們如何去實現封裝呢?實現封裝,需要使用訪問控制符,訪問控制符一共有四種,public(公共的),protected(受保護的),default/friendly(默認的/友好的),private(私有的)。

       對於類的訪問權限只有兩種:

              1、public   可被同一項目中所有的類訪問。 (必須與文件名同名) 

              2、default/friendly  可被同一個包中的類訪問

       對於類中成員(成員變量或成員方法)訪問權限共有四種:

              1、public  可以被項目中所有的類訪問。(項目可見性) 

              2、protected   可以被這個類本身訪問;同一個包中的所有其他的類訪問;被它的子類(同一個包以及不同包中的子類)訪問

              3、default/friendly  可以被這個類本身訪問;被同一個包中的類訪問。(包可見性) •

              4、private   只能被這個類本身訪問。(類可見性) 

封裝要點:

       類的屬性的處理: 

              1、一般使用private。 (除非本屬性確定會讓子類繼承)

              2、提供相應的get/set方法來訪問相關屬性。這些方法通常是public,從而提供對屬性的讀取操作。

              3、boolean變量的get方法是用:is開頭! 

              4、一些只用於本類的輔助性方法可以用private, 

              5、希望其他類調用的方法用public

接下來我們用一個程序去具體的理解封裝:
 

package cn.cou.pack;

public class TestEncapsulation {  //此類可被同一項目中所有的類訪問
	public static void main(String[] args) {

		Human h = new Human();
	      //h.age = 13;  //在此處age用不了
		h.age1 = 13;
		h.age2 = 14;
		h.age3 = 15;
                h.sayAge();
	}

}

class Human {   //此類爲默認權限default,可被同一個包中的類訪問

	private   int age;   //只在此類(Human)中可用
	          int age1;  //可被同一包中的類訪問
	protected int age2;  //可以被這個類本身訪問;同一個包中的所有其他的類訪問;被它的子類(同一個包以及不同包中的子類)訪問
	public    int age3;  //可以被項目中所有的類訪問
	
	void sayAge() {
		System.out.println(age);
	}
}

二、繼承

       java的繼承通過extends關鍵字來實現,實現繼承的類被稱爲子類,被繼承的類稱爲父類,父類和子類的繼承關係是從一般到特殊的關係,比如說,水果和蘋果的關係,蘋果繼承了水果,蘋果是水果的子類,水果是蘋果的父類。另外,extends的英文意思是“擴展”,至於爲何國內把他翻譯成繼承就不知道了,因此,我們可以理解爲,子類是父類的擴展,子類會獲得父類的全部屬性和方法,但是要注意的是子類不能獲得父類的構造方法,以及父類中被private修飾的變量或方法。

       java中只有單繼承,也就是說,一個子類只能繼承自一個父類,每個子類只有一個直接父類,不過,一個父類是可以有多個子類的,這一點可以聯想到樹形圖。java中可以通過接口實現多繼承。不過多繼承是有弊端的,多繼承會引起混亂,使得繼承鏈過於複雜,系統難於維護。就像我們現實中,如果你有多個父母親,那是一個多麼混亂的世界。多繼承,就是爲了實現代碼的複用性,卻引入了複雜性,使得系統類之間的關係混亂。 

       如果定義一個類時,沒有調用extends,則它的父類默認是:java.lang.Object。

我們沿用並加以擴展上面講述封裝時的程序,進行詳細描述:

package cn.cou.pack;

public class TestExtends {  //此類可被同一項目中所有的類訪問
	public static void main(String[] args) {
		
		Human1 h = new Human1();
	      //h.age = 13;  //在此處age用不了
		h.age1 = 13;
		h.age2 = 14;
		h.age3 = 15;
		h.sayAge();
		
		Man man = new Man();
              //man.age = 1;   // 此處age依然不可用,private修飾的age只在Human1類中可用
		man.age1 = 2;
		man.age2 = 3;
		man.age3 = 4;
		man.sayAge();
		man.work();
	}

}

class Human1 {   //此類前沒有修飾,說明爲默認權限default,可被同一個包中的類訪問
	private   int age;   //只在此類(Human1)中可用
	          int age1;  //(默認權限default)可被同一包中的類訪問
	protected int age2;  //可以被這個類本身訪問;同一個包中的所有其他的類訪問;被它的子類(同一個包以及不同包中的子類)訪問
	public    int age3;  //可以被項目中所有的類訪問
	
	void sayAge() {      //此方法前沒有修飾,說明爲默認權限default,可被同一個包中的類訪問
		System.out.println(age);
	}
}

class Man extends Human1{   //子類Man繼承父類Human1
	
	void work() {
		System.out.println("工作工作工作!!!");
	}
}

      接下來詳細的說一下,子類與父類在繼承後,變量、方法的關係:

        1、子類可以繼承父類的所有特性,但其可見性,由父類成員變量、方法的修飾符決定。

                   ①、對於被private修飾的類成員變量或方法,其子類是不可見的,也即不可訪問;

                   ②、對於定義爲默認訪問(沒有修飾符修飾)的類成員變量或方法,只有與父類同處於一個包中的子類可以訪問;

                   ③、對於定義爲public或protected 的類成員變量或方法,所有子類都可以訪問。

        2、子類中可以聲明與父類同名的成員變量,這時父類的成員變量就被隱藏起來了,在子類中直接訪問到的是子類中定義的成員變量。

        3、子類中也可以聲明與父類相同的成員方法,包括返回值類型、方法名、形式參數都應保持一致,稱爲方法的重寫(override),重寫方法不能使用比被重寫方法更嚴格的訪問權限(由於多態)。

        4、被隱藏的父類成員變量、方法是可以被引用的,通過super來實現對被隱藏或被覆蓋的父類成員的訪問。

               ①、訪問父類被隱藏的成員變量和成員方法: super.父類成員變量名

               ②、調用父類被隱藏的方法:super.父類成員方法名([參數列表])

               ③、調用父類的構造方法:super([參數列表]),需要注意到是:super( )只能在子類的構造函數中出現,並且永遠都是位於子類構造函數中的第一條語句。

下面用程序舉例說明,請詳細分析,好好理解:

package cn.cou.pack;

public class TestExtends {  //此類可被同一項目中所有的類訪問
	public static void main(String[] args) {
		
		Human h = new Human();
	      //h.age = 13;  //在此處age用不了
		h.age1 = 13;
		h.age2 = 14;
		h.age3 = 15;
		h.sayAge();
		
		Man man = new Man();
              //man.age = 1;   // 此處age依然不可用,private修飾的age只在Human類中可用
		man.age1 = 2;
		man.age2 = 3;
		man.age3 = 4;
		man.sayAge();
		man.work();
	}

}

class Human {   //此類前沒有修飾,說明爲默認權限default,可被同一個包中的類訪問
	private   int age;   //只在此類(Human)中可用
	          int age1;  //(默認權限default)可被同一包中的類訪問
	protected int age2;  //可以被這個類本身訪問;同一個包中的所有其他的類訪問;被它的子類(同一個包以及不同包中的子類)訪問
	public    int age3;  //可以被項目中所有的類訪問
	
	long number = 8000000000L;
	
	void sayAge() {      //此方法前沒有修飾,說明爲默認權限default,可被同一個包中的類訪問
		System.out.println("age1 = "+age1);
		System.out.println("fnumber = "+number);
	}
	
	Human() //父類的構造方法(每一個類都至少有一個構造方法,如果此處我們不寫,系統會默認爲我們創建一個無參的構造方法,而且不顯示)
	{
	}
}

class Man extends Human{   //子類Man繼承父類Human
	
	long number = 40000000000L;//覆蓋了父類的number變量
	
	void sayAge() //隱藏了父類的sayAge方法
	{
		System.out.println("age1 = "+age1);
		System.out.println("znumber = "+number);
	}
	
	void work() {
		System.out.println("工作工作工作!!!");
		System.out.println("super.number = "+super.number);//調用父類中被隱藏的成員變量
		
		super.sayAge();//調用父類的sayAge方法
	}
	
	Man()//子類的構造方法
	{
		super();//調用父類的構造方法
	}
}

       值得注意一點是:Object類是所有java類的根基類,如果在類的聲明中未使用extends關鍵字指明其父類,則默認父類爲Object類 ,比如上述代碼中TestExtends類,未指明其父類,則其父類就爲Object類。如果你使用的編譯軟件是eclipse,可以選中TestExtends類,點Ctrl+T,就可以查看他的繼承關係。

三、多態(polymorphism)

        多態指的是同一個方法調用,由於對象的不同可能會有不同的行爲,比如在我們現實生活中,用同一個方法比如玩,不同的對象,比如男生玩可能就是打遊戲,女生玩可能就是逛街買東西。同樣都是玩,對象不同,行爲可能就會不同。

        多態的定義格式:

                   定義格式:父類類型 變量名 = new 子類類型();

        多態的要點:

               1、多態是方法的多態,不是屬性的多態,多態與屬性無關。

               2、多態的存在要有3個必要條件:要有繼承,要有方法重寫,父類引用變量指向子類對象

               3、父類引用變量指向子類對象後,用該父類引用調用子類重寫的方法,此時就出現了多態。

       引用變量的兩種類型:

               1、編譯時類型(一般是一個父類):由聲明時的類型決定

               2、運行時類型(運行時,具體是哪個子類就是哪個子類):由實際對應的對象類型決定。 

       對象的轉型:

              父類引用變量指向子類對象,這個過程稱之爲向上轉型(子轉父),屬於自動類型轉換,向上轉型後的父類引用變量只能調用它編譯時類型的方法,不能調用它運行時類型的方法。如果想要調用它運行時類型的方法,需要進行類型的強制轉換,我們稱之爲向下轉型(父轉子),在向下轉型過程中,必須將引用變量轉成真實的子類類型(運行時類型),否則會出現類型轉換異常。

               1、向上轉型,多態本身就是向上轉型過的過程

                    使用格式:父類類型   變量名  =  new   子類類型();

                    注意: 上轉型對象不能操作子類新增的成員變量和方法,可以操作子類繼承或重寫的成員變量和方法 ,如果子類重寫了父類的某個方法,上轉型對象調用該方法時,是調用的重寫方法。 

               2、向下轉型,一個已經向上轉型的子類對象可以使用強制類型轉換的格式,將父類引用類型轉爲子類引用各類型

                    使用格式:子類類型   變量名  =(子類類型) 父類類型的變量;

       拓展:instanceof關鍵字,它的作用是用來判斷某個對象是否屬於某種數據類型。返回值類型爲布爾類型。

案例:

package cn.cou.pack;

public class TestPolymorphism {  //此類可被同一項目中所有的類訪問
	public static void main(String[] args) {
	
		Human2 h = new Human2();
		System.out.println("-----------父類:");
		h.Hu();
		h.stu();

		
		Man1 man = new Man1();
                System.out.println("-----------子類:");
                man.Hu();
                man.study();
        
        
                Human2 m = new Man1();//自動向上轉型(編譯時系統認爲 m 是Human2的類型,只有在運行時才知道是Man1的類型)
        
                System.out.println("----------子轉父:");
                m.Hu();    //調用的是子類重寫的方法
                m.stu();   //父類方法
              //m.study(); //不能使用子類新增的成員變量和方法

                if(m instanceof Man1)
                	System.out.println("m是Man1的類型");
                else
                	System.out.println("m是Human2的類型");
        
       
        
                Man1 n = (Man1) m;//強制向下轉型
        
                System.out.println("----------父轉子:");
                n.Hu();    //子類重寫的方法
                n.stu();   //父類方法
                n.study(); //子類方法
                System.out.println(n instanceof Man1);//判斷n是否是Man1的類型
	}

}


class Human2 {  
	
	void Hu() {
		System.out.println("Hu");
	}
	void stu() {
		System.out.println("學習!");
	}

	
}

class Man1 extends Human2{   //子類Man1繼承父類Human2

	
	void Hu() {   //重寫Hu方法
		System.out.println("Ma");
	}
	
	void study() {
		System.out.println("好好學習天天向上!");
	}
	
}

結果:

-----------父類:
Hu
學習!
-----------子類:
Ma
好好學習天天向上!
----------子轉父:
Ma
學習!
m是Man1的類型
----------父轉子:
Ma
學習!
好好學習天天向上!
true


 

 

       

 

 


 

 

 

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