摘要
閱讀完本章后,大家應(yīng)能根據(jù)需要定義并使用一個(gè)用戶類(lèi),并能夠根據(jù)需求說(shuō)明這個(gè)用戶類(lèi)的特性。另外,還應(yīng)該能夠使用繼承的方法創(chuàng)建子類(lèi),實(shí)現(xiàn)類(lèi)的最大化使用。
(2002-08-29 14:10:16)By
Wing, 出處:
fjxufeng本章目標(biāo):
閱讀完本章后,大家應(yīng)能根據(jù)需要定義并使用一個(gè)用戶類(lèi),并能夠根據(jù)需求說(shuō)明這個(gè)用戶類(lèi)的特性。另外,還應(yīng)該能夠使用繼承的方法創(chuàng)建子類(lèi),實(shí)現(xiàn)類(lèi)的最大化使用。
8.1 定義并使用一個(gè)新類(lèi)
傳授新知
在前面幾章中,我們遇到了不少用Java語(yǔ)言編寫(xiě)的程序,它們可以分為兩類(lèi):
1) Java應(yīng)用程序;
2) Java小應(yīng)用程序。
它們都有一個(gè)共同的特點(diǎn),那就是整個(gè)程序中只包含一個(gè)類(lèi)。不同在于,這個(gè)唯一的類(lèi)的定義不盡相同。
在Java應(yīng)用程序中,形如:
public class testBranch1
而在Java小應(yīng)用程序中,則形如:
public class VariableScope extends Applet
其實(shí),在這些程序中都使用到了其它類(lèi)。在小應(yīng)用程序中,很明顯,所有的類(lèi)都是從Applet類(lèi)中繼承來(lái)的。在應(yīng)用程序中,也使用了其它的類(lèi),不過(guò)不是十分明顯,大家想想,System.out.println是從哪來(lái)的呢?它是從其它類(lèi)中繼承過(guò)來(lái)的,它包含在java.lang包中,無(wú)須指明,編譯器能夠自動(dòng)處理。
Java語(yǔ)言的開(kāi)發(fā)工具包(JDK)中就包含了許許多多的已開(kāi)發(fā)定義的類(lèi),我們可以通過(guò)使用它們迅速地構(gòu)建自己的程序。如果你能夠熟練地使用它們就能夠使用Java語(yǔ)言寫(xiě)出自己所需要的程序。而如果你想要成為Java語(yǔ)言的高手,就一定要學(xué)會(huì)自己定義類(lèi),以供今后的程序使用。下面我們一起來(lái)看一下下面這個(gè)例子。
實(shí)例說(shuō)明
1.首先,我們使用文字編輯軟件輸入下面這個(gè)源程序。
源程序:Birthday.java
public class Birthday {public String year;public String month;public String day;public Birthday(){year=”0000”;month=”00”;day=”00”;}public Birthday(String y,String m,String d){year=y;month=m;day=d;}public String getBirthday(){String fullbirthday=month+”/”+”/”+day+”/”+year;return fullbirthday;}}
2.編譯這個(gè)程序,如果順利完成,將在當(dāng)前目錄下生成一個(gè)名為Birthday.class的文件;
c:javastudy> javac Birthday.java
3.然后輸入以下命令,運(yùn)行這個(gè)程序:
c:javastudy> java Birthday
執(zhí)行這個(gè)程序,將輸出一些信息,如下圖所示:
圖8-1 執(zhí)行Birthday類(lèi)的輸出
Java語(yǔ)言責(zé)怪我們沒(méi)有定義main方法。
4.接下來(lái),我們?cè)儆梦淖志庉嬡浖斎胍韵略闯绦颉?div style="height:15px;">
源程序:useBirthday.java
public class useBirthday {public static void main(String argv[]){Birthday birthday1=new Birthday();Birthday birthday2=new Birthday("1949","10","01");System.out.println(birthday1.getBirthday());System.out.println(birthday2.getBirthday());}}
3.使用javac編譯后,執(zhí)行以下命令,運(yùn)行這個(gè)程序:
c:javastudy> java useBirthday
執(zhí)行這個(gè)程序,將輸出一些信息,如下圖所示:
圖8-2 執(zhí)行useBirthday類(lèi)的輸出
傳授新知
我們先來(lái)看一下第二個(gè)程序useBirthday.java,這是個(gè)Java應(yīng)用程序,main方法中共有四條語(yǔ)句。前兩條,看上去象是定義變量:
Birthday birthday1=new Birthday();Birthday birthday2=new Birthday("1949","10","01");
但是,我們從來(lái)沒(méi)有向大家介紹過(guò)Birthday這種變量類(lèi)型呀!是的,在Java語(yǔ)言中并沒(méi)有Birthday這種變量類(lèi)型。
可是這條語(yǔ)句在編譯過(guò)程中并沒(méi)有報(bào)錯(cuò)呀!這是因?yàn)椋琂ava語(yǔ)言編譯器在useBirtday.java程序所在目錄中發(fā)現(xiàn)了包含Birthday類(lèi)定義的Birthday類(lèi):Birthday.class。
也就是說(shuō),這兩條語(yǔ)句定義了2個(gè)屬于Birthday類(lèi)的對(duì)象:birthday1和birthday2。從Birthday.java程序中,我們可以看到Birthday類(lèi)包含三個(gè)字符型成員變量:
public String year;public String month;public String day;
一些提示:
我們將Birthday稱(chēng)為類(lèi),而將birthday1和 birthday2稱(chēng)為對(duì)象。請(qǐng)大家一定要明明白白地知道其中原委。類(lèi)是一類(lèi)事物,而對(duì)象則是一個(gè)個(gè)體。
成員變量是一個(gè)形象的術(shù)語(yǔ),表示這些變量屬于這個(gè)對(duì)象,屬于這個(gè)類(lèi)。
同時(shí),分別使用new Birthday()和new Birthday(“1949”,”10”,”01”)為它們賦初值。
1)Birthday birthday1=new Birthday();
在這一句中,調(diào)用的是Birthday類(lèi)中的Birthday()方法,我們從Birthday.java中可以看到這個(gè)方法實(shí)現(xiàn):
public Birthday(){year=”0000”;month=”00”;day=”00”;}
也就是說(shuō),它將對(duì)象birthday1的三個(gè)成員變量year,month和day分別賦予了初值“0000”,“00”和“00”。
2) Birthday birthday2=new Birthday("1949","10","01");
在這一條語(yǔ)句中,雖然方法名同是Birthday,但它帶上了參數(shù),所以它調(diào)用的是Birthday類(lèi)中的Birthday(String y,String m,String d)方法。這個(gè)方法的實(shí)現(xiàn)是:
public Birthday(String y,String m,String d){year=y;month=m;day=d;}
也就是將其所帶的參數(shù)值,分別賦值給三個(gè)成員變量。在本例中,“1949”賦值給year,“10”賦值給month,“01”賦值給day。
這個(gè)程序中另兩條語(yǔ)句則十分相似:
System.out.println(birthday1.getBirthday());System.out.println(birthday2.getBirthday());
很明顯,這兩條語(yǔ)句的用途是打印出birthday1和birthday2兩個(gè)對(duì)象的一些信息。什么信息呢?我們可以發(fā)現(xiàn)這兩條語(yǔ)句中都使用了Birthday類(lèi)中的getBirthday方法。
一些提示:
大家注意觀察在上面的語(yǔ)句是如何調(diào)用getBirthday方法的:
birthday1.getBirthday()
前面是對(duì)象名,后面是方法名,中間用“.”連接。請(qǐng)記住這個(gè)“.”,它經(jīng)常被使用。形象的說(shuō),它就表示“的”。即birthday1的getBirthday方法。同樣,我們可以使用這樣在方法來(lái)訪問(wèn)它的成員變量:birthday1.year,即對(duì)象birthday1的成員變量year。
我們就來(lái)看一下這個(gè)方法做了什么:
public String getBirthday() { String fullbirthday=month+”/”+”/”+day+”/”+year; return fullbirthday; }
大家還記得“+”在字符串操作中的用途吧!對(duì),我們?cè)诘?章中就跟大家說(shuō)過(guò),它是用來(lái)進(jìn)行字符串合并的。我們通過(guò)month+”/”+”/”day+”/”+year語(yǔ)句,把birthday1和birthday2兩個(gè)對(duì)象的三個(gè)成員變量組成了一個(gè)“月/日/年”的常用日期表示方法。
然后,getBirthday方法將這個(gè)用“月/日/年”表示法表示的生日日期返回(使用return方法)給System.out.println,這樣,我們就得到了如圖8-2的輸出:
00/00/000010/01/1949
通過(guò)上面的實(shí)例與講解,我們可以得出創(chuàng)建一個(gè)新類(lèi)的方法:
1) 構(gòu)思所需類(lèi)的成員變量和成員方法;
2) 用以下格式來(lái)編寫(xiě)類(lèi):
類(lèi)修飾符 class 類(lèi)名{成員變量定義;……成員方法定義;……}
3) 使用javac編譯這個(gè)類(lèi);
4) 然后我們就可以在其它類(lèi)中使用這個(gè)類(lèi)。
注意:
當(dāng)你編譯使用自定義類(lèi)(如Birthday)的程序(如useBirthday.java)時(shí),這個(gè)類(lèi)(Birthday.class)必須與程序(useBirthday.java)位于相同的目錄中,或者在系統(tǒng)變量CLASSPATH定義的目錄中。否則編譯時(shí)將找不到這個(gè)類(lèi),以致程序無(wú)法編譯成功。
一些提示:
當(dāng)你需要同時(shí)編譯幾個(gè)Java文件時(shí),你可以使用一條命令來(lái)完成。例如:
javac Birthday.java useBirthday.java
javac程序?qū)⒁黄鹁幾g所有這些文件。我們知道編譯useBirthday.java時(shí),需要用到Birthday.class(就是由Birthday.java編譯生成的)。那么大家可能會(huì)以為,我們一定要將Birthday.java放在前面,以確保能夠先編譯生成Birthday.class。
其實(shí)并不需要,Java編譯器能夠智能地處理,你完全可以將useBirthday.java放在Birthday.java前面。
我們?cè)贐irthday類(lèi)定義中,發(fā)現(xiàn)有兩個(gè)與類(lèi)Birthday同名的成員方法:
public Birthday() public Birthday(String y,String m,String d)
這種與類(lèi)同名的成員方法稱(chēng)為構(gòu)造器。每當(dāng)使用new操作符創(chuàng)建屬于這個(gè)類(lèi)的對(duì)象時(shí),就會(huì)執(zhí)行構(gòu)造器方法。
一個(gè)類(lèi)可以有多個(gè)構(gòu)造器,在使用new操作符時(shí),執(zhí)行哪個(gè)構(gòu)造器則取決于它所還的參數(shù)。如:
1)Birthday birthday1=new Birthday();
在這條語(yǔ)句中,由于調(diào)用Birthday方法時(shí),并未有任何參數(shù),所以將調(diào)用Birthday類(lèi)的構(gòu)造器Birthday()。
2) Birthday birthday2=new Birthday("1949","10","01");
而在這條語(yǔ)句中,調(diào)用Birthday方法所帶的參數(shù)與Birthday(String y,String m,String d)相吻合,所以將調(diào)用Birthdya類(lèi)的構(gòu)造器Birthday(String y,String m,String d)。因些,將完成以下賦值工作:
1)year=y; à year=“1949”
2)month=m; à month=“10”
3)day=d; à day=“01”
注意:
如果調(diào)用時(shí)的參數(shù)與所有構(gòu)造器不吻合,將使Java編譯器在編譯程序時(shí)報(bào)錯(cuò),使得無(wú)法編譯成功。
自測(cè)練習(xí)
1) 如果我們定義一個(gè)名為car的類(lèi),那么存儲(chǔ)這個(gè)類(lèi)的源文件名可以是:________。
a. car.class b.任意取名 c.class.java
2) 一個(gè)類(lèi)中,只能擁有一個(gè)構(gòu)造器方法。_________
a. 不對(duì) b.對(duì)
3) 一個(gè)構(gòu)造器方法的方法名,___________________。
a.與類(lèi)同相同 b.可以根據(jù)需要取名 c.可以有多個(gè)不同名的構(gòu)造器
4) 在______________________時(shí),將調(diào)用構(gòu)造器方法。
a.定義一個(gè)屬于該類(lèi)的對(duì)象 b.調(diào)用new操作符
c.打印屬于該類(lèi)的對(duì)象信息
5) 當(dāng)__________________時(shí),編譯使用自定義類(lèi)的程序時(shí)將出錯(cuò)。
a. 自定義類(lèi)放在系統(tǒng)環(huán)境變量PATH(CLASSPATH未指定該目錄)指定的目錄中
b.與程序在同一個(gè)目錄下 c.放在系統(tǒng)環(huán)境變量CALSSPATH指定的目錄中
6) 修改useBirthday.java程序中的語(yǔ)句:
Birthday birthday1=new Birthday();
改為使用構(gòu)造器Birthday(String y,String m,String d),使其結(jié)果相同。
____________________________________________________________________
7) 編寫(xiě)一個(gè)userName類(lèi),包含兩個(gè)成員變量:firstname,lastname;并仿照Birthday類(lèi)構(gòu)建兩個(gè)構(gòu)造器方法,一個(gè)是帶參數(shù),一個(gè)是不帶參數(shù)(將它們初始化為firstname,lastname);最后構(gòu)建一個(gè)fullName方法,用來(lái)返回全名。
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
練習(xí)答案
1)c 在Java語(yǔ)言中,要求存放類(lèi)的文件必須與類(lèi)同名,甚至連大小寫(xiě)都要完全一樣。而car.class是編譯后生成的,存放源文件應(yīng)該是car.java。
2)a 不對(duì),在Java的類(lèi)中,可以定義多個(gè)構(gòu)造器方法。
3)a 在Java語(yǔ)言中,要求構(gòu)造器方法名與類(lèi)名相同。
4)b 調(diào)用new操作符時(shí),才真正創(chuàng)建這個(gè)對(duì)象,這時(shí)調(diào)用構(gòu)造器方法來(lái)構(gòu)造它。這也是構(gòu)造器名字的來(lái)歷。
5)a Java編譯器會(huì)在當(dāng)前目錄和CLASSPATH指定的目錄中尋找相應(yīng)的類(lèi),而不會(huì)在PATH路徑中查找。
6) 這個(gè)很簡(jiǎn)單,因?yàn)椴粠?shù)的構(gòu)造器方法為其賦予了值“0000”、“00”和“00”,因此,我們可以使用帶參的構(gòu)造器來(lái)實(shí)現(xiàn)相同的工作:
Birthday birthday2=new Birthday(“0000”,”00”,”00”);
7) 這里所要的新類(lèi)很簡(jiǎn)單,它與我們前面的實(shí)例Birthday類(lèi)十分類(lèi)似,我們只需要在前面的定義中做一些修改就可以得到了。
以下就是一個(gè)實(shí)例:
源程序:Birthday.java
public class userName{ public String firstname; public String lastname; public userName() { firstname=”firstname”; lastname=”lastname”; } public userName(String first,String last) { firstname=first; lastname=last; } public String fullName() { String fullname=firstname+” ”+lastname; return fullname; }}
8.2 說(shuō)明類(lèi)的特性
8.2.1 private特性
實(shí)例說(shuō)明
1.首先,我們輸入以下源程序,構(gòu)建一個(gè)People類(lèi):
源程序:People.java
public class People {public String name;public String sex;private String age; }
2.接著使用javac編譯這個(gè)類(lèi):
c:javastudy> javac People.java
3.接下來(lái),我們構(gòu)建一個(gè)使用People類(lèi)的程序usePeople.java
源程序:usePeople.java
public class usePeople { public static void main(String argv[]) { People people1=new People(); people1.name=”Kate”; people1.sex=”female”; people1.age=”23”; System.out.println(“Name:”+people1.name); System.out.println(“Sex:”+people1.sex); System.out.println(“Age:”+people1.age); }}
3. 執(zhí)行以下命令,編譯usePeople.java:
c:javastudy> javac usePeople.java
這時(shí),編譯器將報(bào)告錯(cuò)誤,編譯失敗,如下圖所示:
圖8-3 編譯錯(cuò)誤輸出
傳授新知
在上面這個(gè)例子中,我們遇到了一個(gè)錯(cuò)誤:
Variable age in class People not accessible from class usePeople:people1.age=”23”; 1 error
這個(gè)錯(cuò)誤信息的中文信息就是:“在語(yǔ)句people1.age=”23”中有一個(gè)錯(cuò)誤,usePeople類(lèi)無(wú)權(quán)訪問(wèn)People類(lèi)中的變量age?!?div style="height:15px;">
為什么會(huì)出現(xiàn)這個(gè)錯(cuò)誤呢?難道是語(yǔ)句寫(xiě)錯(cuò)了!但是Java編譯器并未對(duì)相類(lèi)似的另兩條語(yǔ)句報(bào)錯(cuò)呀。
我們發(fā)現(xiàn),沒(méi)有報(bào)錯(cuò)的兩條語(yǔ)句所訪問(wèn)的變量name與sex,在People類(lèi)中定義時(shí)使用了public;而報(bào)錯(cuò)的這條語(yǔ)句所訪問(wèn)的變量age在定義時(shí)使用的是private。對(duì),區(qū)別就在這里。
英語(yǔ)單詞public的意思是:公用的,而private的意思則是:個(gè)人的、私有的。噢!People類(lèi)中的成員變量age與另兩個(gè)變量name和sex不同,它是私有的。所以u(píng)sePeople無(wú)權(quán)訪問(wèn)age這個(gè)成員變量。因此,引起了出錯(cuò)。
在Java語(yǔ)言中,我們可以將類(lèi)的某些數(shù)據(jù)、方法聲明為private,這樣這個(gè)數(shù)據(jù)或方法則僅能夠被這個(gè)類(lèi)使用,而不允許其它類(lèi)使用。
這樣做有什么好處呢?這樣可以實(shí)現(xiàn)信息隱藏。我們可以將一個(gè)類(lèi)的所有變量都定義為私有的,然后構(gòu)造一些公用的方法來(lái)訪問(wèn)和處理數(shù)據(jù)。這樣就可以有效地實(shí)現(xiàn)數(shù)據(jù)的封裝,利用程序設(shè)計(jì)。
public class People { private String name; private String sex; private String age; public People(String n,String s,String a) {name=n;sex=s;age=a; } public void infoPrint() {System.out.println("Name:"+name);System.out.println("Sex:"+sex);System.out.println("Age:"+age); }}
public class usePeople { public static void main(String argv[]) { People people1=new People("Kate","female","23"); people1.infoPrint(); }}
3. 使用javac編譯后,執(zhí)行以下命令運(yùn)行程序:
在這個(gè)實(shí)例中,People將數(shù)據(jù)都封裝起來(lái),usePeople則使用People類(lèi)提供的兩個(gè)公用的(public)方法來(lái)設(shè)置成員變量的值,以及打印這些成員變量的值。
public class myBook{ public String bookName; public static String ownerName=”XuFen”; public myBook(String bn) {bookName=bn; } public void infoPrint() {System.out.println("Book Name:"+bookName);System.out.println("Owner:"+ownerName); }}
public class usemyBook{ public static void main(String argv[]) {myBook mybook1=new myBook("C Progamming");myBook mybook2=new myBook("Java Programming");mybook1.infoPrint();mybook2.infoPrint();System.out.println("--------------------------------------");mybook1.bookName="C Programming";mybook1.ownerName=”XuFeng”;mybook1.infoPrint();mybook2.infoPrint(); }}
3. 使用javac編譯后,執(zhí)行以下命令運(yùn)行程序:
myBook mybook1=new myBook("C Progamming");myBook mybook2=new myBook("Java Programming");mybook1.infoPrint();mybook2.infoPrint();
在這一段程序中,我們定義了兩個(gè)myBook類(lèi)的對(duì)象mybook1和mybook2,并且調(diào)用它的構(gòu)造器方法,將其成員變量bookName的值分別設(shè)置為“C Progamming”和“Java Programming”。
我們并沒(méi)有為ownerName賦值呀,為什么會(huì)輸出呢?這是因?yàn)槲覀冊(cè)趍yBook類(lèi)的定義中就為其賦值為“XuFen”了。所有每一個(gè)myBook類(lèi)的對(duì)象都有這個(gè)成員變量了。
mybook1.bookName="C Programming";mybook1.ownerName=”XuFeng”;mybook1.infoPrint();mybook2.infoPrint();