2009-01-16 169 views
12

關鍵字protected授予訪問同一包和子類中的類的權限(http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html)。如何保護java.lang.Object的受保護方法免受子類攻擊?

現在,每個班級都有java.lang.Object作爲超類(http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html)。

因此,我得出結論,即使他們是protected,每個班級都可以訪問java.lang.Object的方法。

看看下面的例子:

 
public class Testclass { 
    public Object getOne() throws CloneNotSupportedException { 
    return this.clone(); 
    } 
    public Object getTwo() throws CloneNotSupportedException { 
    return ((Object) this).clone(); 
    } 
} 

雖然getOne()編譯罰款,getTwo()

 
Testclass.java:6: clone() has protected access in java.lang.Object 
     return ((Object) this).clone(); 

我也不明白爲什麼getTwo()沒有編制,也沒有什麼區別(關於訪問java.lang.Object s會員)與getOne()

+0

很難相信當我看着`Clonable`和`Object.clone()`時,我有完全相同的困惑 - 謝謝。 – wulfgarpro 2011-10-14 02:05:34

回答

16

如果您引用的表達式的編譯時類型是您自己的類或子類,則只能訪問不同包中的類型的受保護成員。 (其中「你的」類是包含代碼的類)。你自己的類也必須是最初聲明該方法的類型的子類。

下面是一個例子;假設Base是在不同的包到所有其他類:

package first; 
public class Base 
{ 
    protected void Foo() {} 
} 

// Yes, each class is really in its own file normally - but treat 
// all the classes below as being in package "second" 

package second; 
public class Child extends Base 
{ 
    public void OtherMethod(Object x) 
    { 
     ((Base) x).Foo(); // Invalid: Base is not Child or subclass 
     ((Child) x).Foo(); // Valid: Child is Child 
     ((GrandChild) x).Foo(); // Valid: GrandChild is subclass of Child 
     ((OtherChild) x).Foo(); // Invalid: OtherChild is not Child or subclass 
    } 
} 

public class GrandChild extends Child {} 
public class OtherChild extends Base {} 

換句話說,它讓你有機會獲得「這是一個像你這樣的對象」的保護成員。

詳細信息可在section 6.6.2 of the Java Language Specification

protected構件或 構造方法的對象可以從外部 其中它僅由代碼中聲明 包,負責 的該實現被訪問目的。

6.6.2.1訪問受保護的成員

Ç是其中 保護成員被聲明的類。訪問 僅允許在 子類SC的正文內。另外,如果標識 表示實例字段或實例 方法,則:如果訪問是由 限定名Q.Id,其中QExpressionName,則訪問被許可 如果且僅當 表達Q類型是小號一個子類小號。如果接入是由現場訪問 表達E.Id,其中Ë 表達,或通過一個方法調用 表達E.Id(。),其中È表達,則該訪問被允許 當且僅當Ë 的類型是小號小號一個子類。

5

當你說「((Object) this).clone()」時,你通過它的超類Object訪問了你自己的對象。您對對象執行了擴展轉換。然後代碼嘗試在Object上調用clone。

但是,正如你所說的,clone是一種受保護的方法,這意味着只有當你的對象與java.lang在同一個包中時,它才能夠訪問OBJECT的clone方法。

當你說this.clone時,你的類擴展了Object,因此可以通過繼承來直接通過protected class修飾符覆蓋或使用clone。但是這並不會改變對象的實現。

通過說((Object)yourObject),您可以獲得只能通過Object類訪問的內容。只有Object類的公共方法可以在java.lang包的外部訪問,所以你得到編譯時異常,因爲編譯器知道這一點。

通過說this.clone(),您正在調用通過Object繼承而獲得的對象的克隆方法,現在可以調用它,因爲它已成爲您的自定義子類的一部分。

+0

您使用受保護程序包的保護令人困惑。 – 2009-01-16 19:49:04

+0

我不這麼認爲:「當你說this.clone時,你的類擴展了Object,因此可以直接通過受保護的類修飾符覆蓋或使用克隆,因爲繼承了」 – 2009-01-16 19:50:50

1

不同之處在於您如何訪問Object.clone()。克隆只有在通過同一包中的子類或類訪問時纔可訪問。在getOne()示例中,您正在調用this.clone()。這顯然滿足了從一個子類中的訪問。

在getTwo()雖然你正在接觸Object.clone()和不是 TestClass.clone()。爲了使其發揮作用,您必須具有對象的包級別訪問權限,因此您不需要,因此也是錯誤。