java面向物件【重寫、this、super,抽象類】
第1章 繼承
1.1 繼承中方法重寫&應用
l 子父類成員方法特殊情況——覆蓋
子類中出現與父類一模一樣的方法時,會出現覆蓋操作,也稱為override重寫、複寫或者覆蓋。
class Fu
{
public void show()
{
System.out.println("Fushow");
}
}
class Zi extends Fu
{
//子類複寫了父類的show方法
publicvoid show()
{
System.out.println("Zishow");
}
}
l 方法重寫(覆蓋)的應用:
當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容。
舉例:比如手機,當描述一個手機時,它具有發簡訊,打電話,顯示來電號碼功能,後期由於手機需要在來電顯示功能中增加顯示姓名和頭像,這時可以重新定義一個類描述智慧手機,並繼承原有描述手機的類。並在新定義的類中覆蓋來電顯示功能,在其中增加顯示姓名和頭像功能。
在子類中,訪問父類中的成員方法格式:
super.父類中的成員方法();
看如下程式碼:
public class Test {
publicstatic void main(String[] args) {
newNewPhone().showNum();
}
}
//手機類
class Phone{
publicvoid sendMessage(){
System.out.println("發簡訊");
}
publicvoid call(){
System.out.println("打電話");
}
public void showNum(){
System.out.println("來電顯示號碼");
}
}
//智慧手機類
class NewPhone extends Phone{
//覆蓋父類的來電顯示號碼功能,並增加自己的顯示姓名和圖片功能
public void showNum(){
//呼叫父類已經存在的功能使用super
super.showNum();
//增加自己特有顯示姓名和圖片功能
System.out.println("顯示來電姓名");
System.out.println("顯示頭像");
}
}
1.2 方法重寫的注意事項
重寫需要注意的細節問題:
l 子類方法覆蓋父類方法,必須要保證許可權大於等於父類許可權。
class Fu(){
void show(){}
publicvoid method(){}
}
class Zi() extends Fu{
public void show(){} //編譯執行沒問題
voidmethod(){} //編譯錯誤
}
l 寫法上稍微注意:必須一模一樣:函式的返回值型別 函式名 引數列表都要一樣。
總結:當一個類是另一個類中的一種時,可以通過繼承,來繼承屬性與功能。如果父類具備的功能內容需要子類特殊定義時,進行方法重寫。
1.3 繼承中子類中出現與父類重名的成員變數
當子父類中出現了同名成員變數時,在子類中若要訪問父類中的成員變數,必須使用關鍵字super來完成。
在子類中,訪問父類中的成員變數格式:
super.父類中的成員變數
看如下程式碼:
class Fu
{
//Fu中的成員變數。
int num = 5;
}
class Zi extends Fu
{
//Zi中的成員變數
int num = 6;
voidshow()
{
//子父類中出現了同名的成員變數時
//在子類中需要訪問父類中非私有成員變數時,需要使用super關鍵字
//訪問父類中的num
System.out.println("Funum="+super.num);
//訪問子類中的num2
System.out.println("Zinum2="+this.num);
}
}
class Demo5
{
publicstatic void main(String[] args)
{
Zi z =new Zi(); //建立子類物件
z.show();//呼叫子類中的show方法
}
}
1.4 this與super
1.4.1 父類物件空間優於子類物件產生
在每次建立子類物件時,我們均會先建立父類物件,再建立其子類物件本身。目的在於子類物件中包含了其對應的父類物件空間,便可以包含其父類物件的成員,如果父類成員非private修飾,則子類可以隨意使用父類成員。
程式碼體現在子類的構造方法呼叫時,一定先呼叫父類的構造方法。
1.4.2 繼承關係圖(this與super)
當子類建立物件後,該子類物件本身可以使用this來指代,而該物件當中的父類物件空間可以使用super來指代。
如下為加入了子父類關係後的物件記憶體圖。
以Person類為例:
//定義父類
public classPerson {
privateString name;
privateint age;
publicPerson(){}
publicPerson(String name,int age) {
this.name= name;
this.age= age;
}
//get/set方法
}
//定義子類
public class Chinese extends Person{
privateString address;
publicChinese(){}
publicChinese(String name,int age,String address) {
super(name,age);
this.address= address;
}
//對address的get/set
}
//定義測試類,使用子類建立物件
public class Test{
Chinese c= new Chinese(“AngelaBaby”,18,”北京海淀區上地軟體園”);
}
1.1.1 this與super呼叫普通成員與構造方法
l 呼叫普通成員:
this.成員變數 可以訪問本類物件的成員變數
super.成員變數 可以訪問父類物件的成員變數
this.成員方法() 可以訪問本類物件的成員方法
super.成員方法() 可以訪問父類物件的成員方法
l 呼叫構造方法:
this(其他引數) 可以訪問本類其他的構造方法
super(其他引數) 可以訪問父類其他的構造方法
l 預設子類呼叫父類構造方法
子類的每個構造方法中均有預設的super(),呼叫父類的空參構造。手動呼叫父類構造會覆蓋預設的super();
第2章 抽象類
2.1 抽象類-產生
當編寫一個類時,我們往往會為該類定義一些方法,這些方法是用來描述該類的功能具體實現方式,那麼這些方法都有具體的方法體。
但是有的時候,某個父類只是知道子類應該包含怎麼樣的方法,但是無法準確知道子類如何實現這些方法。比如一個圖形類應該有一個求周長的方法,但是不同的圖形求周長的演算法不一樣。那該怎麼辦呢?
分析事物時,發現了共性內容,就出現向上抽取。會有這樣一種特殊情況,就是方法功能宣告相同,但方法功能主體不同。那麼這時也可以抽取,但只抽取方法宣告,不抽取方法主體。那麼此方法就是一個抽象方法。
如:
描述講師的行為:工作。
描述助教的行為:工作。
描述班主任的行為:工作。
講師、助教、班主任之間有共性,可以進行向上抽取。抽取它們的所屬共性型別:員工。由於講師、助教、班主任都具有工作功能,但是他們具體工作內容卻不一樣。這時在描述員工時,發現了有些功能不能夠具體描述,那麼,這些不具體的功能,需要在類中標識出來,通過java中的關鍵字abstract(抽象)修飾。
當定義了抽象函式的類也必須被abstract關鍵字修飾,被abstract關鍵字修飾的類是抽象類。
2.2 抽象類&抽象方法的定義
抽象方法定義的格式:
public abstract 返回值型別方法名(引數);
抽象類定義的格式:
abstract class 類名 {
}
看如下程式碼:
//員工
abstractclass Employee{
publicabstractvoid work();//抽象函式。需要abstract修飾,並分號;結束
}
//講師
class TeacherextendsEmployee {
publicvoid work() {
System.out.println("正在講解Java");
}
}
//助教
class AssistantextendsEmployee {
publicvoid work() {
System.out.println("正在輔導學生");
}
}
//班主任
class ManagerextendsEmployee {
publicvoid work() {
System.out.println("正在管理班級");
}
}
2.3 抽象類&抽象方法的使用
抽象類無法直接建立物件,只能被子類繼承後,建立子類物件。
子類需要繼承抽象父類並完成最終的方法實現細節(即重寫方法,完成方法體)。而此時,方法重寫不再是加強父類方法功能,而是父類沒有具體實現,子類完成了具體實現,我們將這種方法重寫也叫做實現方法。
抽象類是擁有構造方法的,其存在的意義在於對自身進行初始化,供其子類使用。
2.4 抽象類常見疑惑
l 抽象類一定是個父類,因為抽象類時不斷抽取共性需求而來的。
l 抽象類中是可以不定義抽象方法的,此時僅僅是不讓該類建立物件,用於某些特殊的設計需要。
l 設計時由具體類抽取出抽象類,而開發階段應該先定義抽象父類,再根據不同需求由父類定義子類。
第3章 綜合案例---員工類系列定義
3.1 案例介紹
某IT公司有多名員工,按照員工負責的工作不同,進行了部門的劃分(研發部員工、維護部員工)。研發部根據所需研發的內容不同,又分為JavaEE工程師、Android工程師;維護部根據所需維護的內容不同,又分為網路維護工程師、硬體維護工程師。
公司的每名員工都有他們自己的員工編號、姓名,並要做它們所負責的工作。
l 工作內容
n JavaEE工程師:員工號為xxx的xxx員工,正在研發淘寶網站
n Android工程師:員工號為xxx的xxx員工,正在研發淘寶手機客戶端軟體
n 網路維護工程師:員工號為xxx的 xxx員工,正在檢查網路是否暢通
n 硬體維護工程師:員工號為xxx的 xxx員工,正在修復印表機
請根據描述,完成員工體系中所有類的定義,並指定類之間的繼承關係。進行XX工程師類的物件建立,完成工作方法的呼叫。
3.2 案例分析
l 根據上述部門的描述,得出如下的員工體系圖
l 根據員工資訊的描述,確定每個員工都有員工編號、姓名、要進行工作。則,把這些共同的屬性與功能抽取到父類中(員工類),關於工作的內容由具體的工程師來進行指定。
n 工作內容
u JavaEE工程師:員工號為xxx的 xxx員工,正在研發淘寶網站
u Android工程師:員工號為xxx的xxx員工,正在研發淘寶手機客戶端軟體
u 網路維護工程師:員工號為xxx的 xxx員工,正在檢查網路是否暢通
u 硬體維護工程師:員工號為xxx的 xxx員工,正在修復印表機
l 建立JavaEE工程師物件,完成工作方法的呼叫
1.1 案例程式碼實現
l 根據員工體系圖,完成類的定義
定義員工類(抽象類)
publicabstractclass Employee {
private Stringid;// 員工編號
private Stringname;// 員工姓名
public String getId() {
returnid;
}
publicvoidsetId(String id) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoidsetName(String name) {
this.name =name;
}
//工作方法(抽象方法)
publicabstractvoid work();
}
l 定義研發部員工類Developer 繼承 員工類Employee
publicabstractclass DeveloperextendsEmployee {
}
l 定義維護部員工類Maintainer 繼承 員工類Employee
publicabstractclass MaintainerextendsEmployee {
}
l 定義JavaEE工程師 繼承 研發部員工類,重寫工作方法
publicclass JavaEEextendsDeveloper {
@Override
publicvoid work() {
System.out.println("員工號為 " +getId() + "的 " + getName() +"員工,正在研發淘寶網站");
}
}
l 定義Android工程師 繼承 研發部員工類,重寫工作方法
publicclass AndroidextendsDeveloper {
@Override
publicvoid work() {
System.out.println("員工號為 " +getId() + "的 " + getName() +"員工,正在研發淘寶手機客戶端軟體");
}
}
l 定義Network網路維護工程師 繼承 維護部員工類,重寫工作方法
publicclass NetworkextendsMaintainer {
@Override
publicvoid work() {
System.out.println("員工號為 " +getId() + "的 " + getName() +"員工,正在檢查網路是否暢通");
}
}
l 定義Hardware硬體維護工程師 繼承 維護部員工類,重寫工作方法
publicclass HardwareextendsMaintainer {
@Override
publicvoid work() {
System.out.println("員工號為 " +getId() + "的 " + getName() +"員工,正在修復印表機");
}
}
l 在測試類中,建立JavaEE工程師物件,完成工作方法的呼叫
publicclass Test {
publicstaticvoid main(String[]args) {
//建立JavaEE工程師員工物件
JavaEEee =newJavaEE();
//設定該員工的編號
ee.setId("000015");
//設定該員工的姓名
ee.setName("小明");
//呼叫該員工的工作方法
ee.work();
}
}