[英]Overridden methods and variables - Inconsistent behavior
當可見性更改為private
時,以下代碼在重寫的方法getName()
上產生編譯時錯誤
這是可以理解的,但奇怪的是,被覆蓋的變量不會產生任何錯誤。
class Base {
public String getName() {
return "Base";
}
public String className = "Base";
}
class Derived extends Base {
private String getName() { //Not compiling
return "derived";
}
private String className = "Derived"; //Compiling successfully
}
public class Test{
public static void main(String[] args) {
System.out.println((new Derived()).className);// Gives compilation error
}
有人可以幫助我了解為什么會這樣嗎?
雖然我們嘗試在main()
編譯中訪問私有變量失敗,但是在方法本身上,當我將訪問類型從public減少為private時,它成功編譯也應該在那里失敗 。
標准(§8.4.8.3)禁止使用較弱的訪問修飾符覆蓋方法:
覆蓋或隱藏方法的訪問修飾符(第6.6節)必須至少提供與覆蓋或隱藏方法相同的訪問權限,如下所示:
如果覆蓋或隱藏方法是公共的,則覆蓋或隱藏方法必須是公共的; 否則,將發生編譯時錯誤。
如果覆蓋或隱藏方法受到保護,則覆蓋或隱藏方法必須受到保護或公開; 否則,將發生編譯時錯誤。
如果覆蓋或隱藏方法具有默認(程序包)訪問權限,則覆蓋或隱藏方法不能為私有方法;否則,不能為私有方法。 否則,將發生編譯時錯誤。
這確保了基類提供的任何方法也可以在同一上下文中的派生類上調用。
變量不能被覆蓋。 Base.className
和Derived.className
是兩個不同的變量。 因此,在Derived
具有相同名稱和不同訪問修飾符的變量是完全有效的。
即此代碼將打印false
:
class Base{
public String str = "hello";
}
class Derived extends Base{
private String str = "whatever";
public Derived(){
super.str = "abc";
str = "def";
}
void foo(){
System.out.println(str.equals(super.str));
}
}
public static void main(String[] args){
new Derived().foo();
}
相關的jls部分:
§6.3和§6.4中指定了字段聲明的范圍和陰影。
如果類聲明了具有特定名稱的字段,則稱該字段的聲明隱藏了超類和該類的超接口中所有相同名稱的字段的所有可訪問聲明。
在這方面,字段的隱藏不同於方法的隱藏(第8.4.8.3節),因為在字段隱藏中靜態字段和非靜態字段之間沒有區別,而在方法隱藏中靜態方法和非靜態方法之間沒有區別。
如果隱藏字段是靜態的,則可以使用限定名對其進行訪問(第6.5.6.2節),也可以使用包含關鍵字super(第15.11.2節)或強制轉換為超類類型的字段訪問表達式進行訪問。
在這方面,字段的隱藏類似於方法的隱藏。
如果字段聲明隱藏了另一個字段的聲明,則兩個字段不必具有相同的類型。
和陰影(§6.4.1) :
在整個d范圍內,名為n的字段或形式參數的聲明d在整個d范圍內,在d發生時在范圍內的任何其他名為n的變量的聲明。
您不能override
字段,而只能hide
其hide
。 這意味着您只需創建具有相同名稱的新變量即可。
從JLS 字段聲明
如果類聲明了具有特定名稱的字段,則稱該字段的聲明隱藏了超類和該類的超接口中所有相同名稱的字段的所有可訪問聲明。
無法使用限制性更強的訪問說明符覆蓋方法(例如,當超類中的方法為public
時,則為private
)。 如果有可能,您將能夠做一些奇怪的事情,例如調用不應訪問的private
方法:
Derived object1 = new Derived();
// Will give an error, because getName() is private
String name1 = object1.getName();
Base object2 = new Derived();
// Should this be possible because getName() is public in Base?
// (Note that object2 is of type Base).
// But that would be strange, because the method is overridden
// in Derived, so we would be calling a private method here that
// should not be accessible from the outside!
String name2 = object2.getName();
在將超類的方法重寫為子類時,訪問級別可以保持不變,也可以更寬/更寬(即,增加子類中重寫方法的訪問可見性)。
因此,如果您的基類方法是公共方法,則不能將其重寫為私有方法或受保護方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.