面向?qū)ο蟪绦蛟O計-Java(第四版)課件 第5章 消息、繼承與多態(tài)_第1頁
面向?qū)ο蟪绦蛟O計-Java(第四版)課件 第5章 消息、繼承與多態(tài)_第2頁
面向?qū)ο蟪绦蛟O計-Java(第四版)課件 第5章 消息、繼承與多態(tài)_第3頁
面向?qū)ο蟪绦蛟O計-Java(第四版)課件 第5章 消息、繼承與多態(tài)_第4頁
面向?qū)ο蟪绦蛟O計-Java(第四版)課件 第5章 消息、繼承與多態(tài)_第5頁
已閱讀5頁,還剩81頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

第5章消息、繼承與多態(tài)5.1消息5.2訪問控制5.3多態(tài)機制5.4繼承機制5.5抽象類、接口與包

5.1消息

5.1.1消息的概念

面向?qū)ο蟮南到y(tǒng)中,對象間的相互作用是通過一個對象向另一個對象發(fā)送消息來體現(xiàn)的。消息就是向?qū)ο蟀l(fā)出服務請求,是對數(shù)據(jù)成員和成員方法的引用。它含有信息如下:

提供服務的對象標識——對象名、服務標識——方法名、輸入信息——實際參數(shù)、回答信息——返回值或操作結(jié)果。

消息具有三個性質(zhì):

(1)同一對象可接收不同形式的多個消息,產(chǎn)生不同的響應。

(2)相同形式的消息可以發(fā)送給不同的對象,各對象所做出的響應可以是截然不同的。

(3)消息的發(fā)送可以不考慮具體的接收者,對象可以響應消息,也可以對消息不予理會,對消息的響應并不是必須的。5.1.2公有消息和私有消息

(1)私有消息:是對象發(fā)送給自己的消息。私有消息對外是不開放的,外界不必了解它;

(2)公有消息:是外界對象向某對象發(fā)送的消息。外界對象不能向某對象發(fā)送私有消息。

5.1.3特定于對象的消息

特定于對象的消息是指將所有能支持此對象可接收消息的方法集中在一起,形成一個大消息。這些消息讓對象執(zhí)行這個方法而不管它可能做什么及怎么做。分為以下三種類型:

(1)可以返回對象內(nèi)部狀態(tài)的消息。

(2)可以改變對象內(nèi)部狀態(tài)的消息。

(3)可以做一些特定操作,改變系統(tǒng)狀態(tài)的消息。

【示例程序C5_1.java】不同類型消息的傳遞示例。給出學生的學號、名字、性別及年齡。

classStudent

{publicStringname;public

char

sex;

public

int

no;public

int

age;

Student(int

cno,Stringcname,char

csex,int

cage)

{name=cname;sex=csex;no=cno;age=cage;}

public

voidshowNo(){System.out.println("No:"+no);}

public

voidshowName(){System.out.println("Name:"+name);}

public

voidshowSex(){System.out.println("Sex:"+sex);}

public

voidshowAge(){System.out.println("age:"+age);}

}

classStudentScore

{private

int

no;private

double

score;

public

voidsendScore(int

cno,double

cscore)

{/*下面兩條語句是對象發(fā)送給自身的消息,

要求給自己

的數(shù)據(jù)成員賦值,這是一種私有消息,外界是不知道的*/

no=cno;score=cscore;

}

voidprintScore(){

System.out.println("No:"+no+"score:"+score);}

}public

classC5_1

{

public

static

voidmain(String[]args)

{

int

m;

//下面兩句發(fā)送new消息給類Student,要求創(chuàng)建st1,st2的對象

Studentst1=newStudent(101,"zhangli",'F',18);

Studentst2=newStudent(102,"hongbing",'M',17);

//發(fā)送new消息給類StudentScore,要求創(chuàng)建sc1,sc2的對象

StudentScoresc1=newStudentScore();

StudentScoresc2=newStudentScore();

/*向st1的對象發(fā)送顯示學號、名字、年齡的消息。這些消息都是公有消息。它們形成了同一對象可接收不同形式的多個消息,產(chǎn)生不同的響應*/

st1.showNo();//這條消息響應的結(jié)果是顯示st1的對象的學號

st1.showName();//顯示對象姓名的消息

st1.showAge();//顯示對象年齡的消息

st1.age=20;//修改對象的數(shù)據(jù)成員的消息,修改st1對象的年齡

m=st1.age;//返回對象的數(shù)據(jù)成員的消息,將返回消息賦給變量m

System.out.println(“m=”+m);

/*向st2的對象發(fā)送兩個顯示信息的消息,與st1的對象相同,顯示學號及名字。這些消息都是公有消息,說明了相同形式的消息可以送給不同的對象,各對象所做出的響應可以是截然不同的*/

st2.showNo();st2.showName();

/*向sc1、sc2的對象各發(fā)送一個按學號輸入成績單的消息,這些消息都是公有消息*/

sc1.sendScore(101,97);sc2.sendScore(102,84);

//向sc1、sc2的對象各發(fā)送一個打印消息,這些消息都是公有消息

sc1.printScore();sc2.printScore();

}//main

}運行結(jié)果:

5.2訪問控制

訪問控制符是一組限定類、數(shù)據(jù)成員或成員方法是否可以被其他類訪問的修飾符。通過聲明類的訪問控制符可以使整個程序結(jié)構(gòu)清晰、嚴謹,減少可能產(chǎn)生的類間干擾和錯誤。5.2.1公共訪問控制符public

Java的類是通過包的概念來組織的。定義在同一個程序文件中的所有類都屬于同一個包。處于同一個包中的類都是可見的,即可以不需任何說明而方便地互相訪問和引用。而對于不同包中的類,一般說來,它們相互之間是不可見的,當然也不可能互相引用。

當一個類被聲明為public時,只要在其他包的程序中使用import語句引入這個public類,就可以訪問和引用這個類,并創(chuàng)建這個類的對象,訪問這個類內(nèi)部可見的數(shù)據(jù)成員和引用它的可見的方法。注意:處于不同包中的public類作為整體對其他類是可見的,并不代表該類的所有數(shù)據(jù)成員和成員方法也同時對其他包中的類是可見的。只有當public類的數(shù)據(jù)成員和成員方法的訪問控制符也被聲明為public時,這個類的所有用public修飾的數(shù)據(jù)成員和成員方法才同時對其他包中的類也是可見的。

例如,把Java類庫中的標準數(shù)學函數(shù)類math和標準數(shù)學函數(shù)方法都聲明為public,以供其他的類和程序使用。

需要注意的是,數(shù)據(jù)成員和成員方法的訪問控制符被聲明為public時,會造成安全性和封裝性下降,所以一般應盡量少用。

【示例程序A.java和B.java】有無public訪問控制符的不同。

packagech52;importch51.A;public

classB{public

static

voidmain(String[]args)

{double

s1;Ap1=newA();//創(chuàng)建A類p1的對象

//p1.x1=7;x1不是公共數(shù)據(jù)成員不能訪問

p1.x2=5.2;//訪問A類p1的對象的數(shù)據(jù)成員

s1=p1.ar(8);//訪問A類p1的對象的成員方法System.out.println("p1.x2="+p1.x2+"s1="+s1);

}}packagech51;public

classA{double

x1;//友好訪問的數(shù)據(jù)成員

public

double

x2;//公共的數(shù)據(jù)成員

public

doublear(double

x)//公共的成員方法{double

s;

s=x;return

s;}}運行結(jié)果:運行結(jié)果:5.2.2缺省訪問控制符

如果一個類沒有訪問控制符,說明它具有缺省的訪問控制特性,這種缺省的訪問控制特性稱為“友好訪問”。友好訪問規(guī)定只有在同一個包中的對象才能訪問和引用這些類,因此,友好訪問又稱為包訪問性。同樣道理,類內(nèi)的數(shù)據(jù)成員和成員方法如果沒有訪問控制符來限定,那么它們同樣具有“友好訪問”的特性,它們也具有包訪問性,可以被同一個包中的其他類所訪問和引用。

【示例程序C5_2.java和ClassArea.java】缺省訪問控制符的程序示例。

在ch5包中創(chuàng)建兩個類:ClassArea類和C5_2類。其中,ClassArea是缺省訪問控制符的類,其功能是計算矩形面積;C5_2是一個公共類,在這個類中創(chuàng)建ClassArea類的實例對象ss,并訪問該對象的成員方法。public

classC5_2

{public

static

voidmain(String[]args)

{double

a=2.2,b=3.1,z;

/*在類C5_2中創(chuàng)建被訪問ClassArea類的ss的對象,并訪問對象

*的成員方法。這就是說,包中類是可見的,可以互相引用*/

ClassAreass=newClassArea();

z=ss.area(a,b);//ss引用對象的成員方法

System.out.println(“z=”+z);

}

}

classClassArea

{double

lon,wid;//數(shù)據(jù)成員的修飾符為缺省

doublearea(double

x,double

y)//成員方法的修飾符為缺省

{

double

s;

//方法內(nèi)的變量

lon=x;wid=y;s=lon*wid;//求矩形面積

return

s;

//返回面積值

}}//運行結(jié)果:z=6.8200000000000015.2.3私有訪問控制符private

用private修飾的數(shù)據(jù)成員或成員方法只能被該類自身訪問和修改,而不能被任何其他類(包括該類的子類)訪問和引用。它提供了最高的保護級別。當其他類希望獲取或修改私有成員時,需要借助于類的方法來實現(xiàn)。

【示例程序C5_3.java】同一個包的同一文件中,用private修飾的父類的數(shù)據(jù)成員不能被子類的實例對象引用,故程序中將該語句變成了注釋語句。classP1

{int

nn;private

int

n=9;//私有數(shù)據(jù)成員n

P1()//構(gòu)造方法

{nn=n++;}//可以被該類的對象自身訪問和修改

voidma()

{System.out.println("n="+n);}//可以被該類的對象自身訪問

}

public

classC5_3extendsP1//C5_3是類P1的子類

{public

static

voidmain(String[]args)

{P1m1=newP1();

System.out.println("m1.nn="+m1.nn);

//System.out.println("m1.n="+m1.n);錯,不能引用父類的私有成員

m1.ma();//可以引用P1類自身的成員方法

}

}運行結(jié)果如下:

m1.nn=9n=105.2.4保護訪問控制符protected

用protected修飾的成員變量可以被三種類引用:該類自身,與它在同一個包中的其他類以及在其他包中的該類的子類。使用protected修飾符的主要作用是允許其他包中的它的子類來訪問父類的特定屬性。

【示例程序C41.java和C42.java】當父類的數(shù)據(jù)成員用protected修飾時,其他包的子類引用該數(shù)據(jù)成員的情況。具體情況見程序中的注釋。packagech51;

public

classC41{

protected

double

x1;double

x2;

protected

doublear(double

x)

{

double

s;s=x;return

s;}

}

packagech52;

importch51.C41;

public

classC42extendsC41

{public

static

voidmain(String[]args)

{double

s1;C42p1=newC42();

p1.x1=7;//可以訪問,屬性x1是protected修飾的

s1=p1.ar(4);//可以訪問,方法ar()是protected修飾的

//p1.x2=9;錯,不能訪問,x2沒有訪問控制符,不能被另一包的實例對象訪問

System.out.println("p1.x1="+p1.x1+"s1="+s1);

}//main

}

運行結(jié)果:p1.x1=7.0s1=4.0

5.3多態(tài)機制

5.3.1多態(tài)的概念

多態(tài)是指一個程序中具有相同名字而內(nèi)容不同的方法共存的情況。這些方法同名的原因是它們的最終功能和目的都相同,但是由于在完成同一功能時可能遇到不同的具體情況,因此需要定義包含不同具體內(nèi)容的方法,來代表多種具體實現(xiàn)形式。

多態(tài)其目的是提高程序的抽象度、封閉性和簡潔性,統(tǒng)一一個或多個相關類對外的接口。

Java中提供了兩種多態(tài)機制:重載與覆蓋。5.3.2重載

當在同一類中定義了多個同名而不同內(nèi)容的成員方法時,我們稱這些方法是重載(override)的方法。重載的方法主要通過形式參數(shù)列表中參數(shù)的個數(shù)、參數(shù)的數(shù)據(jù)類型和參數(shù)的順序等方面的不同來區(qū)分。在編譯期間,Java編譯器要檢查每個方法所用的參數(shù)數(shù)目和類型,然后調(diào)用正確的方法。

【示例程序C5_5.java】加法運算重載的例子。

public

classC5_5{

static

intadd(int

a,int

b)//重載的方法1

{return(a+b);}

static

doubleadd(double

x,double

y)//重載的方法2

{return(x+y);}

static

doubleadd(double

x,double

y,double

z)//重載的方法3

{return(x+y+z);}

public

static

voidmain(String[]args)

{

System.out.println("Sumis:"+add(8.5,2.3));

System.out.println("Sumis:"+add(21,38));

System.out.println("Sumis:"+add(8.5,2.3,8.5+2.3));

}//main

}

運行結(jié)果如下:Sumis:10.8

Sumis:59

Sumis:21.65.3.3覆蓋

由于面向?qū)ο笙到y(tǒng)中的繼承機制,子類可以繼承父類的方法。但是,子類的某些特征可能與從父類中繼承來的特征有所不同,為了體現(xiàn)子類的這種個性,Java允許子類對父類的同名方法重新進行定義,即在子類中可以定義與父類中已定義的方法同名而內(nèi)容不同的方法。這種多態(tài)被稱為覆蓋(overload)。

由于覆蓋的同名方法存在于子類對父類的關系中,因此只需在方法引用時指明引用的是父類的方法還是子類的方法,就可以很容易地把它們區(qū)分開來。具體應用請參閱5.4.3節(jié)。

5.4繼承機制

5.4.1繼承的概念

繼承所表達的就是對象類之間的相交關系,它使得某類對象可以繼承另外一類對象的數(shù)據(jù)成員和成員方法。若類B繼承類A,則屬于類B的對象便具有類A的全部或部分性質(zhì)(數(shù)據(jù)屬性)和功能(操作),我們稱被繼承的類A為基類、父類或超類,而稱繼承類B為A的派生類或子類。父類與子類的層次關系如果類B具有類A的全部屬性和方法,并又具有自己特有的某些屬性和方法,則把類A稱做一般類,把類B叫做類A的特殊類。

繼承避免了對一般類和特殊類之間共同特征進行的重復描述。同時,通過繼承可以清晰地表達每一項共同特征所適應的概念范圍——在一般類中定義的屬性和操作適用于這個類本身以及它以下的每一層特殊類的全部對象。運用繼承原則使得系統(tǒng)模型更簡潔、清晰。

5.4.2繼承的特征

一般來說,繼承具有下述特征:

(1)繼承關系是傳遞的。若類C繼承類B,類B繼承類A,則類C既有從類B那里繼承下來的屬性與方法,也有從類A那里繼承下來的屬性與方法,還可以有自己新定義的屬性和方法。繼承來的屬性和方法盡管是隱式的,但仍是類C的屬性和方法。繼承是在一些比較一般的類的基礎上構(gòu)造、建立和擴充新類的最有效的手段。

(2)繼承簡化了人們對事物的認識和描述,能清晰地體現(xiàn)相關類間的層次結(jié)構(gòu)關系。

(3)繼承通過增強一致性來減少模塊間的接口和界面,大大增加了程序的易維護性。

(4)繼承提供了軟件復用功能。若類B繼承類A,那么建立類B時只需要再描述與基類(類A)不同的少量特征(數(shù)據(jù)成員和成員方法)即可。這能減小代碼和數(shù)據(jù)的冗余度,增加程序的重用性。

(5)提供多重繼承機制。從理論上來說,一個類可以是多個一般類的特殊類,它可以從多個一般類中繼承屬性與方法,這便是多重繼承。Java出于安全性和可靠性的考慮,僅支持單重繼承,而通過使用接口機制來實現(xiàn)多重繼承。

在這個模型中,“本科生”、“研究生”、“脫產(chǎn)研究生”都為單繼承,而“在職研究生”為多重繼承,因為它不僅繼承“學生”/“研究生”的屬性和行為,還繼承“教師”的屬性和行為。單重繼承與多重繼承的例子5.4.3Java用extends指明繼承關系

在Java程序設計中,繼承是通過extends關鍵字來實現(xiàn)的。在定義類時使用extends關鍵字指明新定義類的父類,新定義的類稱為指定父類的子類,這樣就在兩個類之間建立了繼承關系。這個新定義的子類可以從父類那里繼承所有非private的屬性和方法作為自己的成員。實際上,在定義一個類而不給出extends關鍵字及父類名時,默認這個類是系統(tǒng)類object的子類。

1.數(shù)據(jù)成員的繼承

子類可以繼承父類的所有非私有的數(shù)據(jù)成員。

【示例程序C5_6.java】數(shù)據(jù)成員的繼承。

classA1

{int

x=25;

private

int

z;

//不能被子類繼承的私有數(shù)據(jù)成員z

}

classC5_6extendsA1//A1是C5_6的父類,C5_6是A1的子類

{public

static

voidmain(String[]argS)

{C5_6p=newC5_6();

System.out.println(“p.x=”+p.x);

//輸出繼承來的數(shù)據(jù)成員的值

/*System.out.println(“p.z=”+p.z);錯,不能繼承private修飾的z*/

}

}//

運行結(jié)果:

p.x=252.數(shù)據(jù)成員的隱藏

數(shù)據(jù)成員的隱藏是指在子類中重新定義一個與父類中已定義的數(shù)據(jù)成員名完全相同的數(shù)據(jù)成員,即子類擁有了兩個相同名字的數(shù)據(jù)成員,一個是繼承自父類的,另一個是自己定義的。當子類引用這個同名的數(shù)據(jù)成員時,默認操作是引用它自己定義的數(shù)據(jù)成員,而把從父類那里繼承來的數(shù)據(jù)成員“隱藏”起來。當子類要引用繼承自父類的同名數(shù)據(jù)成員時,可使用關鍵字super引導。

【示例程序C5_7.java】數(shù)據(jù)成員的隱藏。

classA11

{int

x=8;}

//父類中定義了數(shù)據(jù)成員x

classC5_7extendsA11

{int

x=24;//子類中也定義了數(shù)據(jù)成員x

public

static

voidmain(String[]argS)

{

int

s1,s2;

A11p=newA11();//創(chuàng)建父類p的對象

C5_7p1=newC5_7();//創(chuàng)建子類p1的對象

s1=p.x;

s2=p1.x;

//子類對象引用自己的數(shù)據(jù)成員,把父類數(shù)據(jù)成員“隱藏”起來

System.out.println("s1="+s1);

System.out.println("s2="+s2);

}//main

}運行結(jié)果:s1=8s2=24A11類的p對象的存儲區(qū)C5_7類的p1對象的存儲區(qū)x=8父類數(shù)據(jù)成員

x=8父類數(shù)據(jù)成員,隱藏x=24子類數(shù)據(jù)成員3.成員方法的繼承

子類可以繼承父類的非私有成員方法。

【示例程序C5_8.java】成員方法的繼承。

classA2

{int

x=0,y=1;

voidMyp(){System.out.println("x="+x+"y="+y);}

private

voidPrintme()

{System.out.println("x="+x+"y="+y);}

}

public

classC5_8extendsA2

{public

static

voidmain(Stringarg[])

{

int

z=3;

C5_8p1=newC5_8();p1.Myp();

//p1.Printme();錯,不能繼承父類的private方法

}}

運行結(jié)果:x=0y=14.成員方法的覆蓋

子類可以重新定義與父類同名的成員方法,實現(xiàn)對父類方法的覆蓋(overload)。方法的覆蓋與數(shù)據(jù)成員的隱藏的不同之處在于:子類隱藏父類的數(shù)據(jù)成員只是使之不可見,父類同名的數(shù)據(jù)成員在子類對象中仍然占有自己獨立的內(nèi)存空間;子類方法對父類同名方法的覆蓋將清除父類方法占用的內(nèi)存,從而使父類方法在子類對象中不復存在。

方法的覆蓋中需要注意:子類在重新定義父類已有的方法時,應保持與父類完全相同的方法名、返回值類型和參數(shù)列表,否則就不是方法的覆蓋,而是子類定義自己特有的方法,與父類的方法無關。

【示例程序C5_9.java】成員方法的覆蓋。

classA3

{int

x=10;int

y=31;

public

voidPrintme(){System.out.println("x="+x+"y="+y);}

}

public

classC5_9extendsA3

{int

z=35;

public

voidPrintme()//子類中定義了與父類同名的成員方法,實現(xiàn)覆蓋

{System.out.println("z="+z);}

public

static

voidmain(Stringarg[])

{A3p2=newA3();

//創(chuàng)建父類p2的對象

C5_9p1=newC5_9();

//創(chuàng)建子類p1的對象

p1.Printme();//子類對象引用子類方法,覆蓋了父類的同名方法

p2.Printme();//父類對象引用父類方法

}

}

運行結(jié)果:z=35x=10y=315.4.4this與super

1.this的使用場合

當成員方法的形參名與數(shù)據(jù)成員名相同,或者成員方法的局部變量名與數(shù)據(jù)成員名相同時,在方法內(nèi)借助this來明確表示引用的是類的數(shù)據(jù)成員,而不是形參或局部變量,從而提高程序的可讀性。簡單地說,this代表了當前對象的一個引用,可將其理解為對象的另一個名字,通過這個名字可以順利地訪問對象,修改對象的數(shù)據(jù)成員,調(diào)用對象的方法。歸納起來,this的使用場合有下述三種:(1)用來訪問當前對象的數(shù)據(jù)成員,其使用形式如下:

this.數(shù)據(jù)成員

(2)用來訪問當前對象的成員方法,其使用形式如下:

this.成員方法(參數(shù))

(3)當有重載的構(gòu)造方法時,用來引用同類的其他構(gòu)造方法,其使用形式如下:

this(參數(shù))

【示例程序C5_10.java】this的使用。

classA4

{int

x=0;int

y=1;

public

voidPrintme()

{System.out.println(“x=”+x+“y=”+y);

System.out.println(“Iaman”+this.getClass().getName());

/*用this來訪問當前對象的成員方法,通過this表示當前對象,來打印當前

對象的類名。其中getClass()和getName()是系統(tǒng)類庫中提供的方法*/

}

}

public

classC5_10extendsA4

{public

static

voidmain(Stringarg[])

{C5_10p1=newC5_10();

p1.Printme();

}

}

運行結(jié)果:x=0y=1Iamanch5.C5_10

【示例程序C5_11.java】this的使用。

classAlassArea

{double

x,y;

doublearea(double

x,double

y)

{

double

s;

this.x=x;//借助this來表示引用的是類數(shù)據(jù)成員

this.y=y;s=this.x*this.y;

return

s;

}}

public

classC5_11extendsAlassArea

{public

static

voidmain(String[]args)

{

double

a=2.2,b=3.1,z;

C5_11ss=newC5_11();//創(chuàng)建ss的對象

z=ss.area(a,b);//引用父類對象的成員方法求面積

System.out.println("z="+z);

}}運行結(jié)果:z=6.820000000000001

【示例程序C5_12.java】計算圓的面積和周長。

public

classC5_12

{public

static

voidmain(String[]args)

{

double

x;Circlecir=newCircle(5.0);

x=cir.area();System.out.println("圓的面積="+x);

x=cir.perimeter();System.out.println("圓的周長="+x);

}}

classCircle

{double

r;//定義半徑

final

double

PI=3//定義圓周率

publicCircle(double

r)//類的構(gòu)造方法

{this.r=r;}//通過構(gòu)造方法給r賦值

doublearea(){return

PI*r*r;}//計算圓面積的方法

doubleperimeter()//計算圓周長的方法

{return2*(this.area()/r);}//使用this變量獲取圓的面積

}

運行結(jié)果:圓的面積=78.53981633974999

圓的周長=31.415926535899995

2.super的使用場合

super代表的就是直接父類。假設類A派生出子類B,類B又派生出自己的子類C,則B是C的直接父類,而A是C的祖先類。若子類的數(shù)據(jù)成員或成員方法名與父類的數(shù)據(jù)成員或成員方法名相同,當要調(diào)用父類的同名方法或使用父類的同名數(shù)據(jù)成員時,可用關鍵字super來指明父類的數(shù)據(jù)成員和方法。

super的使用方法:

(1)用來訪問直接父類隱藏的數(shù)據(jù)成員:super.數(shù)據(jù)成員

(2)用來調(diào)用直接父類中被覆蓋的成員方法:super.成員方法(參數(shù))

(3)用來調(diào)用直接父類的構(gòu)造方法:super(參數(shù))

【示例程序C5_13.java】super的使用。

classA5

{int

x=4;int

y=1;

public

voidprintme()

{System.out.println("x="+x+"y="+y);

System.out.println("classname:"+this.getClass().getName());

}}

public

classC5_13extendsA5

{int

x;

public

voidprintme()

{

int

z=super.x+6;//引用父類A5的數(shù)據(jù)成員

super.printme();//調(diào)用父類A5的成員方法

System.out.println("Iaman"+this.getClass().getName());

x=5;

System.out.println("z="+z+"x="+x);

//打印子類的數(shù)據(jù)成員

}public

static

voidmain(Stringarg[])

{

int

k;

A5p1=newA5();C5_13p2=newC5_13();

p1.printme();p2.printme();

//super.printme();//錯,在static方法中不能引用非static成員方法

//k=super.x+23;//錯,在static方法中不能引用非static數(shù)據(jù)成員

}}

運行結(jié)果:

x=4y=1classname:ch5.A5x=4y=1classname:ch5.C5_13Iamanch5.C5_13z=10x=55.4.5構(gòu)造方法的重載與繼承

1.構(gòu)造方法的重載

一個類的若干個構(gòu)造方法之間可以相互調(diào)用。當一個構(gòu)造方法需要調(diào)用另一個構(gòu)造方法時,可以使用關鍵字this,同時這個調(diào)用語句應該是整個構(gòu)造方法的第一條可執(zhí)行語句。使用關鍵字this來調(diào)用同類的其他構(gòu)造函數(shù)時,優(yōu)點同樣是可以最大限度地提高對已有代碼的利用程度,提高程序的抽象度和封裝性,減少程序的維護工作量。

【示例程序C5_14.java】構(gòu)造方法的重載。

classAddclass

{

public

int

x=0,y=0,z=0;

//以下是多個同名不同參數(shù)的構(gòu)造方法

Addclass(int

x){this.x=x;}//可重載的構(gòu)造方法1

Addclass(int

x,int

y)//可重載的構(gòu)造方法2

{this(x);//當前構(gòu)造方法調(diào)用可重載的構(gòu)造方法1

this.y=y;

}

Addclass(int

x,int

y,int

z)//可重載的構(gòu)造方法3

{this(x,y);

//當前構(gòu)造方法調(diào)用可重載的構(gòu)造方法2

this.z=z;

}

public

intadd(){return

x+y+z;}

}public

classC5_14

{

public

static

voidmain(String[]args)

{

Addclassp1=newAddclass(2,3,5);

Addclassp2=newAddclass(10,20);

Addclassp3=newAddclass(1);

System.out.println("x+y+z="+p1.add());

System.out.println("x+y="+p2.add());

System.out.println("x="+p3.add());

}

}

運行結(jié)果:x+y+z=10x+y=30x=12.構(gòu)造方法的繼承

子類可以繼承父類的構(gòu)造方法,構(gòu)造方法的繼承遵循以下的原則:

(1)子類無條件地繼承父類的不含參數(shù)的構(gòu)造方法。

(2)如果子類自己沒有構(gòu)造方法,則它將繼承父類的無參數(shù)構(gòu)造方法,并將這些方法作為自己的構(gòu)造方法;如果子類自己定義了構(gòu)造方法,則在創(chuàng)建新對象時,它將先執(zhí)行繼承自父類的無參數(shù)構(gòu)造方法,然后再執(zhí)行自己的構(gòu)造方法。

(3)對于父類的含參數(shù)構(gòu)造方法,子類可以通過在自己的構(gòu)造方法中使用super關鍵字來調(diào)用它,但這個調(diào)用語句必須是子類構(gòu)造方法的第一條可執(zhí)行語句。

【示例程序C5_15.java】構(gòu)造方法的繼承。

classAddclass2

{public

int

x=0,y=0,z=0;

Addclass2(int

x){this.x=x;}//父類可重載的構(gòu)造方法1

Addclass2(int

x,int

y)//父類可重載的構(gòu)造方法2

{this.x=x;this.y=y;}

Addclass2(int

x,int

y,int

z)//父類可重載的構(gòu)造方法3

{this.x=x;this.y=y;this.z=z;}

public

intadd(){return

x+y+z;}

}

public

classC5_15extendsAddclass2

{int

a=0,b=0,c=0;

C5_15(int

x){super(x);

a=x+7;}

//子類可重載的構(gòu)造方法1

C5_15(int

x,int

y)//子類可重載的構(gòu)造方法2

{super(x,y);

a=x+5;b=y+5;

}

C5_15(int

x,int

y,int

z)//子類可重載的構(gòu)造方法3

{super(x,y,z);

a=x+4;b=y+4;c=z+4;

}

public

intadd()

{System.out.println("super:x+y+z="+super.add());

return

a+b+c;

}

public

static

voidmain(String[]args)

{

C5_15p1=newC5_15(2,3,5);

C5_15p2=newC5_15(10,20);

C5_15p3=newC5_15(1);

System.out.println("a+b+c="+p1.add());

System.out.println("a+b="+p2.add());

System.out.println("a="+p3.add());

}

}

運行結(jié)果:super:x+y+z=10

a+b+c=22

super:x+y+z=30

a+b=40

super:x+y+z=1

a=85.4.6向方法傳遞對象

傳遞給方法的參數(shù)可以是表達式、對象等,傳遞給方法的參數(shù)若是變量,則只能由實參傳遞給形參,而不能由形參帶回,即它是一種單向值傳遞。也就是說,在方法的引用過程中,對于形參變量值的修改并不影響實參變量值。但是,傳遞給方法的參數(shù)若是對象,則實參與形參的對象的引用指向同一個對象,因此成員方法中對對象的數(shù)據(jù)成員的修改,會使實參對象的數(shù)據(jù)成員值也發(fā)生同樣的變化。這種參數(shù)的傳遞方式被稱為“雙向地址傳遞”。

【示例程序C5_16.java】方法中的參數(shù)是對象時的情形。

classStudent1

{publicStringName;public

int

age=16;public

int

score=0;

public

voidShowStudent(){System.out.println("Name:"+Name);

System.out.println("age:"+age);System.out.println("score:"+score);

}}

public

classC5_16{

staticvoidstudentAttributes(Student1s,StringName,int

age,int

score)

{s.Name=Name;s.age=age;s.score=score;}

public

static

voidmain(String[]args)

{Student1st1=newStudent1();//創(chuàng)建st1的對象

Student1st2=newStudent1();//創(chuàng)建st2的對象

studentAttributes(st1,"zhang",23,81);//對象st1作為實參

studentAttributes(st2,"li",24,90);//對象st2作為實參

st1.ShowStudent();//執(zhí)行此方法可發(fā)現(xiàn)st1的對象將新值帶回

st2.ShowStudent();//再次執(zhí)行此方法可發(fā)現(xiàn)st2的對象將新值帶回

}}運行結(jié)果:Name:zhangage:23score:81

Name:liage:24score:90st1對象存儲區(qū)st2對象存儲區(qū)S形參S形參Name=Age=16Score=0Showstudent(){…}Name=Age=16Score=0Showstudent(){…}雙向地址傳遞

5.4.7繼承與封裝的關系

在面向?qū)ο笙到y(tǒng)中,封裝性主要指的是對象的封裝性,即將屬于某一類的一個具體的對象封裝起來,使其數(shù)據(jù)和操作成為一個整體。引入了繼承機制,對象依然是封裝得很好的實體,其他對象與它進行通信的途徑是發(fā)送消息;

類機制是一種靜態(tài)機制,不管是基類還是派生類,對于對象來說,它仍然是一個類的實例,既可能是基類的實例,也可能是派生類的實例。因此,繼承機制的引入絲毫沒有影響對象的封裝性;繼承和封裝機制具有一定的相似性,它們都是一種共享代碼的手段。

繼承是一種靜態(tài)共享代碼的手段,通過派生類對象的創(chuàng)建,可以接受某一消息,啟動其基類所定義的代碼段,從而使基類和派生類共享這一段代碼。

封裝機制所提供的是一種動態(tài)共享代碼的手段,通過封裝,可將一段代碼定義在一個類中,在另一個類所定義的操作中,可以通過創(chuàng)建該類的實例,并向它發(fā)送消息而啟動這一段代碼,同樣也達到共享的目的。

5.5抽象類、接口與包

抽象類體現(xiàn)數(shù)據(jù)抽象的思想,是實現(xiàn)程序多態(tài)性的一種手段。接口則是Java中實現(xiàn)多重繼承的唯一途徑。包是一個更大的程序單位,主要實現(xiàn)軟件復用。

5.5.1抽象類

具有相同特征卻彼此獨立的幾個類例如:抽象類及其應用三個類都要計算面積與周長,雖然公式不同但目標相同。因此,可以為這三個類抽象出一個父類,在父類里定義圓、三角形和矩形三個類共同的數(shù)據(jù)成員及成員方法。把計算面積與周長的成員方法名放在父類給予說明,再將具體的計算公式在子類中實現(xiàn),通過父類就大概知道子類所要完成的任務,這種結(jié)構(gòu)就是抽象類的概念。

Java程序用抽象類(AbstractClass)來實現(xiàn)自然界的抽象概念。抽象類刻畫了公有行為的特征,并通過繼承機制傳送給它的派生類。在抽象類中定義的方法稱為抽象方法,這些方法只有方法頭的聲明,而用一個分號來代替方法體的定義,即只定義成員方法的接口形式,而沒有具體操作。只有派生類對抽象成員方法的重定義才真正實現(xiàn)與該派生類相關的操作。在各子類繼承了父類的抽象方法之后,再分別用不同的語句和方法體來重新定義它,形成若干個名字相同、返回值相同、參數(shù)列表也相同,目的一致但是具體實現(xiàn)有一定差別的方法。抽象類中定義抽象方法的目的是實現(xiàn)一個接口,即所有的子類對外都呈現(xiàn)一個相同名字的方法。抽象類是它的所有子類的公共屬性的集合,是包含一個或多個抽象方法的類。使用抽象類的一大優(yōu)點就是可以充分利用這些公共屬性來提高開發(fā)和維護程序的效率。對于抽象類與抽象方法的限制如下:

(1)凡是用abstract修飾符修飾的類被稱為抽象類。凡是用abstract修飾符修飾的成員方法被稱為抽象方法。

(2)抽象類中可以有零個或多個抽象方法,也可以包含非抽象的方法。

(3)抽象類中可以沒有抽象方法,但是,有抽象方法的類必須是抽象類。(4)對于抽象方法來說,在抽象類中只指定其方法名及其類型,而不書寫其實現(xiàn)代碼。

(5)抽象類可以派生子類,在抽象類派生的子類中必須實現(xiàn)抽象類中定義的所有抽象方法。

(6)抽象類不能創(chuàng)建對象,創(chuàng)建對象的工作由抽象類派生的子類來實現(xiàn)。

(7)如果父類中已有同名的abstract方法,則子類中就不能再有同名的抽象方法。

(8)?abstract不能與final并列修飾同一個類。

(9)?abstract不能與private、static、final或native并列修飾同一個方法。

【示例程序C5_17.java】抽象類的應用。

public

classC5_17{

public

static

voidmain(String[]args)

{

SquareBox=newSquare(5,15,25,25);

System.out.println("SquareArea="+Box.getArea()+"

Perimeter="+Box.getPerimeter());

Triangletri=newTriangle(5,50,8,4);

System.out.println("TriangleArea="+tri.getArea()+"

Perimeter="+tri.getPerimeter());

Circle1Oval=newCircle1(5,90,25,25);

System.out.println("CircleArea="+Oval.getArea()+"

Perimeter="+Oval.getPerimeter());

}

}

abstract

classShapes//定義一個抽象類Shapes

{

public

int

x,y;//x、y為畫圖的坐標

public

int

width,height;

publicShapes(int

x,int

y,int

width,int

height)

{this.x=x;this.y=y;

this.width=width;

this.height=height;

}

abstract

doublegetArea();//求圖形面積的抽象方法

abstract

doublegetPerimeter();//求圖形周長的抽象方法

}

classSquareextendsShapes//由抽象類Shapes派生的子類——矩形類

{

public

doublegetArea(){return(width*height);}

public

doublegetPerimeter(){return(2*width+2*height);}

publicSquare(int

x,int

y,int

width,int

height)

{super(x,y,width,height);}

}

classTriangleextendsShapes//由抽象類Shapes派生的子類——三角形類

{

public

double

c;//斜邊

public

doublegetArea(){return(0.5*width*height);}

public

doublegetPerimeter(){return(width+height+c);}

publicTriangle(int

x,int

y,int

base,int

height)

{super(x,y,base,height);

c=Math.sqrt(width*width+height*height);

}

}

classCircle1extendsShapes//由抽象類Shapes派生的子類——圓類

{

public

double

r;//半徑

public

doublegetArea(){return(r*r*Math.PI);}

public

doublegetPerimeter(){return(2*Math.PI*r);}

publicCircle1(int

x,int

y,int

width,int

height)

{super(x,y,width,height);

r=(double)width/2.0;

}

}5.5.2接口

多重繼承是指一個子類可以有多個直接父類。

Java出于安全性,不支持類間的多重繼承,而只支持單重繼承。然而在解決實際問題的過程中,僅僅依靠單重繼承并不能將復雜的問題描述清楚。因此,Java語言提供接口來實現(xiàn)多重繼承機制。

1.聲明接口

格式如下:

[修飾符]interface接口名[extends父接口名列表]

{常量數(shù)據(jù)成員聲明

抽象方法聲明

}

說明:

(1)?interface是聲明接口的關鍵字,可以把它看成一個特殊類。

(2)接口名要求符合Java標識符規(guī)定。

(3)修飾符有兩種:public和默認。public修飾的接口是公共接口,可以被所有的類和接口使用;默認修飾符的接口只能被同一個包中的其他類和接口使用。

(4)父接口名列表。接口也具有繼承性。定義一個接口時可以通過extends關鍵字聲明該接口是某個已經(jīng)存在的父接口的派生接口,它將繼承父接口的所有屬性和方法。與類的繼承不同的是,一個接口可以有一個以上的父接口,它們之間用逗號分隔。

(5)常量數(shù)據(jù)成員聲明。常量數(shù)據(jù)成員前可以有也可以沒有修飾符。修飾符是publicfinalstatic和fina1static;接口中的數(shù)據(jù)成員都是用final修飾的常量,

寫法如下:修飾符數(shù)據(jù)成員類型數(shù)據(jù)成員名=常量值

數(shù)據(jù)成員名=常量值

例如:publicfinalstaticdoublePI=3.14159;

finalstaticinta=9;

intSUM=100;(等價于finalstaticintSUM=100;)(6)抽象方法聲明。接口中的方法都是用abstract修飾的抽象方法。在接口中只能給出這些抽象方法的方法名、返回值類型和參數(shù)列表,而不能定義方法體,即這些接口僅僅是規(guī)定了一組信息交換、傳輸和處理的“接口”。

其格式如下:返回值類型方法名(參數(shù)列表);

其中,接口中的方法默認為publicabstract方法。接口中方法的方法體可以由Java語言書寫,也可以由其他語言書寫。方法體由其他語言書寫時,接口方法由native修飾符修飾。定義接口與定義類非常相似。可以把接口理解成一種特殊的類,即由常量和抽象方法組成的特殊類。一個類只能有一個父類,但是它可以同時實現(xiàn)若干個接口。把接口理解成特殊的類,那么這個類利用接口就獲得了多個父類,即實現(xiàn)了多重繼承。

接口定義僅僅是實現(xiàn)某一特定功能的對外接口和規(guī)范,而不能真正地實現(xiàn)這個功能,這個功能的真正實現(xiàn)是在“繼承”這個接口的各個類中完成的,即要由這些類來具體定義接口中各抽象方法的方法體。因而在Java中,通常把對接口功能的“繼承”稱為“實現(xiàn)”。2.定義接口注意事項

(1)接口定義用關鍵字interface,而不是用class。

(2)接口中定義的數(shù)據(jù)成員全是finalstatic修飾的,即常量。

(3)接口中沒有自身的構(gòu)造方法,所有成員方法都是抽象方法。

(4)接口也具有繼承性,可以通過extends關鍵字聲明該接口的父接口。

3.類實現(xiàn)接口的注意事項

(1)在類中,用implements關鍵字就可以調(diào)用接口。一個類若要調(diào)用多個接口,可在implements后用逗號隔開多個接口的名字。

(2)如果實現(xiàn)某接口的類不是abstract的抽象類,則在類的定義部分必須實現(xiàn)指定接口的所有抽象方法,即為所有抽象方法定義方法體,而且方法頭部分應該與接口中的定義完全一致,即有完全相同的返回值和參數(shù)列表。

(3)如果實現(xiàn)某接口的類是abstract的抽象類,則它可以不實現(xiàn)該接口所有的方法。但是對于這個抽象類的任何一個非抽象的子類而言,它們的父類所實現(xiàn)的接口中的所有抽象方法都必須有實在的方法體。這些方法體可以來自抽象的父類,也可以來自子類自身,但是不允許存在未被實現(xiàn)的接口方法。這主要體現(xiàn)了非抽象類中不能存在抽象方法的原則。

(4)接口的抽象方法的訪問限制符都已指定為public,所以類在實現(xiàn)方法時,必須顯式地使用public修飾符,否則將被系統(tǒng)警告為縮小了接口中定義的方法的訪問控制范圍。

【示例程序C5_18.java】將例C5_17.java改寫為接口程序。

public

classC5_18{

public

static

voidmain(String[]args)

{

SquareBox=newSquare(5,15,25,25);

System.out.println("SquareArea="+Box.getArea()+"Perimeter="+Box.getPerimeter());

Triangletri=newTriangle(5,50,8,4);

System.out.println("TriangleArea="+tri.getArea()+"Perimeter="+tri.getPerimeter());

CircleOval=newCircle(5,90,25,25);

System.out.println("CircleArea="+Oval.getArea()+"Perimeter="+Oval.getPerimeter());

}

}interfaceShapes//定義一個接口

{abstract

doublegetArea();//自動被定義為public

doublegetPerimeter();

}

classSquareimplementsShapes//類要實現(xiàn)接口

{public

int

x,y;

public

int

width,height;

public

doublegetArea(){return(width*height);}

public

doublegetPerimeter(){return(2*width+2*height);}

publicSquare(int

x,int

y,int

width,int

height)

{

this.x=x;

this.y=y;

this.width=width;

this.height=height;

}

}

classTriangleimplementsShapes//類要實現(xiàn)接口

{

public

int

x,y;

public

int

width,height;

public

double

c;

public

doublegetArea(){return(0.5*width*height);}

public

doublegetPerimeter(){return(width+height+c);}

publicTriangle(int

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論