作者:臧圩人(zangweiren)
網址:http://zangweiren.javaeye.com
>>>轉載請註明出處!<<<
我們來看看這麼一道題:
Java代碼
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);
}
}
控制檯的輸出結果是多少呢?20?40?還是60?
變量,或者叫做類的屬性,在繼承的情況下,如果父類和子類存在同名的變量會出現什麼情況呢?這就是這道題要考查的知識點——變量(屬性)的覆蓋。
這個問題雖然簡單,但是情況卻比較複雜。因爲我們不僅要考慮變量、靜態變量和常量三種情況,還要考慮private、friendly(即不加訪問修飾符)、protected和public四種訪問權限下對屬性的不同影響。
我們先從普通變量說起。依照我們的慣例,先來看一段代碼:
Java代碼
class ParentClass {
private String privateField = "父類變量--private";
/* friendly */String friendlyField = "父類變量--friendly";
protected String protectedField = "父類變量--protected";
public String publicField = "父類變量--public";
// private的變量無法直接訪問,因此我們給他增加了一個訪問方法
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的變量無法直接訪問,因此我們給他增加了一個訪問方法
public String getPrivateFieldValue() {
return privateField;
}
public static void main(String[] args) {
// 爲了便於查閱,我們統一按照private、friendly、protected、public的順序
// 輸出下列三種情況中變量的值
// ParentClass類型,ParentClass對象
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對象
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對象
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);
}
}
這段代碼的運行結果如下:
1、ParentClass parentClass = new ParentClass();
2、父類變量--private
3、父類變量--friendly
4、父類變量--protected
5、父類變量--public
6、
7、ParentClass subClass = new SubClass();
8、子類變量--private
9、父類變量--friendly
10、父類變量--protected
11、父類變量--public
12、
13、SubClass subClazz = new SubClass();
14、子類變量--private
15、子類變量--friendly
16、子類變量--protected
17、子類變量--public
從上面的結果中可以看出,private的變量與其它三種訪問權限變量的不同,這是由於方法的重寫(override)而引起的。關於重寫知識的回顧留給以後的章節,這裏我們來看一下其它三種訪問權限下變量的覆蓋情況。
分析上面的輸出結果就會發現,變量的值取決於我們定義的變量的類型,而不是創建的對象的類型。
在上面的例子中,同名的變量訪問權限也是相同的,那麼對於名稱相同但是訪問權限不同的變量,情況又會怎樣呢?事實勝於雄辯,我們繼續來做測試。由於private變量的特殊性,在接下來的實驗中我們都把它排除在外,不予考慮。
由於上面的例子已經說明了,當變量類型是父類(ParentClass)時,不管我們創建的對象是父類(ParentClass)的還是子類
(SubClass)的,都不存在屬性覆蓋的問題,因此接下來我們也只考慮變量類型和創建對象都是子類(SubClass)的情況。
Java代碼
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);
}
}
運行結果:
1、子類變量
Java代碼
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);
}
}
運行結果:
1、子類變量
上面兩段不同的代碼,輸出結果確是相同的。事實上,我們可以將父類和子類屬性前的訪問修飾符在friendly、protected和public之間任意切換,得到的結果都是相同的。也就是說訪問修飾符並不影響屬性的覆蓋,關於這一點大家可以自行編寫測試代碼驗證。
對於靜態變量和常量又會怎樣呢?我們繼續來看:
Java代碼
class ParentClass {
public static String staticField = "父類靜態變量";
public final String finalField = "父類常量";
public static final String staticFinalField = "父類靜態常量";
}
public class SubClass extends ParentClass {
public static String staticField = "子類靜態變量";
public final String finalField = "子類常量";
public static final String staticFinalField = "子類靜態常量";
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(SubClass.staticField);
System.out.println(subClass.finalField);
System.out.println(SubClass.staticFinalField);
}
}
運行結果如下:
1、子類靜態變量
2、子類常量
3、子類靜態常量
雖然上面的結果中包含“子類靜態變量”和“子類靜態常量”,但這並不表示父類的“靜態變量”和“靜態常量”可以被子類覆蓋,因爲它們都是屬於類,而不屬於對象。
上面的例子中,我們一直用對象來對變量(屬性)的覆蓋做測試,如果是基本類型的變量,結果是否會相同呢?答案是肯定的,這裏我們就不再一一舉例說明了。
最後,我們來做個總結。通過以上測試,可以得出一下結論:
1、由於private變量受訪問權限的限制,它不能被覆蓋。
2、屬性的值取父類還是子類並不取決於我們創建對象的類型,而是取決於我們定義的變量的類型。
3、friendly、protected和public修飾符並不影響屬性的覆蓋。
4、靜態變量和靜態常量屬於類,不屬於對象,因此它們不能被覆蓋。
5、常量可以被覆蓋。
6、對於基本類型和對象,它們適用同樣的覆蓋規律。
我們再回到篇首的那道題,我想大家都已經知道答案了,輸出結果應該是40。
JAVA面試題解惑系列(三)——變量(屬性)的覆蓋
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.