JAVA基礎——面向對象三大特性:封裝、繼承、多態

一、封裝

1、概念:

將類的某些信息隱藏在類內部,不允許外部程序直接訪問,而是通過該類提供的方法來實現對隱藏信息的操作和訪問。

2、好處:

  • 隻能通過規定的方法訪問數據。
  • 隱藏類的實例細節,方便修改和實現。

3、封裝的實現步驟

需要註意:對封裝的屬性不一定要通過get/set方法,其他方法也可以對封裝的屬性進行操作。當然最好使用get/set方法,比較標準。

A、訪問修飾符

從表格可以看出從上到下封裝性越來越差。

B、this關鍵字

1.this關鍵字代表當前對象

this.屬性 操作當前對象的屬性

this.方法 調用當前對象的方法。

2.封裝對象的屬性的時候,經常會使用this關鍵字。

3.當getter和setter函數參數名和成員函數名重合的時候,可以使用this區別。如:

02e9d1456bd452ad3bbbf8291a87a85f

C、Java 中的內部類

內部類( Inner Class )就是定義在另外一個類裡面的類。與之對應,包含內部類的類被稱為外部類。

那麼問題來瞭:那為什麼要將一個類定義在另一個類裡面呢?清清爽爽的獨立的一個類多好啊!!

答:內部類的主要作用如下:

1. 內部類提供瞭更好的封裝,可以把內部類隱藏在外部類之內,不允許同一個包中的其他類訪問該類。

2. 內部類的方法可以直接訪問外部類的所有數據,包括私有的數據。

3. 內部類所實現的功能使用外部類同樣可以實現,隻是有時使用內部類更方便。

內部類可分為以下幾種:

  • 成員內部類
  • 靜態內部類
  • 方法內部類
  • 匿名內部類  

二、繼承

1、繼承的概念

繼承是類與類的一種關系,是一種“is a”的關系。比如“狗”繼承“動物”,這裡動物類是狗類的父類或者基類,狗類是動物類的子類或者派生類。如下圖所示:

351741cba793c98e9b6f6d79863bf1e2

註:java中的繼承是單繼承,即一個類隻有一個父類。

2、繼承的好處

子類擁有父類的所有屬性和方法(除瞭private修飾的屬性不能擁有)從而實現瞭實現代碼的復用; 

3、語法規則,隻要在子類加上extends關鍵字繼承相應的父類就可以瞭:


A、方法的重寫

子類如果對繼承的父類的方法不滿意(不適合),可以自己編寫繼承的方法,這種方式就稱為方法的重寫。當調用方法時會優先調用子類的方法。

重寫要註意:

  1. 返回值類型
  2. 方法名
  3. 參數類型及個數

都要與父類繼承的方法相同,才叫方法的重寫。

重載和重寫的區別:

方法重載:在同一個類中處理不同數據的多個相同方法名的多態手段。

方法重寫:相對繼承而言,子類中對父類已經存在的方法進行區別化的修改。


B、繼承的初始化順序

1、初始化父類再初始化子類

2、先執行初始化對象中屬性,再執行構造方法中的初始化。

基於上面兩點,我們就知道實例化一個子類,java程序的執行順序是:

父類對象屬性初始化---->父類對象構造方法---->子類對象屬性初始化--->子類對象構造方法   

下面有個形象的圖:


C、final關鍵字

使用final關鍵字做標識有“最終的”含義。

1. final 修飾類,則該類不允許被繼承。

2. final 修飾方法,則該方法不允許被覆蓋(重寫)。

3. final 修飾屬性,則該類的該屬性不會進行隱式的初始化,所以 該final 屬性的初始化屬性必須有值,或在構造方法中賦值(但隻能選其一,且必須選其一,因為沒有默認值!),且初始化之後就不能改瞭,隻能賦值一次。

4. final 修飾變量,則該變量的值隻能賦一次值,在聲明變量的時候才能賦值,即變為常量。


D、super關鍵字

在對象的內部使用,可以代表父類對象。

1、訪問父類的屬性:super.age

2、訪問父類的方法:super.eat()

super的應用:

首先我們知道子類的構造的過程當中必須調用父類的構造方法。其實這個過程已經隱式地使用瞭我們的super關鍵字。

這是因為如果子類的構造方法中沒有顯示調用父類的構造方法,則系統默認調用父類無參的構造方法。

那麼如果自己用super關鍵字在子類裡調用父類的構造方法,則必須在子類的構造方法中的第一行。

要註意的是:如果子類構造方法中既沒有顯示調用父類的構造方法,而父類沒有無參的構造方法,則編譯出錯。

(補充說明,雖然沒有顯示聲明父類的無參的構造方法,系統會自動默認生成一個無參構造方法,但是,如果你聲明瞭一個有參的構造方法,而沒有聲明無參的構造方法,這時系統不會動默認生成一個無參構造方法,此時稱為父類有沒有無參的構造方法。)


E、Object類

Object類是所有類的父類,如果一個類沒有使用extends關鍵字明確標識繼承另一個類,那麼這個類默認繼承Object類。

Object類中的方法,適合所有子類!!!

那麼Object類中有什麼主要的方法呢?

1、toString()

a. 在Object類裡面定義toString()方法的時候返回的對象的哈希code碼(對象地址字符串)。

我們可以發現,如果我們直接用System.out.print(對象)輸出一個對象,則運行結果輸出的是對象的對象地址字符串,也稱為哈希code碼。如:

哈希碼是通過哈希算法生成的一個字符串,它是用來唯一區分我們對象的地址碼,就像我們的身份證一樣。  

b. 可以通過重寫toString()方法表示出對象的屬性。

如果我們希望輸出一個對象的時候,不是它的哈希碼,而是它的各個屬性值,那我們可以通過重寫toString()方法表示出對象的屬性。

2、equals()

a、equals()----返回值是佈爾類型。

b、默認的情況下,比較的是對象的引用是否指向同一塊內存地址-------對象實例化時,即給對象分配內存空間,該內存空間的地址就是內存地址。使用方法如:dog.equals(dog2);

c、 如果是兩個對象,但想判斷兩個對象的屬性是否相同,則重寫equals()方法。

以Dog類為例,重寫後的equals()方法如下(當然你可以根據自己想比較的屬性來重寫,這裡我以age屬性是否相同來重寫equals()方法):

上面有四個判斷,它們的含義分別是:

1.判斷地址是否相同----if (this == obj),相同則返回true

2.判斷對象是否為空----if (obj == null),為空則返回false

3.getClass()可以得到類對象,判斷類型是否一樣-----if (getClass() != obj.getClass()),不一樣則返回false

4.判斷屬性值是否一樣----if (age != other.age),不一樣返回false

5.如果地址相同,對象不為空,類型一樣,屬性值一樣則返回true

這裡要註意的是,理解obj.getClass()得到的類對象和類的對象的區別,以下用圖形表示:

可以看到,對於類對象我們關心它屬於哪個類,擁有什麼屬性和方法,比如我和你都是屬於“人”這個類對象;而類的對象則是一個類的實例化的具體的一個對象。比如我和你是兩個不同的人。

三、多態

面向對象的最後一個特性就是多態,那麼什麼是多態呢?多態就是對象的多種形態。

java裡的多態主要表現在兩個方面:

1.引用多態

父類的引用可以指向本類的對象;

父類的引用可以指向子類的對象;

這兩句話是什麼意思呢,讓我們用代碼來體驗一下,首先我們創建一個父類Animal和一個子類Dog,在主函數裡如下所示:

註意:我們不能使用一個子類的引用來指向父類的對象,如:

這裡我們必須深刻理解引用多態的意義,才能更好記憶這種多態的特性。為什麼子類的引用不能用來指向父類的對象呢?我在這裡通俗給大傢講解一下:就以上面的例子來說,我們能說“狗是一種動物”,但是不能說“動物是一種狗”,狗和動物是父類和子類的繼承關系,它們的從屬是不能顛倒的。當父類的引用指向子類的對象時,該對象將隻是看成一種特殊的父類(裡面有重寫的方法和屬性),反之,一個子類的引用來指向父類的對象是不可行的!!

2.方法多態

根據上述創建的兩個對象:本類對象和子類對象,同樣都是父類的引用,當我們指向不同的對象時,它們調用的方法也是多態的。

創建本類對象時,調用的方法為本類方法;

創建子類對象時,調用的方法為子類重寫的方法或者繼承的方法;

使用多態的時候要註意:如果我們在子類中編寫一個獨有的方法(沒有繼承父類的方法),此時就不能通過父類的引用創建的子類對象來調用該方法!!!

註意:繼承是多態的基礎。


A、引用類型轉換 

瞭解瞭多態的含義後,我們在日常使用多態的特性時經常需要進行引用類型轉換。

引用類型轉換:

1. 向上類型轉換(隱式/自動類型轉換),是小類型轉換到大類型。

就以上述的父類Animal和一個子類Dog來說明,當父類的引用可以指向子類的對象時,就是向上類型轉換。如:

2. 向下類型轉換(強制類型轉換),是大類型轉換到小類型(有風險,可能出現數據溢出)。

將上述代碼再加上一行,我們再次將父類轉換為子類引用,那麼會出現錯誤,編譯器不允許我們直接這麼做,雖然我們知道這個父類引用指向的就是子類對象,但是編譯器認為這種轉換是存在風險的。如:

那麼我們該怎麼解決這個問題呢,我們可以在animal前加上(Dog)來強制類型轉換。如:

73af078d50e45773a5bb422457e9be7b

但是如果父類引用沒有指向該子類的對象,則不能向下類型轉換,雖然編譯器不會報錯,但是運行的時候程序會出錯,如:

其實這就是上面所說的子類的引用指向父類的對象,而強制轉換類型也不能轉換!!

還有一種情況是父類的引用指向其他子類的對象,則不能通過強制轉為該子類的對象。如:   

這是因為我們在編譯的時候進行瞭強制類型轉換,編譯時的類型是我們強制轉換的類型,所以編譯器不會報錯,而當我們運行的時候,程序給animal開辟的是Dog類型的內存空間,這與Cat類型內存空間不匹配,所以無法正常轉換。這兩種情況出錯的本質是一樣的,所以我們在使用強制類型轉換的時候要特別註意這兩種錯誤!!下面有個更安全的方式來實現向下類型轉換。。。。

3. instanceof運算符,來解決引用對象的類型,避免類型轉換的安全性問題。

instanceof是Java的一個二元操作符,和==,>,<是同一類東東。由於它是由字母組成的,所以也是Java的保留關鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回boolean類型的數據。

我們來使用instanceof運算符來規避上面的錯誤,代碼修改如下:

利用if語句和instanceof運算符來判斷兩個對象的類型是否一致。

補充說明:在比較一個對象是否和另一個對象屬於同一個類實例的時候,我們通常可以采用instanceof和getClass兩種方法通過兩者是否相等來判斷,但是兩者在判斷上面是有差別的。Instanceof進行類型檢查規則是:你屬於該類嗎?或者你屬於該類的派生類嗎?而通過getClass獲得類型信息采用==來進行檢查是否相等的操作是嚴格的判斷,不會存在繼承方面的考慮;

總結:在寫程序的時候,如果要進行類型轉換,我們最好使用instanceof運算符來判斷它左邊的對象是否是它右邊的類的實例,再進行強制轉換。


B、抽象類

定義:抽象類前使用abstract關鍵字修飾,則該類為抽象類。

使用抽象類要註意以下幾點:

1. 抽象類是約束子類必須有什麼方法,而並不關註子類如何實現這些方法。

2. 抽象類應用場景:

a. 在某些情況下,某個父類隻是知道其子類應該包含怎樣的方法,但無法準確知道這些子類如何實現這些方法(可實現動態多態)。

b. 從多個具有相同特征的類中抽象出一個抽象類,以這個抽象類作為子類的模板,從而避免子類設計的隨意性。

3. 抽象類定義抽象方法,隻有聲明,不需要實現。抽象方法沒有方法體以分號結束,抽象方法必須用abstract關鍵字來修飾。如:  

4、包含抽象方法的類是抽象類。抽象類中可以包含普通的方法,也可以沒有抽象方法。如:

5、抽象類不能直接創建,可以定義引用變量來指向子類對象,來實現抽象方法。以上述的Telephone抽象類為例:     

public abstract class Telephone { public abstract void call();//抽象方法,方法體以分號結束,隻有聲明,不需要實現 public void message(){ System.out.println("我是抽象類的普通方法"); }//抽象類中包含普通的方法}

发表回复

相关推荐

显卡的发展史(四)-核弹降临

1945年四月,在一个阳光明媚的下午,美国白宫里倒下一个残疾的老人,他心有不甘,自己的任务还没能完成,但是上帝却依然要带 ...

· 6秒前

E3上的手遊:拳皇改成女性向 多款國產遊戲展出

一年一度的E3大展正在美國洛杉磯如火如荼的舉辦中。雖然E3一向以3A級大作為主,但也會有手遊亮相。今年E3,除瞭國內廠商有展...

· 15秒前

論生機與生命質量

怎樣才算有生機?基於馬斯洛的需求層次模型、三鼎學的五度修身理論和璞真山人的生命年齡論,關於生機,璞真山人提出一個生機...

· 25秒前

公元前3世纪的罗马3——破局西西里

公元前264年,罗马与迦太基的战争正式开始。然而迦太基是怎样的存在呢,在这里咱们先好好介绍下这个西地中海强权国家。

· 34秒前

广州6大服装批发市场✅新手拿货最全攻略

广州作为服装市场的一个龙头,全国各地很多二批市场都在这里打货,连锁店,实体店等也是在这里拿货,这里有最新全最潮最快的 ...

· 44秒前

Copyright 2015-2025 www.icpchaxun.com ©All Rights Reserved.