Java入門系列之訪問修飾符作用范圍


前言

之前以為Java和C#中訪問修飾符差不多一樣,后面才了解到還是有些差異,本節只講解學習Java中訪問修飾符一些需要注意的地方或者從概念上不太好理解我們會通過實際例子來說明,若有錯誤之處,還請批評指正。

訪問修飾符

Java默認(Default)訪問修飾符權限和C#中類似(在C#中准確的說嵌套在其他類中默認可以為私有,如果直接在命名空間聲明的類或結構體可以是public,也可以是internal,但一定不是私有,這里請注意),如果不提供任何訪問修飾符,那么該類將具有包訪問權限,比如如下在包com.company下創建不帶訪問修飾符的Person,然后再在該包中創建Person1,在該類中我們可以初始化Person

package com.company;

class Person {

}
package com.company;

public class Person1 {
    public  void  InitialPerson(){
        new Person();
    }
}

但是接下來我們再創建一個包com.company1,在其包下通過Person2則不能初始化Person,此時必然會出現編譯錯誤

package com.company1;

import com.company.Person;

public class Person2 {
    public  void  InitialPerson(){
        new Person();
    }
}

對於private私有修飾符則沒有太多要講解的了,除了包含該成員的類外,其他任何類都無法訪問此類成員,Java中比較難理解的是protected修飾符, 該訪問修飾符無論是Java還是C#主要用來處理繼承的概念,憑借我們對C#的理解,這里我們認為是本包任何類以及實現該類的子類(不管子類是否在本包中還是其他包中) ,這種說法是完全正確的嗎?子類在同一包中肯定可以訪問,我們討論在不同包中的情況會略顯復雜一些,首先我們在包com.company定義Animal類,而在包com.company1中定義Tiger類,同時定義一個訪問修飾符為protected的動物叫的方法如下:

package com.company;

public class Animal {
    protected void Shout(){
        System.out.println("Animal");
    }
}
package com.company1;

import com.company.Animal;

public class Tiger extends Animal {

}

接下來我們再在包com.company中定義一個類,然后在該類中定義方法,將上述位於不同包中的Animal和Tiger類作為參數變量,此時可以訪問叫的方法

package com.company;

import com.company1.Tiger;

public class OtherAnimal {
    public void OtherMethod(Animal animal, Tiger tiger)
    {
        animal.Shout();
        tiger.Shout();
    }
}

然后我們再在Tiger子類定義一個方法,無論是通過當前實例引用還是直接通過super關鍵字調用,都可以調用基類的叫方法

package com.company;

import com.company1.Tiger;

public class OtherAnimal {
    public void OtherMethod(Animal animal, Tiger tiger)
    {
        animal.Shout();
        tiger.Shout();
    }
}

當然若我們在基類Animal中定義方法通過其基類變量訪問叫的方法毫無疑問也是可以的,即使將叫的方法設置為私有的,因為在其基類內部

public void AnimalMethod(Animal animal) {
    animal.Shout();
}

若我們在子類Tiger中再定義一個方法,將Tiger作為變量傳遞進去,此時也是可以訪問基類的叫方法

public void tigerMethod1(Tiger tiger) {
    tiger.Shout();
}

已經列舉如上諸多情況,那是不是就說明在子類中一定能訪問到叫方法呢?當然不是,如下兩種情況則是無效的,會出現編譯錯誤。

當在基類包外直接引用基類變量訪問無效

我們在子類中再定義一個方法,直接引用基類的變量,然后訪問叫方法,此時將無效。因為protected具有包訪問權限,使得直接訪問基類受保護成員變為私有或者說直接引用基類變量,無法判斷其類型,因為可能在運行時是基類中的其他子類型,這么講是否會更妥當一點。

public void tigerMethod2(Animal animal)
{
    //發生編譯錯誤
    animal.Shout();
}

當在子類包中的非子類直接引用子類變量訪問無效

我們在子類所在包中再定義一個類,然后引用子類變量訪問叫方法,此時將無效。因為子類從其基類繼承受保護的成員,此時會使它們對非子類私有:

package com.company1;

public class Tiger1 {
    public  void  tiger1Method(Tiger tiger){
        //發生編譯錯誤
        tiger.Shout();
    }
} 

總結

網上有一部分文章對protected的總結是:本包任何類以及實現該類的子類(不管子類是否在本包中還是其他包中),這種說法不能說錯誤,只能說意思比較隱晦,因為直接讀這段話可能就只考慮了在子類中通過子類實例或直接通過關鍵字super調用基類的受保護的成員,而可能會欠缺對非子類和直接通過基類引用受保護的成員的考慮。 protected修飾符無論是Java亦或是C#具有兩層概念訪問權限的組合,一是基於程序集(C#)、包(Java)權限、二是繼承權限。所以對於Java的protected訪問權限可總結為:本包任何類以及實現該類的子類,無論子類位於本包還是不同包,但對基類外部包直接訪問私有,同時對外部包中非子類私有。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM