好東西分享
我們來看看這么一道題:
- class ?ParentClass?{ ??
- ???? public ? int ?i?=? 10 ; ??
- } ??
- ??
- public ? class ?SubClass? extends ?ParentClass?{ ??
- ???? public ? int ?i?=? 30 ; ??
- ??
- ???? public ? static ? void ?main(String[]?args)?{ ??
- ????????ParentClass?parentClass?=? new ?SubClass(); ??
- ????????SubClass?subClass?=? new ?SubClass(); ??
- ????????System.out.println(parentClass.i?+?subClass.i); ??
- ????} ??
- }??
class ParentClass { public int i = 10; } public class SubClass extends ParentClass { public int i = 30; public static void main(String[] args) { ParentClass parentClass = new SubClass(); SubClass subClass = new SubClass(); System.out.println(parentClass.i + subClass.i); } }
控制臺(tái)的輸出結(jié)果是多少呢?20?40?還是60?
變量,或者叫做類的屬性,在繼承的情況下,如果父類和子類存在同名的變量會(huì)出現(xiàn)什么情況呢?這就是這道題要考查的知識(shí)點(diǎn)——變量(屬性)的覆蓋。
這個(gè)問題雖然簡單,但是情況卻比較復(fù)雜。因?yàn)槲覀儾粌H要考慮變量、靜態(tài)變量和常量三種情況,還要考慮private、friendly(即不加訪問修飾符)、protected和public四種訪問權(quán)限下對(duì)屬性的不同影響。
我們先從普通變量說起。依照我們的慣例,先來看一段代碼:
- class ?ParentClass?{ ??
- ???? private ?String?privateField?=? "父類變量--private" ; ??
- ??
- ???? /*?friendly?*/ String?friendlyField?=? "父類變量--friendly" ; ??
- ??
- ???? protected ?String?protectedField?=? "父類變量--protected" ; ??
- ??
- ???? public ?String?publicField?=? "父類變量--public" ; ??
- ??
- ???? //?private的變量無法直接訪問,因此我們給他增加了一個(gè)訪問方法 ??
- ???? public ?String?getPrivateFieldValue()?{ ??
- ???????? return ?privateField; ??
- ????} ??
- } ??
- ??
- public ? class ?SubClass? extends ?ParentClass?{ ??
- ???? private ?String?privateField?=? "子類變量--private" ; ??
- ??
- ???? /*?friendly?*/ String?friendlyField?=? "子類變量--friendly" ; ??
- ??
- ???? protected ?String?protectedField?=? "子類變量--protected" ; ??
- ??
- ???? public ?String?publicField?=? "子類變量--public" ; ??
- ??
- ???? //?private的變量無法直接訪問,因此我們給他增加了一個(gè)訪問方法 ??
- ???? public ?String?getPrivateFieldValue()?{ ??
- ???????? return ?privateField; ??
- ????} ??
- ??
- ???? public ? static ? void ?main(String[]?args)?{ ??
- ???????? //?為了便于查閱,我們統(tǒng)一按照private、friendly、protected、public的順序 ??
- ???????? //?輸出下列三種情況中變量的值 ??
- ??
- ???????? //?ParentClass類型,ParentClass對(duì)象 ??
- ????????ParentClass?parentClass?=? new ?ParentClass(); ??
- ????????System.out.println( "ParentClass?parentClass?=?new?ParentClass();" ); ??
- ????????System.out.println(parentClass.getPrivateFieldValue()); ??
- ????????System.out.println(parentClass.friendlyField); ??
- ????????System.out.println(parentClass.protectedField); ??
- ????????System.out.println(parentClass.publicField); ??
- ??
- ????????System.out.println(); ??
- ??
- ???????? //?ParentClass類型,SubClass對(duì)象 ??
- ????????ParentClass?subClass?=? new ?SubClass(); ??
- ????????System.out.println( "ParentClass?subClass?=?new?SubClass();" ); ??
- ????????System.out.println(subClass.getPrivateFieldValue()); ??
- ????????System.out.println(subClass.friendlyField); ??
- ????????System.out.println(subClass.protectedField); ??
- ????????System.out.println(subClass.publicField); ??
- ??
- ????????System.out.println(); ??
- ??
- ???????? //?SubClass類型,SubClass對(duì)象 ??
- ????????SubClass?subClazz?=? new ?SubClass(); ??
- ????????System.out.println( "SubClass?subClazz?=?new?SubClass();" ); ??
- ????????System.out.println(subClazz.getPrivateFieldValue()); ??
- ????????System.out.println(subClazz.friendlyField); ??
- ????????System.out.println(subClazz.protectedField); ??
- ????????System.out.println(subClazz.publicField); ??
- ????} ??
- }??
class ParentClass { private String privateField = "父類變量--private"; /* friendly */String friendlyField = "父類變量--friendly"; protected String protectedField = "父類變量--protected"; public String publicField = "父類變量--public"; // private的變量無法直接訪問,因此我們給他增加了一個(gè)訪問方法 public String getPrivateFieldValue() { return privateField; } } public class SubClass extends ParentClass { private String privateField = "子類變量--private"; /* friendly */String friendlyField = "子類變量--friendly"; protected String protectedField = "子類變量--protected"; public String publicField = "子類變量--public"; // private的變量無法直接訪問,因此我們給他增加了一個(gè)訪問方法 public String getPrivateFieldValue() { return privateField; } public static void main(String[] args) { // 為了便于查閱,我們統(tǒng)一按照private、friendly、protected、public的順序 // 輸出下列三種情況中變量的值 // ParentClass類型,ParentClass對(duì)象 ParentClass parentClass = new ParentClass(); System.out.println("ParentClass parentClass = new ParentClass();"); System.out.println(parentClass.getPrivateFieldValue()); System.out.println(parentClass.friendlyField); System.out.println(parentClass.protectedField); System.out.println(parentClass.publicField); System.out.println(); // ParentClass類型,SubClass對(duì)象 ParentClass subClass = new SubClass(); System.out.println("ParentClass subClass = new SubClass();"); System.out.println(subClass.getPrivateFieldValue()); System.out.println(subClass.friendlyField); System.out.println(subClass.protectedField); System.out.println(subClass.publicField); System.out.println(); // SubClass類型,SubClass對(duì)象 SubClass subClazz = new SubClass(); System.out.println("SubClass subClazz = new SubClass();"); System.out.println(subClazz.getPrivateFieldValue()); System.out.println(subClazz.friendlyField); System.out.println(subClazz.protectedField); System.out.println(subClazz.publicField); } }
這段代碼的運(yùn)行結(jié)果如下:
- ParentClass parentClass = new ParentClass();
- 父類變量--private
- 父類變量--friendly
- 父類變量--protected
- 父類變量--public
- ParentClass subClass = new SubClass();
- 子類變量--private
- 父類變量--friendly
- 父類變量--protected
- 父類變量--public
- SubClass subClazz = new SubClass();
- 子類變量--private
- 子類變量--friendly
- 子類變量--protected
- 子類變量--public
從上面的結(jié)果中可以看出,private的變量與其它三種訪問權(quán)限變量的不同,這是由于方法的重寫(override)而引起的。關(guān)于重寫知識(shí)的回顧留給以后的章節(jié),這里我們來看一下其它三種訪問權(quán)限下變量的覆蓋情況。
分析上面的輸出結(jié)果就會(huì)發(fā)現(xiàn),變量的值取決于我們定義的變量的類型,而不是創(chuàng)建的對(duì)象的類型。
在上面的例子中,同名的變量訪問權(quán)限也是相同的,那么對(duì)于名稱相同但是訪問權(quán)限不同的變量,情況又會(huì)怎樣呢?事實(shí)勝于雄辯,我們繼續(xù)來做測(cè)試。由于private變量的特殊性,在接下來的實(shí)驗(yàn)中我們都把它排除在外,不予考慮。
由于上面的例子已經(jīng)說明了,當(dāng)變量類型是父類(ParentClass)時(shí),不管我們創(chuàng)建的對(duì)象是父類(ParentClass)的還是子類(SubClass)的,都不存在屬性覆蓋的問題,因此接下來我們也只考慮變量類型和創(chuàng)建對(duì)象都是子類(SubClass)的情況。
- class ?ParentClass?{ ??
- ???? /*?friendly?*/ String?field?=? "父類變量" ; ??
- } ??
- ??
- public ? class ?SubClass? extends ?ParentClass?{ ??
- ???? protected ?String?field?=? "子類變量" ; ??
- ??
- ???? public ? static ? void ?main(String[]?args)?{ ??
- ????????SubClass?subClass?=? new ?SubClass(); ??
- ????????System.out.println(subClass.field); ??
- ????} ??
- }??
class ParentClass { /* friendly */String field = "父類變量"; } public class SubClass extends ParentClass { protected String field = "子類變量"; public static void main(String[] args) { SubClass subClass = new SubClass(); System.out.println(subClass.field); } }
運(yùn)行結(jié)果:
- 子類變量
?
- class ?ParentClass?{ ??
- ???? public ?String?field?=? "父類變量" ; ??
- } ??
- ??
- public ? class ?SubClass? extends ?ParentClass?{ ??
- ???? protected ?String?field?=? "子類變量" ; ??
- ??
- ???? public ? static ? void ?main(String[]?args)?{ ??
- ????????SubClass?subClass?=? new ?SubClass(); ??
- ????????System.out.println(subClass.field); ??
- ????} ??
- }??
class ParentClass { public String field = "父類變量"; } public class SubClass extends ParentClass { protected String field = "子類變量"; public static void main(String[] args) { SubClass subClass = new SubClass(); System.out.println(subClass.field); } }
運(yùn)行結(jié)果:
- 子類變量
上面兩段不同的代碼,輸出結(jié)果確是相同的。事實(shí)上,我們可以將父類和子類屬性前的訪問修飾符在friendly、protected和public之間任意切換,得到的結(jié)果都是相同的。也就是說訪問修飾符并不影響屬性的覆蓋,關(guān)于這一點(diǎn)大家可以自行編寫測(cè)試代碼驗(yàn)證。
對(duì)于靜態(tài)變量和常量又會(huì)怎樣呢?我們繼續(xù)來看:
- class ?ParentClass?{ ??
- ???? public ? static ?String?staticField?=? "父類靜態(tài)變量" ; ??
- ??
- ???? public ? final ?String?finalField?=? "父類常量" ; ??
- ??
- ???? public ? static ? final ?String?staticFinalField?=? "父類靜態(tài)常量" ; ??
- } ??
- ??
- public ? class ?SubClass? extends ?ParentClass?{ ??
- ???? public ? static ?String?staticField?=? "子類靜態(tài)變量" ; ??
- ??
- ???? public ? final ?String?finalField?=? "子類常量" ; ??
- ??
- ???? public ? static ? final ?String?staticFinalField?=? "子類靜態(tài)常量" ; ??
- ??
- ???? public ? static ? void ?main(String[]?args)?{ ??
- ????????SubClass?subClass?=? new ?SubClass(); ??
- ????????System.out.println(SubClass.staticField); ??
- ???????? //?注意,這里的subClass變量,不是SubClass類 ??
- ????????System.out.println(subClass.finalField); ??
- ????????System.out.println(SubClass.staticFinalField); ??
- ????} ??
- }??
class ParentClass { public static String staticField = "父類靜態(tài)變量"; public final String finalField = "父類常量"; public static final String staticFinalField = "父類靜態(tài)常量"; } public class SubClass extends ParentClass { public static String staticField = "子類靜態(tài)變量"; public final String finalField = "子類常量"; public static final String staticFinalField = "子類靜態(tài)常量"; public static void main(String[] args) { SubClass subClass = new SubClass(); System.out.println(SubClass.staticField); // 注意,這里的subClass變量,不是SubClass類 System.out.println(subClass.finalField); System.out.println(SubClass.staticFinalField); } }
運(yùn)行結(jié)果如下:
- 子類靜態(tài)變量
- 子類常量
- 子類靜態(tài)常量
雖然上面的結(jié)果中包含“子類靜態(tài)變量”和“子類靜態(tài)常量”,但這并不表示父類的“靜態(tài)變量”和“靜態(tài)常量”可以被子類覆蓋,因?yàn)樗鼈兌际菍儆陬悾粚儆趯?duì)象。
上面的例子中,我們一直用對(duì)象來對(duì)變量(屬性)的覆蓋做測(cè)試,如果是基本類型的變量,結(jié)果是否會(huì)相同呢?答案是肯定的,這里我們就不再一一舉例說明了。
最后,我們來做個(gè)總結(jié)。通過以上測(cè)試,可以得出一下結(jié)論:
- 由于private變量受訪問權(quán)限的限制,它不能被覆蓋。
- 屬性的值取父類還是子類并不取決于我們創(chuàng)建對(duì)象的類型,而是取決于我們定義的變量的類型。
- friendly、protected和public修飾符并不影響屬性的覆蓋。
- 靜態(tài)變量和靜態(tài)常量屬于類,不屬于對(duì)象,因此它們不能被覆蓋。
- 常量可以被覆蓋。
- 對(duì)于基本類型和對(duì)象,它們適用同樣的覆蓋規(guī)律。
我們?cè)倩氐狡椎哪堑李},我想大家都已經(jīng)知道答案了,輸出結(jié)果應(yīng)該是40。
?
向原作者致敬,轉(zhuǎn)自:
作者:臧圩人(zangweiren)
網(wǎng)址:
http://zangweiren.iteye.com
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
