2012-01-06 134 views
0

考慮以下非法代碼: -我不明白這種繼承功能

class WrongCode{ 
    int i; 
    static int i; 
} 

這裏,編譯器說,我們在同一個班級重複的字段。

現在,考慮在同一文件中的以下類。

class Parent{ 
    int i = 10; 
} 

class Child extends Parent{ 
    static int i = 100; 
} 

public class Main{ 
    public static void main(String ... aaa){ 
     Parent ob = new Child(); 
     System.out.println(ob.i); // This prints Parent's i 
    } 
} 

由於實際對象是Child,因此不應該參考Child's i嗎?如果它指的是家長的「我」,那麼在某種程度上,它也會在其自己的班級中擁有家長的「我」以及不允許的自己的靜態「我」。

孩子靜態我overshadows父母我。父母的我不是靜態的,那麼它如何直接使用實例而不是className來訪問?

+3

嘗試'Child ob = new Child();'得到派生的'i'。 – 2012-01-06 06:44:06

+0

在Child類中,讓我非靜態的,看看會發生什麼?它仍然應該打印父母我。 – 2012-01-06 06:47:13

+0

@βнɛƨнǤʋяʋиɢ讓我在Child中是非靜態的,結果相同。 – whitehat 2012-01-06 06:49:30

回答

0

ob,孩子的static int i是不可見的,因爲ob的類型是父母的,不論它是如何被實例化(基類或派生類)。

這就是爲什麼你的價值爲,即Parent s i值。

0

Java允許您的類擁有自己的變量,該變量與父類中的變量具有相同的名稱。但它不能讓你隨機重新定義父變量,因爲這會導致其他東西被破壞。所以它做什麼......當你有一個聲明爲父類的變量obj時,即使它擁有一個子類的實例,obj.i將引用父類的i而不是孩子的類。

0

當您訪問類成員字段(實例變量),如ob.i.您將從編譯時已知的類中獲得結果,而不是在運行時已知的結果。這就是爲什麼你有價值爲10,這是父母的價值。

對於方法調用,它們在運行時分派給實際類的參考點的對象。

關於陰影這裏是Java的郎規範說:

如果類聲明的字段具有特定名稱,那麼該字段的聲明說,隱藏字段的任何和所有可訪問聲明具有相同名稱在超類和類的超接口中。

隱藏字段可以通過使用一個合格的名稱(如果它是靜態的)訪問

language spec

你可以參考「字段聲明」一節。

0

實際上,它的多態性和ob只能訪問父類字段和行爲,如果有...

1

它在這裏是沒有辦法System.out.println(ob.i);實現可以打印Childi是很重要的:它只知道ob是聲明類型Parent的,不在於它是與實際Child實例化。因此,如果Parent沒有任何i,則會出現編譯錯誤。如果父母有i,則會打印。

我已經看到它在SO上提到通過實例訪問類變量(即ob.i相當於Parent.i)應該被認爲是Java的嚴重設計缺陷。我同意它有時會令人困惑。無論如何,你的父母和孩子也可以有一個非靜態的i,它不一定是相同的。上面的論點應該適用於推理在哪種情況下打印哪一個。