java語(yǔ)言程序設(shè)計(jì)案例教程-(5)課件_第1頁(yè)
java語(yǔ)言程序設(shè)計(jì)案例教程-(5)課件_第2頁(yè)
java語(yǔ)言程序設(shè)計(jì)案例教程-(5)課件_第3頁(yè)
java語(yǔ)言程序設(shè)計(jì)案例教程-(5)課件_第4頁(yè)
java語(yǔ)言程序設(shè)計(jì)案例教程-(5)課件_第5頁(yè)
已閱讀5頁(yè),還剩131頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第5章類的繼承5.1 類的繼承5.2 屬性的隱藏和方法的重寫5.3 類之間的層次結(jié)構(gòu)5.4 JCreater第5章 類 的 繼 承學(xué)習(xí)目標(biāo) 掌握面向?qū)ο蟪绦蛟O(shè)計(jì)中繼承的概念; 學(xué)會(huì)使用繼承機(jī)制設(shè)計(jì)Java程序; 了解Java語(yǔ)言中類的層次結(jié)構(gòu); 掌握super關(guān)鍵字的使用方法; 理解繼承機(jī)制在軟件開發(fā)中的優(yōu)點(diǎn); 掌握J(rèn)Creater編程工具的基本用法。繼承(inheritance)是一種由已有的類創(chuàng)建新類的機(jī)制,通過(guò)繼承可以實(shí)現(xiàn)類的復(fù)用。繼承是面向?qū)ο蟪绦蛟O(shè)計(jì)的主要特征之一?;局R(shí)5.1 類 的 繼 承在第1章的案例1-1程序中,定義了一個(gè)人類(People),其中定義了人的姓名(name)

2、和年齡(age)兩個(gè)屬性,并定義了一個(gè)自我介紹的方法(introduceMyself)?,F(xiàn)在,如果要開發(fā)一個(gè)學(xué)生管理系統(tǒng),就需要定義一個(gè)學(xué)生類(Student)。我們知道,“學(xué)生也是人”,也就是說(shuō)學(xué)生也具有人類的一般特性,如也有姓名和年齡。那么在學(xué)生管理系統(tǒng)中,能不能使用案例1-1中定義的人類來(lái)構(gòu)建學(xué)生類呢?這就要使用Java程序設(shè)計(jì)中的繼承來(lái)實(shí)現(xiàn)。本節(jié)介紹有關(guān)類繼承的基本知識(shí)。5.1.1 繼承的基本知識(shí)1. 繼承在設(shè)計(jì)學(xué)生管理系統(tǒng)時(shí),定義的學(xué)生類(Student)只要繼承人類(People)中已經(jīng)定義的屬性和方法,然后根據(jù)學(xué)生類的特點(diǎn),添加一些學(xué)生所特有的屬性和方法即可。這樣,就可以簡(jiǎn)化學(xué)生

3、類的定義,因?yàn)槿祟愔幸呀?jīng)定義好的屬性和方法通過(guò)繼承后,學(xué)生類便可以自動(dòng)擁有。再如,在另外一個(gè)系統(tǒng)中,如果已經(jīng)定義好了一個(gè)一般的汽車類,那么其他各種類型的汽車(如轎車、計(jì)程車和巴士),都可以從汽車類中繼承有關(guān)屬性和方法,如圖5-1所示。圖5-1 汽車類在圖5-1中,汽車類包含了所有汽車具有的公共屬性和公共方法,再定義轎車類、計(jì)程車類和巴士類時(shí),在這些類中分別添加各自特有的屬性和方法,即可完成不同汽車類的定義。圖5-1中的汽車類在面向?qū)ο蟪绦蛟O(shè)計(jì)中叫超類、基類或父類。在父類中,通常定義了一些通用的狀態(tài)與行為。圖5-1中,不論轎車、出租車還是巴士,都是汽車,故屬于汽車類的一種,這些類都繼承了汽車類的

4、屬性與行為。在面向?qū)ο蟪绦蛟O(shè)計(jì)中,由繼承而得到的類稱為子類。在使用繼承機(jī)制設(shè)計(jì)程序時(shí),可以先創(chuàng)建一個(gè)具有公有屬性的一般類,根據(jù)一般類再創(chuàng)建具有特殊屬性的新類,新類繼承一般類的狀態(tài)和行為,并根據(jù)需要增加它自己特有的狀態(tài)和行為。因此,可以通過(guò)繼承實(shí)現(xiàn)類的復(fù)用,通過(guò)類的復(fù)用來(lái)提高程序設(shè)計(jì)的效率。注意:在Java語(yǔ)言中,不支持多重繼承,即一個(gè)子類只能有一個(gè)父類。2. 在程序中實(shí)現(xiàn)類的繼承在Java程序中,實(shí)現(xiàn)類的繼承關(guān)系要使用extends關(guān)鍵字。通過(guò)繼承關(guān)系定義一個(gè)子類的一般格式是:class 子類名 extends 父類名 子類類體創(chuàng)建的子類將會(huì)繼承父類的屬性和方法,此外,我們還可以在子類中添加新

5、的屬性和方法。由于Java語(yǔ)言只支持單繼承,因此關(guān)鍵字extends后只能寫一個(gè)父類名。3. 訪問(wèn)控制一個(gè)子類是不是可以訪問(wèn)父類的所有屬性和方法呢?當(dāng)然不是。子類可以訪問(wèn)的父類成員屬性和成員方法,決定于父類成員屬性和成員方法在定義時(shí)所加的訪問(wèn)控制符。Java語(yǔ)言中成員的訪問(wèn)控制共有四種類型,除了前面章節(jié)中已經(jīng)介紹過(guò)的public和private修飾符外,還有protected修飾符和默認(rèn)訪問(wèn)狀態(tài)。 (1) public修飾符。public是公共的意思,被public修飾的成員可以被所有類訪問(wèn)。(2) private修飾符。類中被private修飾的成員,只能被這個(gè)類本身訪問(wèn),其他類(包括同一個(gè)

6、包中的類、其他包中的類和子類)都無(wú)法直接訪問(wèn)private修飾的成員。(3) 默認(rèn)訪問(wèn)狀態(tài)。如果在類的成員前沒(méi)有任何訪問(wèn)控制符,則該成員屬于默認(rèn)訪問(wèn)狀態(tài)(default)。處于默認(rèn)訪問(wèn)狀態(tài)的成員,只能被同一個(gè)包中的其他類訪問(wèn)。因此,默認(rèn)訪問(wèn)狀態(tài)的成員具有包可見性。 (4) protected修飾符。如果要讓子類能夠訪問(wèn)父類的成員,就要把父類的成員聲明為protected。另外要注意,用protected修飾的成員也可以被同一個(gè)包中的其他類訪問(wèn)。在程序設(shè)計(jì)中,確定一個(gè)成員用什么訪問(wèn)控制符修飾,要視具體情況而定。如果是類中對(duì)外提供的接口,就要使用public修飾;如果是不希望被外界訪問(wèn)的成員變量和

7、方法,應(yīng)當(dāng)用private修飾;如果是子類中可以訪問(wèn)的成員,則要用protected修飾;如果是該類所在包中的其他類可以訪問(wèn)的成員,則要用默認(rèn)訪問(wèn)狀態(tài)(一個(gè)成員一般應(yīng)盡量少用默認(rèn)訪問(wèn)狀態(tài))。對(duì)上述訪問(wèn)控制符作用范圍的總結(jié)如表5-1所示。表5-1 訪問(wèn)控制符的作用范圍下面通過(guò)一個(gè)示例說(shuō)明訪問(wèn)控制符的用法。如圖5-2所示,定義了兩個(gè)包,包名分別為one和two,包one中有一個(gè)類E,類E中定義了4個(gè)屬性,分別用不同的訪問(wèn)控制符修飾。包two中定義了4個(gè)類,類A中定義了4個(gè)具有不同訪問(wèn)控制符修飾的屬性,類B繼承了同一個(gè)包中的類A,類C繼承了不同包中的類E,類D中定義了一個(gè)主方法main。圖5-2 訪

8、問(wèn)控制符示例one包中的類E定義如下:01 /定義一個(gè)包one02 /程序名為E.java03 package one;04 public class E05 private int w = 1;06 public int x = 2;07 int y = 3;08 protected int z = 4;09 two包中定義的類A、B、C和D如下:01 /定義一個(gè)包two02 /程序名為D.java03 package two;04 import one.*;05 06 class A07 private int a = 10;08 public int b = 20;09 int c =

9、30;10 protected int d = 40;11 12 13 class B extends A /類B繼承了同一個(gè)包two中的類A14 void showA()15 /System.out.println(a); /a是父類A的私有成員,子類不能訪問(wèn)16 System.out.println(b); /b是父類A的公共成員,子類可以訪問(wèn)17 System.out.println(c); /c是父類A的默認(rèn)訪問(wèn)成員,可以被同一個(gè)包中的子類訪問(wèn)18 System.out.println(d);/d是父類A的保護(hù)成員,子類可以訪問(wèn)19 21 22 class C extends E /類

10、C繼承了不同包中的類E,類E在one包中23 void showE()24 /System.out.println(w); /w是父類E的私有成員,子類不能訪問(wèn)25 System.out.println(x); /x是父類E的公共成員,子類可以訪問(wèn)26 /System.out.println(y); /y是父類E的默認(rèn)訪問(wèn)成員,不能被不同包中的子類訪問(wèn)27 System.out.println(z); /z是父類E的保護(hù)成員,子類可以訪問(wèn)28 29 30 class D31 public static void main(String args)32 33 A a1 = new A();/在類

11、D中實(shí)例化一個(gè)同包中類A的實(shí)例34 /System.out.println(a1.a);/a是類A的私有成員,不能被其他類訪問(wèn)35 System.out.println(a1.b); /b是類A的公共成員,可以被其他類訪問(wèn)36 System.out.println(a1.c); /c是類A的默認(rèn)訪問(wèn)成員,可以被同一個(gè)包中的類訪問(wèn)37 System.out.println(a1.d); /d是類A的保護(hù)成員,可以被同一個(gè)包中的類訪問(wèn)3839 B b1 = new B();40 b1.showA();41 42 C c1 = new C();43 c1.showE();44 45 E e1 = n

12、ew E();/在類D中實(shí)例化一個(gè)不同包中類E的實(shí)例46 /System.out.println(e1.w);/w是類E的私有成員,不能被其他類訪問(wèn)47 System.out.println(e1.x); /x是類E的公共成員,可以被其他類訪問(wèn)48 /System.out.println(e1.y); /y是類E的默認(rèn)訪問(wèn)成員,不能被不同包中的類訪問(wèn)49 /System.out.println(e1.z); /z是類E的保護(hù)成員,不能被不同包中的類訪問(wèn)50 51 請(qǐng)讀者仔細(xì)分析程序中語(yǔ)句的注釋,用心體會(huì)訪問(wèn)控制符的功能。程序中,注釋掉了類中不能被訪問(wèn)的其他類的屬性。用下列命令分別編譯程序E.j

13、ava和D.java:javac -d . E.javajavac -d . D.java用下列命令執(zhí)行編譯后的程序:java two.D仔細(xì)分析程序的運(yùn)行結(jié)果,看與自己分析的結(jié)果是否一致。 5.1.2 【案例5-1】 定義學(xué)生類1. 案例描述在開發(fā)一個(gè)學(xué)生管理系統(tǒng)時(shí),要定義一個(gè)學(xué)生類。學(xué)生類除了有姓名和年齡屬性外,還有學(xué)號(hào)和成績(jī)等屬性,學(xué)生類中要求有定義自我介紹的方法(即要有一個(gè)輸出學(xué)生信息的方法)。 2. 案例效果案例程序的執(zhí)行效果如圖5-3所示。圖5-3 案例5-1的顯示效果 3. 技術(shù)分析在第1章案例1-1中定義的人類(People)已經(jīng)有姓名(name)和年齡(age)兩個(gè)屬性,還定

14、義了一個(gè)自我介紹的方法(introduceMyself)。因此,在定義學(xué)生類(Student)時(shí),可以繼承People類,這樣只要在Student類中添加學(xué)生特有的屬性和方法即可。 4. 程序解析下面是學(xué)生類的定義,為了測(cè)試學(xué)生類,在學(xué)生類中定義了一個(gè)主方法(main)。程序如下:01 /*02 /案例:5-1 03 /程序名:Student.java04 /功能:定義學(xué)生類 05 /*06 07 class People08 String name;09 int age;10 11 void introduceMyself( )12 System.out.println(-);13 Syst

15、em.out.println(My name is +name+.);14 System.out.println(I am +age+ years old.);15 16 17 18 /學(xué)生類19 class Student extends People20 String stuNo; /學(xué)號(hào)21 int java; /java語(yǔ)言成績(jī)22 23 void introduceMyself()24 System.out.println(-);25 System.out.println(My name is +name+.);26 System.out.println(I am +age+ yea

16、rs old.);27 /roduceMyself();28 System.out.println(我的學(xué)號(hào)是 + stuNo + .);29 System.out.println(我的Java語(yǔ)言成績(jī)是 + java + .);30 31 32 public static void main(String args)33 Student s1 = new Student();34 = liping;35 s1.age = 21;36 s1.stuNo = 20070901;37 s1.java = 89;38 roduceMyself();394

17、0 為了便于解釋,在該程序代碼中將案例1-1中定義的People類也寫入了源程序中,其實(shí),當(dāng)People類和Student類在同一個(gè)包中時(shí),源程序中只要定義Student類就可以了。該程序的第19行定義了Student類,該類使用關(guān)鍵字extends繼承了People類。在20行和21行定義了學(xué)生的兩個(gè)屬性:學(xué)號(hào)和Java語(yǔ)言成績(jī)。在2330行定義了一個(gè)方法introduceMyself,該方法進(jìn)行學(xué)生的自我介紹,其中方法的前3行與People類中定義的introduceMyself方法的功能完全相同。 3239行定義了一個(gè)測(cè)試Student的主方法,該方法的33行實(shí)例化了一個(gè)學(xué)生類型的對(duì)象s

18、1。34行和35行中使用了從父類中繼承而來(lái)的name屬性和age屬性。36行和37行中的stuNo屬性和java屬性則是學(xué)生類中定義的新屬性。38行調(diào)用了在學(xué)生類中定義的方法introduceMyself,用來(lái)輸出學(xué)生的信息。5.1.3 【相關(guān)知識(shí)】 類的修飾符在定義類中的屬性和方法時(shí),根據(jù)需要可以加訪問(wèn)修飾符。在定義一個(gè)類時(shí),根據(jù)需要也可以加修飾符。類的修飾符分4種情況: 類定義前面沒(méi)有任何修飾符:這樣的類只能被同一個(gè)包中的其他類訪問(wèn),即類具有包(package)訪問(wèn)特性。 public修飾符:用public修飾的類可以被同一個(gè)包中的其他類或不同包的其他類訪問(wèn)。 final修飾符:用fina

19、l修飾的類不允許被繼承(在5.3節(jié)介紹)。 abstract修飾符:用abstract修飾的類不能實(shí)例化對(duì)象,只能用于繼承(在第6章介紹)。有時(shí)需要將public和final組合使用,如在Java API中有一個(gè)非常重要的類java.lang.System,該類關(guān)系到系統(tǒng)的一些控制信息,如果被子類修改,則有可能造成錯(cuò)誤。所以,該類被定義成如下的格式:public final class System extends Object 讀者可以查看JDK幫助,System類前面的public表示任何一個(gè)類可以訪問(wèn)該類(本書中的每個(gè)案例在輸出信息時(shí)就使用了該類),final表示不能被繼承(即該類沒(méi)有其

20、它子類)。關(guān)于public修飾符要注意以下幾個(gè)問(wèn)題:(1) 一個(gè)源程序文件里,只能有一個(gè)被public修飾的類。(2) 當(dāng)一個(gè)程序文件中定義了多個(gè)類時(shí),文件名必須與public修飾的類名一致,并且文件名中字母的大小寫也要與類名一樣。(3) 一個(gè)類要使用其他包中被public修飾的類時(shí),應(yīng)使用import語(yǔ)句引入該類;也可以使用長(zhǎng)類名的方式,如java.awt.Button,表示使用java.awt包中的Button類。(4) 其他包中的非公共類是不能使用的。例如,下面是包p1中定義的ClassA類,程序名為ClassA.java(注意ClassA是一個(gè)非公共類):package p1;clas

21、s ClassAint a;下面是引用p1包中ClassA類的ClassB類(注意,這兩個(gè)類不在同一個(gè)包中),程序名為ClassB.java,ClassB類在包p2中:package p2;import p1.ClassA;class ClassBClassA a;用下面的命令編譯ClassA類:javac d . ClassA.javaClassA類可以被正確編譯,然后用下面的命令編譯ClassB類:javac d . ClassB.javaClassB類在編譯時(shí),出現(xiàn)如下的編譯錯(cuò)誤:ClassB.java:2: p1.ClassA 在 p1 中不是公共的;無(wú)法從外部軟件包中對(duì)其進(jìn)行訪問(wèn)im

22、port p1.ClassA; 1 錯(cuò)誤該錯(cuò)誤信息的含義是,ClassB.java程序的第2行發(fā)生錯(cuò)誤,錯(cuò)誤的原因是p1.ClassA類不是公共類,不能被不同的包引用。要修改以上編譯錯(cuò)誤,只要在ClassA的類定義前加public即可。注意:在方法和屬性前使用的修飾符private和protected一般不能用在類定義前,也就是說(shuō)沒(méi)有私有類和保護(hù)類。 5.2 屬性的隱藏和方法的重寫子類是一個(gè)比父類更具體的類,如“學(xué)生是人”和“轎車是車”,這里的“學(xué)生”和“轎車”分別是對(duì)“人”和“車”的具體化,因此它們比父類“人”和“車”擁有更多的屬性和方法,體現(xiàn)在程序設(shè)計(jì)中,就是一個(gè)類在繼承父類時(shí),常常要對(duì)父

23、類進(jìn)行如下的擴(kuò)展: 添加新的成員屬性(變量); 添加新的成員操作(方法); 隱藏父類的屬性; 重寫父類中的方法。5.2.1 屬性隱藏和方法重寫的基本知識(shí)1. 屬性的隱藏如果子類中定義了與父類中同名的屬性,則在子類中訪問(wèn)這種屬性時(shí),在默認(rèn)情況下引用的是子類自己定義的成員屬性,而將從父類那里繼承而來(lái)的成員屬性“隱藏”起來(lái)了。因此,隱藏是指子類對(duì)從父類繼承來(lái)的屬性進(jìn)行了重新定義。子類中,重新定義的屬性數(shù)據(jù)類型可以與父類中的類型相同,也可以與父類中的類型不同。屬性的隱藏由于在子類中定義了與父類中同名的屬性,因而可能會(huì)造成對(duì)程序理解上的混亂,況且屬性的隱藏在實(shí)際軟件開發(fā)中的用處不大,建議盡量避免使用。2

24、. 方法的重寫(或叫方法的覆蓋)方法的重寫指子類中重新定義了與父類中同名的方法,則父類中的方法被覆蓋(Override)。方法的重寫通常具有實(shí)際意義,如在案例5-1中,學(xué)生類的23行重寫了與父類中同名的introduceMyself方法,因?yàn)閷W(xué)生自我介紹時(shí),不但要介紹普通人具有的姓名和年齡,還要介紹學(xué)生所特有的學(xué)號(hào)和成績(jī)等信息。通過(guò)方法重寫可以將父類中的方法改造為適合子類使用的方法。被覆蓋的方法在子類中訪問(wèn)時(shí),將訪問(wèn)在子類中定義的方法,如案例5-1中的38行,將調(diào)用在Student類中定義的introduceMyself方法。注意1:方法的覆蓋需要子類中的方法頭和父類中的方法頭完全相同,即應(yīng)有

25、完全相同的方法名、返回值類型和參數(shù)列表。注意2:在子類中也可以重載父類中已有的方法。子類中重載的方法應(yīng)與父類中重載的方法具有相同的方法名和不同的參數(shù)形式。注意3:如果不希望子類對(duì)從父類繼承而來(lái)的方法進(jìn)行重寫,則可以在方法名前加final關(guān)鍵字。 注意4:覆蓋方法不能比它所覆蓋的父類中的方法有更嚴(yán)格的訪問(wèn)權(quán)限(訪問(wèn)權(quán)限可以相同)。下面舉一個(gè)實(shí)例進(jìn)行說(shuō)明。如下的程序中定義了兩個(gè)類F和S,子類S繼承了父類F,F(xiàn)類中定義了一個(gè)用protected修飾的屬性a和一個(gè)用protected修飾的方法showA():01 class F02 protected int a = 1;03 protected v

26、oid showA()04 System.out.println(a);05 06 07 08 class S extends F09 private int a = 2;10 void showA()11 System.out.println(a);12 13 編譯該程序時(shí)將出現(xiàn)如下錯(cuò)誤:S.java:10: S 中的 showA() 無(wú)法覆蓋 F 中的 showA();正在嘗試指定更低的訪問(wèn)權(quán)限;為 protected void showA() 1 錯(cuò)誤該錯(cuò)誤發(fā)生在showA()方法上。根據(jù)本章前面所學(xué)的知識(shí)我們知道,被protected修飾的成員(第03行的showA()方法)可以“被不

27、同包中的子類訪問(wèn)”,而包訪問(wèn)特性的成員(第10行的showA()方法)只能被同一個(gè)包中的類訪問(wèn),不能“被不同包中的子類訪問(wèn)”。由此,第10行定義的showA()方法比03行定義的showA()方法有“更嚴(yán)格的訪問(wèn)權(quán)限”,所以程序出現(xiàn)錯(cuò)誤。該錯(cuò)誤可按注意4的要求進(jìn)行修改,即在第10行方法showA前面加public或protected修飾符,使其具有與父類中showA相同或更大的訪問(wèn)控制權(quán)限。 但要注意,對(duì)于屬性沒(méi)有這樣的要求,如子類中第09行的屬性a隱藏了父類中02行定義的屬性a,父類中的a用protected修飾,而子類中的a用private修飾,這是允許的。注意5:覆蓋方法不能比它所覆蓋的

28、方法拋出更多的異常(第7章介紹)。 3. 子類訪問(wèn)父類被重寫的方法和被隱藏的屬性要在子類中訪問(wèn)被重寫的方法和被隱藏的屬性時(shí),如果直接用被重寫的方法名或被隱藏的屬性名,則被訪問(wèn)的是子類中定義的方法和屬性。如果要在子類中訪問(wèn)父類中被重寫的方法和被隱藏的屬性,則要使用關(guān)鍵字super。 簡(jiǎn)單地說(shuō),super表示當(dāng)前對(duì)象的直接父類對(duì)象。因此,可以通過(guò)super關(guān)鍵詞訪問(wèn)到父類中被重寫的方法和被隱藏的屬性。super的使用有三種情況:(1) 訪問(wèn)父類中被隱藏的成員變量,如:super.變量名; (2) 調(diào)用父類中被重寫的方法,如:super.方法名(參數(shù)列表);(3) 調(diào)用父類的構(gòu)造方法,如:super

29、(參數(shù)列表);在案例5-1中,父類People中定義的introduceMyself方法可以輸出一個(gè)人的姓名和年齡,因此子類中23行定義的introduceMyself方法,可以調(diào)用父類中11行已經(jīng)定義好的introduceMyself方法。具體做法是將程序中的第24行、25行和26行加上注釋,而將27行的注釋去掉,程序?qū)⒌玫较嗤膱?zhí)行結(jié)果。在下面的程序片段中,第6行使用super.x訪問(wèn)父類中被隱藏的屬性x:1 class X2 int x = 1;3 4 5 class Y extends X6 int x = super.x + 2;7 如何使用super調(diào)用父類的構(gòu)造方法,將在下一節(jié)介

30、紹。 5.2.2 【案例5-2】 重寫學(xué)生類1. 案例描述本節(jié)將按照面向?qū)ο蟮某绦蛟O(shè)計(jì)思想重寫案例5-1的學(xué)生類。2. 案例效果見案例5-1的顯示效果。3. 技術(shù)分析在定義人類Person時(shí),子類有權(quán)訪問(wèn)的屬性應(yīng)該用protected修飾;一個(gè)類的對(duì)外接口(即其他類可以訪問(wèn)的方法)應(yīng)該用public;子類在繼承父類時(shí),根據(jù)需要可以擴(kuò)展某些方法的功能,即對(duì)某些方法進(jìn)行覆蓋。 4. 程序解析下面是案例5-2的程序代碼:01 /*02 /案例:5.2 03 /程序名:Student2.java04 /功能:定義學(xué)生類 05 /*06 07 class People208 protected Stri

31、ng name;09 protected int age;10 11 public People2()12 13 public People2(String name, int age)14 = name;15 this.age = age;16 17 18 public void introduceMyself( )19 System.out.println(-);20 System.out.println(My name is +name+.);21 System.out.println(I am +age+ years old.);22 23 24 25 /學(xué)生類26

32、 class Student2 extends People227 private String stuNo; /學(xué)號(hào)28 private int java; /java語(yǔ)言成績(jī)29 30 public Student2(String name, int age, String stuNo, int java)31 = name;32 this.age = age;33 this.stuNo = stuNo;34 this.java = java;35 36 37 public void introduceMyself()38 roduceMyself()

33、;39System.out.println(我的學(xué)號(hào)是 + stuNo + .);40System.out.println(我的Java語(yǔ)言成績(jī)是 + java + .);414243 public static void main(String args)44Student2 s1 = new Student2(liping, 21, 20070901,89);45roduceMyself();4647該程序比較簡(jiǎn)單,請(qǐng)讀者自己分析。5.2.3 【相關(guān)知識(shí)】 方法覆蓋與方法重載的區(qū)別“覆蓋”與“重載”兩種技術(shù)對(duì)Java語(yǔ)言的初學(xué)者而言很容易混淆。所謂“重載”(Overload),

34、是在同一個(gè)類(或父類與子類)中定義了名稱相同但參數(shù)個(gè)數(shù)或參數(shù)類型不同的方法,因此在調(diào)用方法時(shí),系統(tǒng)便可依據(jù)參數(shù)的個(gè)數(shù)或類型來(lái)決定調(diào)用哪一個(gè)被重載的方法。所謂“覆蓋”(Override),是在子類中定義了名稱、參數(shù)個(gè)數(shù)與類型均與父類相同的方法,用以改寫或擴(kuò)展父類里方法的功能。下面通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明方法重載與方法覆蓋的區(qū)別:01 class F02 protected void showA()03 System.out.println(F類中的showA方法);04 05 06 07 class S extends F08 protected void showA()09 System.out.p

35、rintln(S類中的showA方法);10 11 12 void showA(int a)13 System.out.println(a);14 15 16 public static void main(String args)17 new S().showA(3);18 new S().showA();19 20 父類F中02行定義的showA方法與子類S中08行定義的showA方法是覆蓋關(guān)系,而子類S中12行定義的showA方法與其中08行定義的showA方法是重載關(guān)系,因?yàn)樗鼈兊膮?shù)不同。5.3 類之間的層次結(jié)構(gòu)一個(gè)子類繼承了一個(gè)父類,同時(shí)該子類還可以是其他類的父類,這樣就形成了一個(gè)

36、類之間的繼承關(guān)系圖。本節(jié)介紹類層次關(guān)系圖,以及父類對(duì)子類的影響等問(wèn)題。5.3.1 類的層次結(jié)構(gòu)類A如果有兩個(gè)子類AA和AB,類AA如果有一個(gè)子類AAA,類AB如果有一個(gè)子類ABA,它們之間的繼承關(guān)系就構(gòu)成了圖5-4左邊的部分。類似地,由B類及其子類構(gòu)成了圖5-4中間的部分,其他類之間也可以構(gòu)成類似的關(guān)系。 圖5-4 類的層次結(jié)構(gòu)1. Object類圖5-4所示的樹形結(jié)構(gòu)中,類是分層次的,最頂層是Object類。在Java語(yǔ)言中,所有類都直接或間接地繼承了在Java API中定義的Object類,Object類位于java.lang包中。在一個(gè)類定義中,如果沒(méi)有直接指出其父類,則Java語(yǔ)言默認(rèn)

37、其父類為Object。例如,下面定義了一個(gè)類Point:class Point float x; float y;它與下面Point的定義是等價(jià)的:class Point extends Object float x; float y;Java語(yǔ)言中,所有類都是由Object類導(dǎo)出的,即所有類都直接或間接地繼承了Object類。因此,在Object類中定義的public方法可以被任何一個(gè)Java類使用,也就是說(shuō),任何一個(gè)Java對(duì)象都可以調(diào)用這些方法。Object類中常用的兩個(gè)實(shí)例方法是: equals():equals方法等價(jià)于比較運(yùn)算符(=)。比較運(yùn)算符用來(lái)比較兩個(gè)簡(jiǎn)單數(shù)據(jù)類型的值是否相等

38、,或者判斷兩個(gè)對(duì)象是否具有相同的引用值。 toString():該方法返回代表這個(gè)對(duì)象的一個(gè)字符串表示。默認(rèn)情況下,返回的字符串由該對(duì)象所屬的類名、符號(hào)和代表該對(duì)象的一個(gè)數(shù)組成。例如:System.out.println (myClinder),輸出類似Cylinder15037e5的字符串,這些信息的意義不大,在編程中通常重寫toString方法,使它返回一個(gè)代表該對(duì)象的易懂的字符串。 分析下面的示例程序(注意equals()和toString()在程序中的用法):01 class Obj02 int x = 12;03 04 05 class TestObj06 public static

39、 void main(String args)07 Obj a = new Obj();08 Obj b = new Obj();09 Obj c = b; /c和b引用內(nèi)存中相同的對(duì)象10 System.out.println(a.toString();11 System.out.println(a);12 System.out.println(a.equals(b);13 c.x = 24;14 System.out.println(b.equals(c);15 System.out.println(b.x);16 17 該程序執(zhí)行后輸出的結(jié)果如圖5-5所示。圖5-5 示例程序的運(yùn)行結(jié)果從

40、圖5-5中可以看出,如果調(diào)用含有對(duì)象參數(shù)的System.out.println方法(即輸出的量為對(duì)象名稱),則系統(tǒng)就會(huì)自動(dòng)調(diào)用toString方法打印出相應(yīng)的信息。2. 繼承的傳遞性繼承具有傳遞性。也就是說(shuō),父類可以把一些特性傳遞給子類,而子類又可以把這些特性再傳遞它的子類(即子類的子類),依次類推。因此,子類繼承的特性可能來(lái)源于它的父類,也可能來(lái)源于它的祖先類。分析下面的示例程序。01 class A02 public int a1 = 1;03 int a2 = 2;04 protected int a3 = 3; 05 06 07 class B extends A /B類繼承了A類08

41、 public int b1 = 11;09 int b2 = 22;10 protected int b3 = 33;11 12 13 class C extends B /C類繼承了B14 int c1 = 111;15 void showC()16 System.out.println(clas A a1= + a1);17 System.out.println(clas A a2= + a2);18 System.out.println(clas A a3= + a3);19 System.out.println(clas B b1= + b1);20 System.out.print

42、ln(clas B b2= + b2);21 System.out.println(clas B b3= + b3);22 System.out.println(clas C c1= + c1);23 24 25 public static void main(String args)26 C objC = new C();27 objC.showC();28 29 該程序的執(zhí)行結(jié)果如圖5-6所示。分析圖5-6中輸出的結(jié)果,弄清類之間的繼承關(guān)系。圖5-6 示例程序的執(zhí)行結(jié)果3. 對(duì)象的初始化在Java語(yǔ)言中,對(duì)象的初始化非常重要。在使用對(duì)象之前,首要先初始化對(duì)象,這樣做是為了保證對(duì)象處于安全狀

43、態(tài)。一個(gè)子類對(duì)象既包含了從父類繼承來(lái)的屬性,也包含了它自己新定義的屬性,因此在創(chuàng)建一個(gè)子類對(duì)象時(shí),這些屬性都要被正確的初始化。 其中,參數(shù)是可選的。如果沒(méi)有參數(shù),則super()調(diào)用的就是父類無(wú)參的構(gòu)造方法。如果子類的構(gòu)造方法中沒(méi)有調(diào)用父類構(gòu)造方法的super語(yǔ)句,則系統(tǒng)就會(huì)在子類構(gòu)造方法執(zhí)行時(shí),自動(dòng)調(diào)用父類無(wú)參構(gòu)造方法,即執(zhí)行一條super()語(yǔ)句。該規(guī)則的用意是確保在子類構(gòu)造方法執(zhí)行之前,就調(diào)用了父類的構(gòu)造方法,以完成對(duì)父類變量的初始化操作。盡管子類的構(gòu)造方法可以自動(dòng)調(diào)用父類的無(wú)參構(gòu)造方法,但是為了養(yǎng)成良好的編程習(xí)慣,作者建議在編寫子類的構(gòu)造方法時(shí),第一條語(yǔ)句應(yīng)該是調(diào)用父類構(gòu)造方法的語(yǔ)句。

44、根據(jù)以上說(shuō)明,請(qǐng)讀者自己分析下面示例程序的運(yùn)行結(jié)果:01 class Art02 Art() /Art類的構(gòu)造方法03 System.out.println(Art Constructor.);04 05 06 07 class Drawing extends Art08 Drawing() /Drawing類的構(gòu)造方法09 System.out.println(Drawing Constructor.);10 11 12 public static void main(String args)13 Drawing d = new Drawing(); /創(chuàng)建一個(gè)Drawing類的對(duì)象14 1

45、5 分析下面的程序有什么錯(cuò)誤:01 class Employee 02 String name;03 /public Employee()04 public Employee(String n) 05 name = n;06 07 08 09 class Manager extends Employee 10 String department;11 /public Manager()12 public Manager(String s, String d) 13 super(s); /調(diào)用父類帶一個(gè)參數(shù)的構(gòu)造方法14 department = d;15 16 17 18 class Test

46、Manager19 public static void main(String args)20 Manager m1 = new Manager();21 Manager m2 = new Manager(ZhangFan,market);22 23 程序的20行調(diào)用Manager類的默認(rèn)構(gòu)造方法初始化一個(gè)對(duì)象m1,但由于在Manager類中已經(jīng)定義了一個(gè)帶參數(shù)的構(gòu)造方法,系統(tǒng)就不會(huì)自動(dòng)添加一個(gè)無(wú)參的默認(rèn)構(gòu)造方法,因此程序編譯時(shí)將發(fā)生錯(cuò)誤。如果給Manager類添加一個(gè)無(wú)參的構(gòu)造方法,如第11行所示(將11行的注釋去掉),程序編譯時(shí)還會(huì)發(fā)生錯(cuò)誤,這又是為什么呢?因?yàn)镸anager類中已經(jīng)添加

47、了無(wú)參的構(gòu)造方法 該構(gòu)造方法要自動(dòng)調(diào)用其父類Employee的無(wú)參構(gòu)造方法,而父類Employee中沒(méi)有定義無(wú)參的構(gòu)造方法,并且由于在類Employee中已經(jīng)定義了一個(gè)有參數(shù)的構(gòu)造方法,因此系統(tǒng)也不會(huì)自動(dòng)添加一個(gè)無(wú)參的構(gòu)造方法。為了使該程序能被正確編譯,還要給Employee類添加一個(gè)無(wú)參的構(gòu)造方法,即將03行的注釋去掉后編譯程序,則不會(huì)發(fā)生編譯錯(cuò)誤。這個(gè)錯(cuò)誤是初學(xué)者最常見的一個(gè)錯(cuò)誤,防范的措施就是給每一個(gè)類都加上無(wú)參的構(gòu)造方法。注意1:父類的構(gòu)造方法的功能是完成父類屬性的初始化,因此子類不能繼承父類的構(gòu)造方法。注意2:用super調(diào)用父類的構(gòu)造方法時(shí),該語(yǔ)句只能出現(xiàn)在子類構(gòu)造方法的第一行。由

48、于在一個(gè)類的構(gòu)造方法中使用this(見第3章)調(diào)用該類的其他構(gòu)造方法時(shí),也要將其放在第一行,因此在一個(gè)構(gòu)造方法中,this調(diào)用和super調(diào)用不能同時(shí)出現(xiàn)(請(qǐng)讀者自己分析其中的原因)。 最后,將創(chuàng)建一個(gè)類的對(duì)象時(shí)對(duì)象初始化的順序總結(jié)如下:首先,將分配到的存儲(chǔ)空間自動(dòng)進(jìn)行初始化(初始化的值,見表3-7所示)。其次,進(jìn)行顯式初始化(即在類中聲明的屬性,如果賦了初值,就要進(jìn)行顯式初始化)。第三,調(diào)用構(gòu)造方法進(jìn)行初始化。4. 父類對(duì)象和子類對(duì)象之間的轉(zhuǎn)換子類是對(duì)父類的具體化,如我們說(shuō)“狗是一種哺乳動(dòng)物”,即就是說(shuō),在哺乳動(dòng)物這個(gè)大類中,狗只是其中的一種哺乳動(dòng)物(在Java語(yǔ)言中,就是說(shuō)哺乳動(dòng)物類(Ma

49、mmal)是狗類(Dog)的父類),這句話如果反過(guò)來(lái)說(shuō)“哺乳動(dòng)物就是一種狗”就不對(duì)了,因?yàn)椴溉閯?dòng)物還包括馬、羊等。這個(gè)問(wèn)題與Java語(yǔ)言中的下面兩個(gè)問(wèn)題有聯(lián)系。 1) 一個(gè)子類對(duì)象可以直接賦給一個(gè)父類對(duì)象這個(gè)問(wèn)題可以用下面的程序加以說(shuō)明。定義一個(gè)哺乳動(dòng)物類:class Mammal狗是一種哺乳動(dòng)物類,所以可以用下面的繼承關(guān)系定義:class Dog extends Mammalvoid run 程序中說(shuō)明了一個(gè)如下的動(dòng)物類對(duì)象的引用:Mammal m;程序中創(chuàng)建了一個(gè)狗類的實(shí)例:Dog dog1 = new Dog();如果有如下的賦值:m = dog1;這就好比說(shuō)“狗是一種哺乳動(dòng)物”,因此這

50、種賦值是正確的??梢杂孟旅娴姆绞綍鴮懀篗ammal m = new Dog(); 這種賦值方式是將類繼承層次結(jié)構(gòu)的下層對(duì)象轉(zhuǎn)化為上層對(duì)象,因此可以將父類的對(duì)象m叫做子類對(duì)象dog1的上轉(zhuǎn)型對(duì)象。上轉(zhuǎn)型對(duì)象會(huì)失去子類對(duì)象的一些特有屬性,如我們說(shuō)“狗是一種哺乳動(dòng)物”時(shí),就只指狗的哺乳動(dòng)物類特性,而不是指狗所特有的屬性。因此,一個(gè)上轉(zhuǎn)型對(duì)象不能操作子類新增加的屬性和方法。上轉(zhuǎn)型對(duì)象的本質(zhì)是子類對(duì)象包含了父類對(duì)象的域,所以在創(chuàng)建一個(gè)子類對(duì)象時(shí),也隱含地創(chuàng)建了一個(gè)父類對(duì)象(這也是子類對(duì)象實(shí)例化時(shí),其構(gòu)造方法首先要調(diào)用父類構(gòu)造方法的原因),因此子類對(duì)象可以賦給父類對(duì)象。也可以這樣理解這個(gè)問(wèn)題,父類對(duì)象的取

51、值范圍較大(如哺乳動(dòng)物可以是馬、狗、貓等),而子類對(duì)象的取值范圍較小(如狗只是哺乳動(dòng)物中的一小類),所以子類對(duì)象賦給父類對(duì)象是正確的(相當(dāng)于簡(jiǎn)單數(shù)據(jù)類型中,可以將一個(gè)取值范圍較小的量賦給一個(gè)取值范圍較大的量,如將一個(gè)byte型量賦給一個(gè)int型量,這是正確的)。注意1:子類對(duì)象賦給父類對(duì)象時(shí),會(huì)自動(dòng)進(jìn)行類型轉(zhuǎn)換。注意2:因?yàn)镴ava語(yǔ)言中的所有類都直接或間接繼承了Object類,所以任何一個(gè)類的對(duì)象都可以賦給Object類的對(duì)象,即Object類的對(duì)象可引用任何對(duì)象。2) 一個(gè)父類對(duì)象不能直接賦給子類對(duì)象如有下面的賦值:Dog dog2 = new Mammal();這就好像說(shuō)“哺乳動(dòng)物是狗”

52、。我們知道哺乳動(dòng)物很多,只能說(shuō)狗是哺乳動(dòng)物里的一種,而不能說(shuō)哺乳動(dòng)物都是狗。因此,在Java語(yǔ)言中這種賦值是不允許的。如果的確要進(jìn)行這樣的賦值,則只能進(jìn)行強(qiáng)制類型轉(zhuǎn)換:Dog dog2 = (Dog)new Mammal();注意:父類對(duì)象賦給子類對(duì)象時(shí)要使用強(qiáng)制類型轉(zhuǎn)換。父類對(duì)象不能賦給子類對(duì)象也可以這樣理解,因?yàn)楦割悓?duì)象中不包含子類對(duì)象新增加的域,正是這些子類中新增加的域限制了子類對(duì)象,使其只能是父類中有這些屬性的那一部分。所以,將一個(gè)父類對(duì)象賦給一個(gè)子類對(duì)象,相當(dāng)于簡(jiǎn)單數(shù)據(jù)類型中,將一個(gè)取值范圍大的量賦給一個(gè)取值范圍小的量,這是錯(cuò)誤的,除非使用強(qiáng)制類型轉(zhuǎn)換。 5.3.2 【案例5-3】

53、定義公司員工類1. 案例描述在開發(fā)一個(gè)公司管理信息系統(tǒng)的過(guò)程中,涉及到的人員有普通員工、公司經(jīng)理等,現(xiàn)要求設(shè)計(jì)公司的有關(guān)員工類。2. 案例效果案例程序的執(zhí)行效果如圖5-7所示。圖5-7 案例5-3的執(zhí)行效果3. 技術(shù)分析一個(gè)公司的普通員工擁有員工號(hào)(employeeNumber)、姓名(name)、地址(address)等屬性。公司的經(jīng)理也是一名員工,只不過(guò)經(jīng)理比普通員工擁有更多的權(quán)限和職責(zé),如公司的經(jīng)理有所管理的部門(department)等。通過(guò)以上分析可知,定義的普通員工類(employee)應(yīng)該是經(jīng)理類(manager)的父類(說(shuō)明:該程序主要是為了說(shuō)明類之間的繼承關(guān)系以及this與s

54、uper關(guān)鍵字在類中的用法。為了節(jié)省篇幅,這里給出的員工屬性比較少)。 4. 程序解析01 /*02 /案例:5.2 03 /程序名:TestManager.java04 /功能:定義公司員工類和經(jīng)理類 05 /*06 07 /公司員工類08 class Employee 09 protected String employeeNumber;10 protected String name;11 protected String address;12 13 public Employee()14 this(, , );15 16 17 public Employee(String employ

55、eeNumber, String name, String address) 18 this.employeeNumber = employeeNumber;19 = name;20 this.address = address;21 22 23 protected void showEmployee()24 System.out.println(-);25 System.out.println(員工編號(hào): + employeeNumber);26 System.out.println(姓名: + name);27 System.out.println(地址: + addr

56、ess);28 29 30 31 /公司經(jīng)理類32 class Manager extends Employee 33 protected String department;34 35 public Manager()36 this(, , , );37 38 39 public Manager(String employeeNumber, String name, String address,String department) 40 super(employeeNumber,name,address); /調(diào)用父類帶3個(gè)參數(shù)的構(gòu)造方法41 this.department = depar

57、tment;42 43 44 protected void showManager()45 super.showEmployee();46 System.out.println(管理的部門: + department); 47 48 49 50 /測(cè)試類51 class TestManager52 public static void main(String args)53 Employee e = new Employee(100010,Zhangping, zhong shan road);54 e.showEmployee();55 56 Manager m = new Manager(

58、100001,ZhangFan,dong fang hong road,market);57 m.showManager();58 59 在程序的0829行定義了一個(gè)普通的員工類Employee。0911行定義了員工的三個(gè)屬性,都用protected修飾,表示同一個(gè)包中的其他類和子類可以訪問(wèn)這些屬性。1315行定義了一個(gè)無(wú)參的構(gòu)造方法,方法體中的一條語(yǔ)句為“this(, , )”,表示調(diào)用Employee類中帶3個(gè)參數(shù)的構(gòu)造方法,這樣做的目的是為了防止當(dāng)使用無(wú)參的構(gòu)造方法初始化對(duì)象時(shí),將類中定義的3個(gè)屬性都初始化為null,在Manger類中定義的無(wú)參構(gòu)造方法也有類似的功能。3248行定義的M

59、anager類中,40行表示調(diào)用父類帶3個(gè)參數(shù)的構(gòu)造方法,45行表示調(diào)用父類的showEmployee()方法。5.3.3 【相關(guān)知識(shí)】 final關(guān)鍵字與終止繼承在Java語(yǔ)言中,final關(guān)鍵字有三種用法:修飾變量、修飾方法和修飾類。1. 修飾變量在第3章中曾講過(guò),如果一個(gè)變量被final關(guān)鍵字修飾,則該變量就是常量,只能進(jìn)行一次賦值。2. 修飾方法一個(gè)方法如果不希望在子類中被重寫,就要用final修飾,這種方法也叫終結(jié)方法。在這種情況下,子類只能使用從父類繼承下來(lái)的方法,而無(wú)法對(duì)父類中的方法進(jìn)行擴(kuò)展。這種做法的好處是,可以防止子類對(duì)父類中的關(guān)鍵方法進(jìn)行重寫時(shí)而產(chǎn)生的錯(cuò)誤,增加了代碼的安全

60、性和正確性。用final修飾方法時(shí),則方法不能被覆蓋??聪旅娴氖纠绦颍?01 class P02 final void print()03 System.out.println(a final method.);04 05 06 07 class Q extends P08 void print()09 System.out.println(override a final method.);10 11 該程序?qū)a(chǎn)生如下的編譯錯(cuò)誤:P.java:8: Q 中的 print() 無(wú)法覆蓋 P 中的 print();被覆蓋的方法為 final void print() 1 錯(cuò)誤在父類P中,02行

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論