現上一道面試題
public class MainClass {
public static void main(String[] args) {
Fu f = new Zi();
Zi z = new Zi();
System.out.println("f.num:"+f.num);
System.out.println("z.num:"+z.num);
System.out.println("f.num:"+f.num2);
System.out.println("z.num:"+z.num2);
f.method1();
z.method1();
f.method4();
z.method4();
}
}
abstract class Fu{
public int num = 5;
public int num2 = 7;
public Fu(){
num2 = 9;
method3();
}
public void method1(){
System.out.println("Fu method1");
}
void method3(){
System.out.println("Fu method3");
}
static void method4(){
System.out.println("Fu method4");
}
}
class Zi extends Fu{
public int num = 6;
public int num2 = 8;
public void method1(){
System.out.println("Zi method1");
}
void method3(){
System.out.println("Zi method3");
}
static void method4(){
System.out.println("Zi method4");
}
}
這道題,如果不是對java的繼承處理有深刻理解,還是很難答對的。
其實掌握一個原則,就萬變不離其宗了: 對於成員方法是覆蓋,對於成員變量和靜態方法是隱藏
怎麼理解這句話呢?
1.如果子類重寫了父類的成員方法,那麼就是覆蓋,就是說 new Zi()之後,在new出來的實例中只存在子類的方法了,不管你聲明的類型是父類還是子類。
2.如果子類有父類的同名成員變量的話,那麼就是隱藏,所謂的隱藏就是new Zi()之後,在實例中會存在兩個成員變量,到底是取哪一個就是根據聲明類型來決定的。
3.如果子類重寫了父類的靜態方法,那麼也是隱藏,調用哪一個也是由聲明類型決定的。
現在我們分析上面的面試題:
Fu f = new Zi();這個肯定是最讓我們迷惑的,但是根據我們上面的原則就很好處理了,知道f.num=5,即成員變量由聲明類型決定,相當於隱藏了子類中的num變量;
f.method1()調用子類的實現,即完全覆蓋,相當於實例中只有子類一個方法了;f.method4();和成員變量處理類似,相當於隱藏了子類中的實現;
最終輸出結果:
Zi method3
Zi method3
f.num:5
z.num:6
f.num:9
z.num:8
Zi method1
Zi method1
Fu method4
Zi method4
大家應該明白了吧。