以前覺得Java和C#中訪問修飾符差很少同樣,後面才瞭解到仍是有些差別,本節只講解學習Java中訪問修飾符一些須要注意的地方或者從概念上不太好理解咱們會經過實際例子來講明,如有錯誤之處,還請批評指正。學習
Java默認(Default)訪問修飾符權限和C#中相似(在C#中準確的說嵌套在其餘類中默承認覺得私有,若是直接在命名空間聲明的類或結構體能夠是public,也能夠是internal,但必定不是私有,這裏請注意),若是不提供任何訪問修飾符,那麼該類將具備包訪問權限,好比以下在包com.company下建立不帶訪問修飾符的Person,而後再在該包中建立Person1,在該類中咱們能夠初始化Personspa
package com.company; class Person { }
package com.company; public class Person1 { public void InitialPerson(){ new Person(); } }
可是接下來咱們再建立一個包com.company1,在其包下經過Person2則不能初始化Person,此時必然會出現編譯錯誤code
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的動物叫的方法以下:blog
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關鍵字調用,均可以調用基類的叫方法it
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做爲變量傳遞進去,此時也是能夠訪問基類的叫方法class
public void tigerMethod1(Tiger tiger) { tiger.Shout(); }
已經列舉如上諸多狀況,那是否是就說明在子類中必定能訪問到叫方法呢?固然不是,以下兩種狀況則是無效的,會出現編譯錯誤。import
咱們在子類中再定義一個方法,直接引用基類的變量,而後訪問叫方法,此時將無效。由於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訪問權限可總結爲:本包任何類以及實現該類的子類,不管子類位於本包仍是不一樣包,但對基類外部包直接訪問私有,同時對外部包中非子類私有。