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