java權限訪問修飾符

一.java的四種訪問權限
1.幾個注意的細節:

  • 類的訪問權限只有兩種:public和default(默認包訪問權限)
  • java編譯單元概念:一個.java文件是一個編譯單元,每個編譯單元最多只能有一個public類,而且該public類名稱必須與文件的名稱相同(包括大小寫,但不包括文件後綴名.java).如果該編譯單元內還有其他類,那麼這些類只能是default權限,不能被包外訪問,而且這些類的主要作用是爲public提供支持的.
  • 構造函數也可以私有化(private),然後在類中實例化一個對象,再通過方法返回該對象
  • 成員變量(在類裏面聲明的變量)在聲明時可以不給它初始化,編譯器會自動給這個成員變量初始化,但局部變量(在方法裏面聲明的變量)在聲明時一定要給它初始化,因爲編譯器不會自動給局部變量初始化,任何變量在使用之前必須對它進行初始化。

2.Java有四種訪問權限, 其中三種有訪問權限修飾符,分別爲private,protected和public,還有一種不帶任何修飾符的默認訪問權限(也叫包訪問權限)。

  • private: Java語言中對訪問權限限制的最窄的修飾符,一般稱之爲“私有的”。被其修飾的類、屬性以及方法只能被該類的對象訪問,其子類不能訪問,更不能允許跨包訪問。
  • default:即不加任何訪問修飾符,通常稱爲”默認訪問權限”。該模式下,只允許在同一個包中進行訪問。
  • protect: 介於public 和 private 之間的一種訪問修飾符,一般稱之爲“繼承訪問權限”。被其修飾的類、屬性以及方法只能被類本身的方法及子類訪問,即使子類在不同的包中也可以訪問。
  • public: Java語言中訪問限制最寬的修飾符,一般稱之爲“公共的”。被其修飾的類、屬性以及方法不僅可以跨類訪問,而且允許跨包(package)訪問。

3.下面用表格的形式來展示四種訪問權限之間的異同點.表格如下:
(1)public修飾的類:

\ 當前類 同一個包的非子類 不同包的非子類 同一包的子類 不同包的子類
public
protected  
default    
private        

(2)默認包訪問權限的類(對於一個包裏面的包訪問權限類A,在其他package的類裏面import類A的時候就已經出錯了。所以,其他package普通類根本就訪問不了類A,其他package的類也成爲不了類A的子孫類(即默認訪問權限的類的子類只能在同一包下)):

\ 當前類 同一個包的非子類 不同包的非子類 同一包的子類 不同包的子類
public    
protected    
default    
private        

(3)詳解protected訪問權限:
說例子之前,我們應該先正確理解一句話:protected修飾的屬性或方法,表示在同一個包內或者不同包的子類可以訪問。
解析:
“不同包中的子類可以訪問”(子類可訪問,意思是用子類的對象去引用方法),是指當兩個類不在同一個包中的時候,繼承自父類的子類內部且主調(調用者)爲子類的引用時才能訪問父類用protected修飾的成員屬性或方法。 在子類內部,主調爲父類的引用時並不能訪問此protected修飾的成員(super關鍵字除外)。
我們用一個例子來仔細說明:

public class MyObject {

    public static void main(String[] args) {
        Object o1 = new Object();//Object對象有一個clone()方法,該方法是protected的
        o1.clone();//此處報錯:The method clone() from the type Object is not visible
    }

}

解析:
子類對象創建的過程,其實是先加載其父類文件,創建其父類對象之後,再加載子類文件,創建子類對象,最後形成一個包裹結構的對象(見博文《繼承》中對象創建的內存分析).如果子類沒有覆蓋父類中的屬性和方法,則子類的屬性和方法只是對父類中同名屬性和方法的引用(也就是說沒被覆蓋的方法其實是父類的);如果子類覆蓋了父類中的屬性和方法,則被覆蓋的屬性和方法是對自己的引用(也就是說被覆蓋的方法纔是子類自己的).

public class MyObject2 {

    public static void main(String[] args) throws CloneNotSupportedException {
        MyObject2 obj = new MyObject2();
        obj.clone();//編譯通過
    }

    String name = "xxx";
    public void shuchu() throws CloneNotSupportedException{
        clone();
    }

}

解析:
子類引用可以直接調用父類的protected方法,而且子類中可以直接調用父類方法

Test1.java
class MyObject {}

public class Test {
    public static void main(String[] args) {
       MyObject obj = new MyObject();
       obj.clone(); // 這裏編譯報錯:The method clone() from the type Object is not visible
    }
}

我們知道clone()是Object類的protected方法.這說明,該方法可以被同包(java.lang)下和它(java.lang.Object)的子類訪問.這裏MyObject類是Object的子類(默認繼承java.lang.Object).
同樣Test1也是java.lang.Object的子類。但是,在Test類中,主調卻爲MyObject對象,因此編譯報錯

Test2.java
class MyObject2 {
    protected Object clone() throws CloneNotSupportedException {
       return super.clone();
    }
}

public class Test2 {
    public static void main(String[] args) throws CloneNotSupportedException {
       MyObject2 obj = new MyObject2();
       obj.clone(); // 編譯通過
    }
}

這裏,我們在MyObject2類中覆蓋父類的clone()方法,在另一個類Test2中調用clone()方法,編譯通過。
編譯通過的原因顯而易見,當你在MyObject2類中覆蓋clone()方法時,MyObject2類和Test2類在同一個包下,所以此protected方法對Test2類可見。

Test3.java
package 1
public class MyObject3 {
protected Object clone() throws CloneNotSupportedException {
       return super.clone();
    }
}

package 2
public class Test3 extends MyObject3 {
    public static void main(String args[]) {
       MyObject3 obj = new MyObject3();
       obj.clone(); // Compile error.
       Test3 tobj = new Test3();
       tobj.clone();// Complie OK.
    }
}

這裏我用Test3類繼承MyObject3,注意這兩個類是不同包的,否則就是示例2的情形。在Test3類中調用Test3類的實例tobj的clone()方法,編譯通過。而同樣調用MyObject3類的實例obj的clone()方法,編譯錯誤!
意想不到的結果,protected方法不是可以被繼承類訪問嗎?
必須明確,類Test3確實是繼承了類MyObject3(包括它的clone方法),所以在類Test3中可以調用自己的clone方法。但類MyObject3的protected方法對其不同包子類Test3來說,是不可見的。


二.面向對象的三大特性之封裝

  1. 封裝的定義:封裝從字面上來理解就是包裝的意思,專業點就是信息隱藏,是指利用抽象數據類型將數據和基於數據的操作封裝在一起,使其構成一個不可分割的獨立實體,數據被保護在抽象數據類型的內部,儘可能地隱藏內部的細節,只保留一些對外接口使之與外部發生聯繫。系統的其他對象只能通過包裹在數據外面的已經授權的操作來與這個封裝的對象進行交流和交互。也就是說用戶是無需知道對象內部的細節(當然也無從知道),但可以通過該對象對外的提供的接口來訪問該對象。
  2. 封裝的好處:
    (1)良好的封裝能夠減少耦合
    (2)類內部的結構可以自由修改
    (3)可以對成員進行更精確的控制
    (4)隱藏信息,實現細節
  3. 實現封裝的一般步驟:
    (1)修改屬性的可見性來限制對屬性的訪問。一般把屬性聲明爲private
    (2)爲每個屬性創建一對賦值方法和取值方法,用於對這些屬性的訪問。(get,set方法)
    (3)在賦值和取值方法中,加入對屬性的存取限制。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章