一、封裝
封裝是一種對(duì)類的保護(hù)機(jī)制,防止該類的屬性厉颤、方法及數(shù)據(jù)被外部類隨意地訪問。因此被封裝的內(nèi)容對(duì)外部類而言應(yīng)該是隱藏的喧伞,如果外部類需要訪問它們的話走芋,必須通過該類提供的合法途徑進(jìn)行訪問绩郎。如此潘鲫,可以實(shí)現(xiàn)對(duì)類中數(shù)據(jù)的可控保護(hù)并且將內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)隱藏起來,外部只需要按要求使用即可肋杖,無需過于關(guān)心內(nèi)部細(xì)節(jié)溉仑。
1.1 將成員私有化
最直觀簡潔的封裝例子就是對(duì)類中成員變量使用private進(jìn)行封裝了,例子如下:
public class Animal {
private String name;
// 外部只能通過getter獲取name的數(shù)據(jù)
public String getName() {
return name;
}
// 外部只能通過setter修改name的數(shù)據(jù)
public void setName(String name) {
this.name = name;
}
}
1.2 使用package
使用package可以更好地組織類状植,通常也有以下的一些好處:
- 可以按照功能或者模塊將相關(guān)的類或者接口組織在同一個(gè)包中浊竟,方便查找和使用怨喘,也使系統(tǒng)代碼的邏輯易于區(qū)分。
- 包采用了樹形目錄的存儲(chǔ)方式振定,同一個(gè)包中的類名一定不同必怜,不同包中的類名可以相同,當(dāng)需要使用相同的類名時(shí)可以在類名前面加上包名來指定使用哪一個(gè)后频。
- 包的存在具有訪問權(quán)限梳庆,只有在同一包中類才能訪問彼此的default類型的成員。
1.3 使用訪問修飾符
訪問修飾符 | 本類 | 同包 | 子類 | 其它 |
---|---|---|---|---|
private | Y | N | N | N |
default | Y | Y | N | N |
protected | Y | Y | Y | N |
public | Y | Y | Y | Y |
關(guān)于protected需要重點(diǎn)說明一下卑惜,這里的子類可以訪問指的是在子類的內(nèi)部可以訪問膏执,main方法不算內(nèi)部,而在非子類中露久,即使擁有父類或者子類的引用更米,也是不能訪問父類的protected內(nèi)容的。比如:
package cn.zx.test;
public class Animal {
private String name;
String age;
protected String legs;
public String color;
}
package cn.zx.tset;
import cn.zx.test.Animal;
public class Dog extends Animal {
public Dog(){
// 可以訪問到legs
System.out.println(super.legs);
System.out.println(this.legs);
}
public static void main(String[] args) {
Animal a = new Dog();
// 以下語句編譯不通過毫痕,取不到legs
System.out.println(a.legs);
}
}
package cn.zx.tset;
import cn.zx.test.Animal;
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
// 以下語句編譯不通過征峦,取不到legs
System.out.println(a.legs);
}
}
1.4 使用this關(guān)鍵字
通過this指代當(dāng)前對(duì)象,在當(dāng)前對(duì)象內(nèi)部消请,可以通過this來訪問該對(duì)象的屬性眶痰,獲取數(shù)據(jù)并調(diào)用其方法。
比如setter和getter中的this的使用梯啤。
1.5 使用內(nèi)部類
內(nèi)部類也很好地實(shí)現(xiàn)了面向?qū)ο笾嘘P(guān)于封裝的特性竖伯,由于內(nèi)部類比較重要,單獨(dú)寫了一篇文章因宇,請(qǐng)參考《內(nèi)部類有哪些七婴?它們存在的意義是什么?》
二察滑、繼承
2.1 繼承的定義
繼承是一種描述類與類之間通用到細(xì)分打厘,抽象到具體的關(guān)聯(lián)關(guān)系。子類與父類是一種is-a
的關(guān)系贺辰,比如dog is a mammal
,jack is a human
等户盯,繼承可以更方便地描述物理世界中真實(shí)的父與子的關(guān)系,除此之外饲化,還可以將多個(gè)子類中共同的部分抽離出來形成父類莽鸭,實(shí)現(xiàn)代碼穩(wěn)定部分的封裝,也大大提高了代碼的復(fù)用性吃靠。
通常繼承在使用過程中需要注意以下幾點(diǎn):
- 子類默認(rèn)擁有父類中除了private以外的所有屬性和方法硫眨。
- 子類可以額外增加自己的屬性和方法。
- 子類可以重寫父類的方法巢块。
- 一個(gè)類只能繼承一個(gè)父類礁阁。
2.2 重寫父類方法
如果子類對(duì)從父類繼承來的方法不滿意巧号,想在里面加入適合自己的一些操作時(shí),就可以將方法進(jìn)行重寫姥闭。并且子類在調(diào)用方法中丹鸿,優(yōu)先調(diào)用子類自己的方法。
當(dāng)然在方法重寫時(shí)我們需要注意棚品,重寫的方法一定要與原父類的方法語法保持一致卜高,比如返回值類型,參數(shù)類型及個(gè)數(shù)南片,和方法名都必須一致掺涛。
2.3 父類與子類的加載順序
繼承的初始化順序是先初始化父類再初始化子類。
當(dāng)你需要在子類中訪問父類的屬性或者調(diào)用父類的方法及父類的構(gòu)造方法時(shí)疼进,可以使用super薪缆。
2.4 使用final防止繼承
final的用法非常多:
- 當(dāng)其修飾類的時(shí)候,表示該類不能被繼承伞广。
- 當(dāng)其修飾方法的時(shí)候拣帽,表示該方法不能被重寫。
- 當(dāng)其修飾類屬性的時(shí)候嚼锄,則該類屬性不會(huì)被默認(rèn)初始化减拭,而是需要手動(dòng)賦值。
- 當(dāng)其修飾變量的時(shí)候区丑,表示該變量只能賦值一次拧粪,為常量。
三沧侥、多態(tài)
多態(tài)也稱為動(dòng)態(tài)綁定可霎,是指在執(zhí)行期間才來判斷所引用對(duì)象的實(shí)際類型,再根據(jù)其實(shí)際的類型調(diào)用相應(yīng)的方法宴杀。通俗地講癣朗,只通過父類就能夠引用不同的子類,這就是多態(tài)旺罢,我們只有在運(yùn)行的時(shí)候才會(huì)知道引用變量所指向的具體實(shí)例對(duì)象旷余。
3.1 向上轉(zhuǎn)型
Animal a = new Dog()
這就是一個(gè)向上轉(zhuǎn)型豁翎,使用向上轉(zhuǎn)型扳肛,有以下需要注意的事項(xiàng):
- 我們可以使用一個(gè)父類的引用實(shí)際指向一個(gè)子類的對(duì)象,但不能反過來距芬。
- 使用向上轉(zhuǎn)型我們可以通過該引用來獲取父類的所有屬性和方法罩驻,以及子類擴(kuò)展的屬性穗酥。但無法再獲取子類擴(kuò)展的方法。
- 對(duì)于子類重寫了父類的方法的情況惠遏,該引用會(huì)優(yōu)先調(diào)用子類中重寫的方法砾跃。
具體看個(gè)例子:
public class Animal {
private String name = "plutor";
public void bark(){
System.out.println("I am " + name);
}
}
public class Dog extends Animal {
private String age = "4";
@Override
public void bark() {
super.bark();
System.out.println("my age is " + age);
}
public void sleep(){
System.out.println("sleep");
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Dog();
// 優(yōu)先使用子類中重寫的方法
a.bark();
// 無法使用子類中擴(kuò)展的方法,以下語句編譯不通過
a.sleep();
}
}
3.2 抽象類和接口
什么時(shí)候使用抽象類节吮?
- 在某些情況下抽高,某個(gè)父類只是知道其子類應(yīng)該包含怎樣的方法,但無法準(zhǔn)確知道這些子類如何實(shí)現(xiàn)這些方法透绩。也就是說抽象類是約束子類必須要實(shí)現(xiàn)哪些方法翘骂,而并不關(guān)注方法如何去實(shí)現(xiàn)。
- 從多個(gè)具有相同特征的類中抽象出一個(gè)抽象類帚豪,以這個(gè)抽象類作為子類的模板碳竟,從而避免了子類設(shè)計(jì)的隨意性。
抽象類的規(guī)則
- 用 abstract 修飾符定義抽象類狸臣。
- 用 abstract 修飾符定義抽象方法莹桅,只用聲明,不需要實(shí)現(xiàn)烛亦。
- 包含抽象方法的類就是抽象類诈泼。
- 抽象類中可以包含普通的方法,也可以沒有抽象方法煤禽。
- 抽象類的對(duì)象不能直接創(chuàng)建铐达,我們通常是定義引用變量指向子類對(duì)象。
接口比抽象類更進(jìn)一步檬果,完全不包含任何實(shí)現(xiàn)的方法體瓮孙。
- 接口不能用于實(shí)例化對(duì)象。
- 接口中所有的方法是抽象方法选脊。
- 接口中的成員變量只能是 static final 類型的衷畦。
- 接口支持多繼承,比如
public interface A extends B,C{}
知牌。