第3章 面向?qū)ο蟮暮诵奶卣?/span>
3-1?什么是類?什么是對(duì)象?他們之間的關(guān)系是怎樣的?
【答】在面向?qū)ο蟮母拍钪?,類是既包括?shù)據(jù)又包括作用于數(shù)據(jù)的一組操作的封裝體。類中的數(shù)據(jù)稱為成員變量,類中的數(shù)據(jù)操作稱為成員方法。類中的成員變量和成員方法統(tǒng)稱為類的成員。
?對(duì)象是類的實(shí)例。對(duì)象與類的關(guān)系就像變量與數(shù)據(jù)類型的關(guān)系一樣。是抽象與具體,模板與實(shí)例的關(guān)系,類是抽象的、是模板,對(duì)象是具體的、是實(shí)例。
?
3-2?作為引用數(shù)據(jù)類型,對(duì)象在賦值和方法的參數(shù)傳遞方面與基本數(shù)據(jù)類型的變量有什么不同?
【答】作為引用數(shù)據(jù)類型,兩個(gè)對(duì)象之間的賦值是引用賦值,對(duì)象可被賦值為null。具體可參見課本第三章圖3.1的(d)。方法聲明中形式參數(shù)的數(shù)據(jù)類型,既可以是基本數(shù)據(jù)類型,也可以是引用數(shù)據(jù)類型。如果形式參數(shù)的數(shù)據(jù)類型是基本數(shù)據(jù)類型,則實(shí)際參數(shù)向形式參數(shù)傳遞的是值;如果形參的數(shù)據(jù)類型是引用數(shù)據(jù)類型,則實(shí)參向形參傳遞的是引用。
同樣,方法返回值的數(shù)據(jù)類型,既可以是基本數(shù)據(jù)類型,也可以是引用數(shù)據(jù)類型,兩者分別傳遞值和引用。
?
3-3?面向?qū)ο蠹夹g(shù)的三個(gè)核心特性是什么?
【答】類的封裝、繼承和多態(tài)。
?
3-4?什么是封裝?為什么要將類封裝起來?封裝的原則是什么?
【答】封裝性是面向?qū)ο蟮暮诵奶卣髦?,它提供一種信息隱藏技術(shù)。
類的封裝包含兩層含義:一是將數(shù)據(jù)和對(duì)數(shù)據(jù)的操作組合起來構(gòu)成類,類是一個(gè)不可分割的獨(dú)立單位;二是類中既要提供與外部聯(lián)系的方法,同時(shí)又要盡可能隱藏類的實(shí)現(xiàn)細(xì)節(jié)。軟件擴(kuò)充和維護(hù)的需要需對(duì)類進(jìn)行封裝。封裝原則:隱藏內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。
?
3-5?類中的方法與C++中的函數(shù)有什么差別?
【答】Java類中的成員方法與C語言中的函數(shù)很像,但在聲明、調(diào)用等方面存在很大差別。具體方法可參考課本P66~P67。
?
3-6?類的構(gòu)造方法和析構(gòu)方法有什么作用?它們分別被誰調(diào)用?它們的訪問權(quán)限范圍應(yīng)該是怎樣的?是否每個(gè)類都必須設(shè)計(jì)構(gòu)造方法和析構(gòu)方法?沒有設(shè)計(jì)構(gòu)造方法和析構(gòu)方法的類執(zhí)行什么構(gòu)造方法和析構(gòu)方法?
【答】類的構(gòu)造方法和析構(gòu)方法是類特殊的成員方法,構(gòu)造方法用于在創(chuàng)建實(shí)例時(shí)進(jìn)行初始化;析構(gòu)方法用于在釋放實(shí)例時(shí)執(zhí)行特定操作。構(gòu)造方法由new運(yùn)算符調(diào)用;析構(gòu)方法可由對(duì)象調(diào)用,或被虛擬機(jī)自動(dòng)執(zhí)行。它們的訪問權(quán)限范圍通常都是public。
構(gòu)造方法不能繼承,析構(gòu)方法能夠繼承。一個(gè)類可以不聲明構(gòu)造方法和析構(gòu)方法。當(dāng)一個(gè)類沒有聲明構(gòu)造方法時(shí),Java為它提供一個(gè)無參數(shù)的默認(rèn)構(gòu)造方法,約定自動(dòng)調(diào)用父類的默認(rèn)構(gòu)造方法(無參數(shù));當(dāng)一個(gè)類沒有聲明析構(gòu)方法時(shí),它執(zhí)行繼承來的父類的析構(gòu)方法。
?
3-7 Java定義了幾個(gè)關(guān)鍵字用于表示幾種訪問權(quán)限?各表示什么含義?類有幾種訪問權(quán)限?類中成員有幾種訪問權(quán)限?分別使用什么關(guān)鍵字?
【答】Java定義了三個(gè)表示權(quán)限的關(guān)鍵字(public、protected、private)。類有2種訪問權(quán)限分別是:公有public,缺省。類中成員有4種訪問權(quán)限分別是:公有public,可被所有類訪問;保護(hù)protected,可被同一包及包外所有子類訪問;缺省,可被當(dāng)前包中所有類訪問;私有private,只能被當(dāng)前類訪問。
?
3-8?this引用有什么作用?this引用有幾種使用方法?
【答】Java類中成員方法與C語言中函數(shù)還有一個(gè)重要差別就是,Java類中每個(gè)成員方法都可以使用代詞this引用調(diào)用該方法的當(dāng)前對(duì)象自己,this引用有以下3種用法:
(1)this用于指代調(diào)用成員方法的當(dāng)前對(duì)象自身,語法格式如下:
??? this
(2)通過this可以調(diào)用當(dāng)前對(duì)象的成員變量,調(diào)用當(dāng)前對(duì)象的成員方法。語法格式如下:
??? this.成員變量
? ??this.成員方法([參數(shù)列表])注意:Java中的this是引用方式,不是C++中的指針方式。
(3)this引用還可以用在重載的構(gòu)造方法中,調(diào)用本類已定義好的構(gòu)造方法。語法格式如下:
?? this([參數(shù)列表])注意:在構(gòu)造方法中,this()引用必須是第一行語句。
?
3-9?說明類成員與實(shí)例成員的區(qū)別。
【答】Java的類中可以包括兩種成員:實(shí)例成員和類成員。
實(shí)例成員是屬于對(duì)象的,實(shí)例成員包括實(shí)例成員變量和實(shí)例成員方法。類成員是屬于類的,需要用關(guān)鍵字static標(biāo)識(shí),也稱為靜態(tài)成員。具體區(qū)別如下:
1.實(shí)例成員變量與類成員變量
?? (1)?兩者聲明時(shí)的差別。當(dāng)一個(gè)類聲明成員變量時(shí),沒有使用關(guān)鍵字static聲明的為實(shí)例成員變量,使用關(guān)鍵字static聲明的為類成員變量。
(2)?兩者存儲(chǔ)結(jié)構(gòu)的差別。當(dāng)創(chuàng)建一個(gè)對(duì)象時(shí),系統(tǒng)會(huì)為每一個(gè)對(duì)象的每一個(gè)實(shí)例成員變量分配一個(gè)存儲(chǔ)單元,使得屬于不同對(duì)象的實(shí)例成員變量有不同的值;而為每一個(gè)類成員變量只分配一個(gè)存儲(chǔ)單元,使得所有對(duì)象公用一個(gè)類成員變量。
(3)?兩者引用方式的差別。實(shí)例成員變量屬于對(duì)象,必須通過對(duì)象訪問;類成員變量屬于類,既可以通過對(duì)象,也可以通過類訪問。
2.實(shí)例成員方法與類成員方法
?(1)?兩者聲明時(shí)的差別。當(dāng)一個(gè)類聲明成員方法時(shí),沒有使用關(guān)鍵字static聲明的為實(shí)例成員方法,使用關(guān)鍵字static聲明的為類成員方法。
(2)?兩者方法體中語句的差別。類成員方法只能訪問類成員變量;實(shí)例成員方法既可以訪問類成員變量,也可以訪問實(shí)例成員變量。在實(shí)例成員方法體中,可以使用this引用指代當(dāng)前對(duì)象;而在類成員方法體中,則不能使用this引用。
(3)?兩者引用方式的差別。實(shí)例成員方法必須通過對(duì)象訪問;類成員方法既可以通過對(duì)象,也可以通過類訪問。
?
3-10?什么是繼承?繼承機(jī)制的作用是什么?子類繼承了父類中的什么?子類不需要父類中的成員時(shí)怎么辦?能夠刪除它們嗎?Java允許一個(gè)類有多個(gè)父類嗎?
【答】繼承性是面向?qū)ο蟮暮诵奶卣髦?,是一種由已有的類創(chuàng)建新類的機(jī)制。被繼承的類稱為父類或超類,通過繼承產(chǎn)生的新類稱為子類或派生類。繼承機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)中實(shí)現(xiàn)軟件可重用性的最重要手段。
通過繼承,子類自動(dòng)擁有父類的所有成員,包括成員變量和成員方法(不包括構(gòu)造方法)。子類可以更改父類成員,還可以增加自己的成員,但是,不能刪除父類的成員。
在Java中以“單重繼承+接口”的方式代替多重繼承,不允許一個(gè)類有多個(gè)父類。
?
3-11?子類能夠訪問父類中什么樣權(quán)限的成員?
【答】雖然子類繼承了父類的成員變量和成員方法,但并不是對(duì)所有的成員都有訪問權(quán)限。訪問權(quán)限說明如下:
?(1)子類對(duì)父類的私有成員(private)沒有訪問權(quán)限。
(2)子類對(duì)父類的公有成員(public)和保護(hù)成員(protected)具有訪問權(quán)限。
(3)子類對(duì)父類中缺省權(quán)限成員訪問權(quán)限分為兩種情況,對(duì)同一包中父類的缺省權(quán)限成員具有訪問權(quán)限,而對(duì)不同包中父類的缺省權(quán)限成員沒有訪問權(quán)限。
?
3-12?如果子類聲明的成員與父類成員同名會(huì)怎么樣?
【答】如果子類重定義父類的同名成員變量,則子類隱藏了父類成員變量。如果子類重定義父類的同名成員方法,當(dāng)子類方法的參數(shù)列表與父類方法的參數(shù)列表完全相同時(shí),則稱子類成員方法覆蓋了成員方法。如果子類重定義父類的同名成員方法,當(dāng)子類方法的參數(shù)列表與父類方法的參數(shù)列表不同時(shí),子類繼承了父類的成員方法,并重載了繼承來的該成員方法。
?
3-13 super引用有什么作用?super引用有幾種使用方法?
【答】當(dāng)子類重定義了父類成員時(shí),則存在同名成員問題。此時(shí),在子類方法體中,成員均默認(rèn)為子類成員。如果需要引用父類同名成員,則需要使用supper引用。在以下兩種同名成員情況下,需要使用supper引用。
(1)子類隱藏父類成員時(shí),如需要訪問父類同名成員變量時(shí),需要使用supper指代父類的同名成員變量。語法如下:
????? super.成員變量
(2)子類覆蓋父類成員時(shí),如需要訪問父類同名成員方法時(shí),需要使用supper指代父類的同名成員方法。語法如下:
????? super.成員方法([參數(shù)列表])
注意:super引用不能像this引用一樣單獨(dú)使用。
?
3-14?什么是多態(tài)性?什么是方法的重載?方法的重載和覆蓋有何區(qū)別?
【答】在面向?qū)ο笳Z言中,多態(tài)是指一個(gè)方法可以有多種實(shí)現(xiàn)版本,類的多態(tài)性表現(xiàn)為方法的多態(tài)性。重載是指同一個(gè)類中的多個(gè)方法可以同名但參數(shù)列表必須不同。重載表現(xiàn)為同一個(gè)類中方法的多態(tài)性。覆蓋是指子類重定義了父類中的同名方法。覆蓋表現(xiàn)為父類與子類之間方法的多態(tài)性。
?
3-15?什么是運(yùn)行時(shí)多態(tài)?方法的重載和覆蓋分別是什么時(shí)的多態(tài)性?
【答】如果在編譯時(shí)不能確定、只有在運(yùn)行時(shí)才能確定執(zhí)行多個(gè)同名方法中的哪一個(gè),則稱為運(yùn)行時(shí)多態(tài)。方法的重載都是編譯時(shí)多態(tài)。方法的覆蓋變現(xiàn)出兩種多態(tài)性,當(dāng)對(duì)象獲得本類的實(shí)例時(shí),為編譯時(shí)多態(tài),否則為運(yùn)行時(shí)多態(tài)。
?
3-16?什么是抽象類?在什么情況下需要設(shè)計(jì)抽象類?抽象類中是否必須有抽象方法?
【答】使用關(guān)鍵字abstract聲明的類稱為抽象類,使用abstract聲明的成員方法為抽象方法。抽象類中可以不包含抽象方法,但包含抽象方法的類必須被聲明為抽象類。
3-17?什么是最終類?在什么情況下需要設(shè)計(jì)最終類?最終類中是否必須有最終方法?
【答】使用關(guān)鍵字final聲明的類稱為最終類,最終類不能被繼承。使用final聲明的成員方法稱為最終方法,最終方法不能被子類覆蓋。最終類中包含的都是最終方法,非最終類也可以包含最終方法。
?
3-18?將輾轉(zhuǎn)相除法求兩個(gè)整數(shù)的最大公因數(shù)gcd(a,b)用遞歸方法實(shí)現(xiàn),輾轉(zhuǎn)相除法題意見例2.11,再設(shè)計(jì)下列方法:
(1)求兩個(gè)整數(shù)a﹑?b的最小公倍數(shù);
(2)求三個(gè)整數(shù)a﹑b﹑c的最大公約數(shù)。
〖解答〗程序如下。
public class GCD_recursion
{
??? public static int gcd(int a,int b)?????????? ????? //返回a,b的最大公因數(shù)
??? {
?? ?????if (b==0)
??????????? return a;
???????????
??????? if (a<0)
??????????? return gcd(-a,b);
???????????
??????? if (b<0)
??????????? return gcd(a,-b);
???????????
??????? return gcd(b, a%b);
??? }
??? public static int gcd(int a,int b,int c)???? ?//返回a,b,c的最大公因數(shù)
??? {
??????? return gcd(gcd(a,b),c);
??? }
??? public static int multiple(int a,int b)????? ???????? //返回a,b的最小公倍數(shù)
??? {
??????? return a*b/gcd(a,b);
??? }
??? public static void main(String args[])
??? {
??????? int a=12,b=18,c=27;
??????? System.out.println("gcd("+a+","+b+")="+gcd(a,b));
??????? System.out.println("gcd("+(-a)+","+b+")="+gcd(-a,b));
??????? System.out.println("gcd("+a+","+b+","+c+")="+gcd(a,b,c));
??????? System.out.println("multiple("+a+","+b+")="+multiple(a,b));
??? }
}
程序運(yùn)行結(jié)果如下:
gcd(12,18)=6
gcd(-12,18)=6
gcd(12,18,27)=3
multiple(12,18)=36
?
3-19?用遞歸方法求?n個(gè)數(shù)的無重復(fù)全排列。
〖解答〗程序如下。
public class Permutation
{
??? private int[] table;
???
??? public Permutation(int n)??????????????????? ????? //構(gòu)造方法
??? {
??????? if (n>0)
??????? {
?????????? ?table = new int[n];
??????????? for (int i=0;i<n;i++)
??????????????? table[i] = i+1;
??????????? permute(n);
??????? }
??????? else
??????????? table = null;
??? }
??? private void output()??????????????????????? ???? //輸出數(shù)組元素
??? {
??????? for (int i=0;i<table.length;i++)
??????????? System.out.print("? "+table[i]);
??????? System.out.println();
??? }
??? private void swap(int i,int j)??????????????? ???????? //交換數(shù)組兩個(gè)元素值
??? {
??????? if (table!=null && i>=0 && i<table.length && j>=0 && j<table.length)
??????? {
?? ?????????int temp = table[i];
??????????? table[i] = table[j];
??????????? table[j] = temp;
??????? }
??? }
??? private void permute(int n)?????????????????? ???? //用遞歸方法求n個(gè)數(shù)的無重復(fù)全排列
??? {
??????? if (n==1)
??????????? this.output();
??????? else
??????? {
??? ????????permute(n-1);
??????????? for (int j=0;j<n-1;j++)
??????????? {
??????????????? swap(n-1,j);
??????????????? permute(n-1);
??????????????? swap(n-1,j);
??????????? }
??????? }???????
??? }
??? public static void main(String args[])
??? {
??????? new Permutation(3);
??? }
}
程序運(yùn)行結(jié)果如下:
? 1? 2? 3
? 2? 1? 3
? 3? 2? 1
? 2? 3? 1
? 1? 3? 2
? 3? 1? 2
?
3-20 Java為什么不支持指針?C++的指針類型存在哪些潛在的錯(cuò)誤?沒有指針,Java如何實(shí)現(xiàn)在C++中用指針實(shí)現(xiàn)的功能?例如,通過訪問指針訪問數(shù)組元素,通過指針使用字符串,方法參數(shù)傳遞地址,方法參數(shù)用于輸出,方法返回非基本數(shù)據(jù)類型等。
【答】由于指針往往在帶來方便的同時(shí)也導(dǎo)致代碼不安全的根源,如內(nèi)存泄露等,同時(shí)也會(huì)使程序變得非常復(fù)雜難以理解,Java語言明確說明取消了指針。Java使用引用代替了指針。
?
3-21 Java為什么不支持C++的運(yùn)算符重載特性?
【答】這是為了防止運(yùn)算符重載使得代碼的功能變的不清晰。
?