Java基礎之面向對象(封裝、繼承、多態)

一、面向對象的概念

        面向對象是程序設計的一種思想,是從面向過程編程演變而來的。舉一個例子,我們如何把大象裝冰箱裏,按照面向過程的思想來回答這個問題就是:1、把冰箱門打開;2、把大象放冰箱裏;3、把冰箱門關上;如果按照面向對象的思想來思考這個問題,我們看到的就是冰箱這一個對象,它具有打開動作、存儲動作、關閉動作,就是將這些功能封裝到冰箱這個對象中,只要我們找到冰箱這個對象,就可以執行它的打開、存儲、關閉等操作。再比如:你要買電腦,但是你不懂,但是你可以找一個懂電腦的人來幫你買電腦,這個人就是所謂的對象。懂電腦的人代表的是一類人,這裏稱之爲類,而具體幫你買電腦的可能是張三,李四等某一個人,而這某一個具體的人就被稱之爲對象。這也就是類與對象的關係。我們在編程中需要做的事情就是找到可以實現某些功能的對象來幫助我們完成某些特定的功能。而類就是JAVA語言中描述現實生活的事物,對象就是現實生活中確實存在的那個事物。

        面向對象有三大特性,封裝、繼承和多態,下面我們一一學習

二、面向對象之封裝

1、封裝的概念:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。比如說:我們的電腦的CPU,內存,顯卡,電源等裝備我們是看不到的,因爲他們都被封裝在機箱裏面了,而我們只需要按一下電腦爲我們提供的電源按鈕就可以啓動電腦爲我們工作,這樣大大的提高了設備的安全性以及使用的方便性。另外,函數就是java中最小的封裝體
2、封裝的好處:
        1、將變化隔離。對象的內部變化只在對象內部體現,我們在外部看不到
        2、便於使用。我們無需知道對象內部的構造,直接拿過來通過它對外提供的訪問方式來使用
        3、提高重用性。比如我們的機箱裏面的部件可以隨便換,但是這個機箱還是這個機箱
        4、提高安全性。不能直接使用對象的成員,通過公共方法訪問,可以在對象內部採取安全措施,避免外部錯誤操作的發生
3、封裝的原則:
        1、將不需要對外提供的內容都隱藏起來。
        2、把屬性都隱藏,提供公共方法對其訪問。

4、private關鍵字:

       封裝使用的關鍵字是private。用於修飾類中的成員(成員變量和成員方法),只能在本類中訪問,private是java語言中最低權限。私有是封裝一種體現形式。訪問類中被private修飾的成員變量的公共訪問方法,賦值函數定義爲set,取值函數定義爲get。定義在類中的成員變量,一般都會加上private。代碼如下:

	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

5、this關鍵字:
        this代表所在函數所屬對象的引用,哪個對象調用this所在的函數,this就代表哪個對象
this的應用:
        1、當定義類中功能時,該函數的內部要調用到該函數的對象時,用this來表示這個對象。但凡本類內部功能中使用到了本類對象,都用this表示
        2、用於構造函數之間相互調用
        3、this關鍵字只能定義在構造函數的第一行

6、static關鍵字

        用法:是一個修飾符,用於修飾成員(成員變量,成員函數),不能存在於方法中
        當成員被靜態修飾後,就多了一種調用方式除了可以被對象調用外,還可以直接用類名調用。類名.靜態成員

        特點:1、隨着類的加載而加載;也就是說靜態會隨着類的消失而消失,說明其生命週期最長
                   2、優先於對象存在
                   3、被所有對象共享
                   4、可以直接被類名所調用
       類變量和實例變量的區別:
       1、存放位置
            類變量隨着類的加載存在於方法區中
            實例變量隨着對象的建立而存在於堆內存中
       2、聲明週期
            類變量聲明週期最長,隨着類的消失而消失
            實例變量的聲明週期隨着對象的消失而消失
       3、主函數是靜態的
      注意事項:
       1、靜態方法只能訪問靜態成員
       2、非靜態方法既可以訪問非靜態成員,也可以訪問靜態成員
       3、靜態方法中不可以定義this、super關鍵字 因爲靜態優先於對象 所以靜態方法中不可以出現this
      靜態有利有弊:
      利:1、 對對象的共享數據進行單獨空間存儲,節省空間,
             2、可以直接被類名調用
      弊:1、生命週期過長
             2、訪問具有侷限性(靜態只能訪問靜態)

      靜態代碼塊  static{}:隨着類的加載而加載;構造代碼塊{}:隨着對象的初始化而加載,用於初始化對象,存放不同對象共性的內容

7、封裝的應用--單例設計模式

        單例設計模式的出現是爲了保證對象在內存中的唯一性。建立對象的時候,絕不可以去 new創建對象。因此我們需要在類的內部創建自己的對象,然後提供一個公共方法讓外界可以獲取此對象,無論有多少次使用,該對象只創建了一次,因此稱爲單例設計模式。單例設計模式分爲餓漢式和懶漢式:

        1、餓漢式:直接創建好自己的對象

class Single {
	private Single() {
	}

	private static Single single = new Single();

	public static Single getInstence() {
		return single;
	}
}
        2、懶漢式:當外界使用的時候才創建對象(存在安全隱患,開發不建議使用,但面試會問)
class Student {
	private Student() {
	}
	private static Student student = null;
	
	public static Student getStudent() {
		if (student == null) {
			synchronized (Student.class) {
				if (student == null) {
					student= new Student();
				}
			}
		}
		return student;
	}
}

餓漢式與懶漢式有什麼不同:

懶漢式特點在於實例的延遲加載,延遲加載在多線程訪問時會出現安全問題,可以通過加同步來解決。用同步代碼塊和同步函數都可以,但是稍微有些低效。用雙重判斷的方式可以解決這個效率問題,加同步的時候使用的鎖是該類所屬的字節碼文件對象

8、對象初始化步驟:

        Person per=new Person("lisi",20);這句話都做的什麼?
        1、因爲new用到了Person.class,所以會先找到Person.class文件並加載到內存中
        2、執行該類中的static代碼塊(如果有的話),給Person.class類進行初始化
        3、在堆內存中開闢空間,分配內存地址
        4、在堆內存中建立對象的特有屬性,並進行默認初始化
        5、對屬性進行顯示初始化
        6、對對象進行構造代碼塊{}初始化
        7、對對象進行對應的構造函數初始化
        8、將內存地址賦給棧內存中的per變量

三、面向對象之繼承

        概念:多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼那個類即可。多個類可以稱爲子類,單獨這個類稱爲父類或者超類。子類可以直接訪問父類中的非私有的屬性和行爲。通過 extends 關鍵字讓類與類之間產生繼承關係。如:

class SubDemo extends Demo{}

繼承的出現提高了代碼的複用性。繼承的出現讓類與類之間產生了關係,提供了多態的前提。

1、Java只支持單繼承,不支持多繼承。
        一個類只能有一個父類,不可以有多個父類。
        class SubDemo extends Demo{} //ok
        class SubDemo extends Demo1,Demo2...//error
2、Java支持多層繼承(繼承體系)
        class A{}
        class B extends A{}
        class C extends B{}
3、定義繼承需要注意:
        不要僅爲了獲取其他類中某個功能而去繼承;類與類之間要有所屬( " is a " )關係,xx1是xx2的一種。

4、this和super的使用

        super和this的用法相像,this代表本類對象的引用,super代表父類的內存空間的標識。當子父類出現同名成員時,可以用super進行區分;子類要調用父類構造函數時,可以使用super語句。子類中有一行隱式語句super() 會訪問父類中的空參數構造函數,子類中所有構造函數第一行都有super(),子類初始化時首先要訪問父類的構造函數 如果要訪問非默認的構造函數 則通過super(。。。)訪問

        結論:子類中所有的構造函數都會訪問父類默認的構造函數 當父類中沒有空參數的構造函數時候 必須通過super指定訪問父類中的構造函數,也可以使用this()語句訪問本類中的構造函數 子類中至少有一個構造函數訪問父類的構造函數 

        注意:this 和 super不能同時存在 因爲都得寫第一行進行初始化

5、函數覆蓋(Override)

        1>子類中出現與父類一模一樣的方法時,會出現覆蓋操作,也稱爲重寫或者複寫。
        2>父類中的私有方法不可以被覆蓋。
        3>在子類覆蓋方法中,繼續使用被覆蓋的方法可以通過super.函數名獲取。
        4>覆蓋注意事項:
             覆蓋時,子類方法權限一定要大於等於父類方法權限
             靜態只能覆蓋靜態。
        5>覆蓋的應用:
        當子類需要父類的功能,而功能主體子類有自己特有內容時,可以複寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容。

6、 final關鍵字

        1>final可以修飾類,方法,變量。
        2>final修飾的類不可以被繼承。
        3>final修飾的方法不可以被覆蓋。
        4>final修飾的變量是一個常量。只能被賦值一次。
        5>內部類只能訪問被final修飾的局部變量。

以下是繼承的使用示例代碼:

class Fu{
	Fu() {
		System.out.println("fu");
	}
	int num=4;
	void show(){
		System.out.println("dddd");
	}
}
class Zi extends Fu{
	Zi() {
		//super();子類初始化的時候會自動調用父類的構造方法
		System.out.println("zi");
	}
	int num=5;
	void show(){
		super.show();//調用父類的show方法
		System.out.println(num+"..."+super.num);
	}
	void print(){
		System.out.println("dd");
	}
}
public class ExtendsDemo {
	public static void main(String[] args) {
		Zi z=new Zi();
		z.show();
	}
}


四、面向對象之多態

概念:事物存在的多種形態
        1、多態的體現
             父類的引用指向自己子類對象
             父類的引用可以接受子類對象
        2、多態的前提
             必須是類與類之間有關係,要麼繼承要麼實現
             存在覆蓋
        3、多態的好處
             大大提高程序的擴展性
        4、多態的弊端:
             提高了擴展性,但是隻能使用父類的引用訪問父類的成員
        6、代碼中的特點
             在多態中非靜態成員函數的特點:
                 在編譯時期:參閱引用型變量所屬的類中是否有相應方法,如果有,編譯通過,否則失敗
                 在運行時期:參閱對象所屬的類中是否有調用的方法;
             簡單總結:成員函數在多態調用時 編譯看左邊 ,運行看右邊
             多態中成員變量和靜態函數 :無論編譯和運行都參考左邊,引用型變量所數的類

代碼示例:
abstract class Animal{
	abstract void eat();
}
class Cat extends Animal{
	@Override
	void eat() {
		System.out.println("喫魚");
	}
	public void catchMouse(){
		System.out.println("抓老鼠");
	}
}
class Dog extends Animal{
	@Override
	void eat() {
		System.out.println("喫骨頭");
	}
}
public class DuoTaiDemo {
	public static void main(String[] args) {
		Animal a=new Cat();
		Cat b=(Cat)a;//強制將父類的引用,轉成子類類型,向下轉型
		//千萬不要將父類對象轉換成子類類型
		eat(a);
		b.catchMouse();
	}
	public static void eat(Animal a){
		a.eat();
		if(a instanceof Cat){
			Cat c=(Cat)a;
			c.catchMouse();
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章