訪問修飾符你用對了嗎

北漂程式設計師發表於2022-05-21

  不知道大家在平時的開發過程中有沒有注意到訪問修飾符,哈哈哈,有沒有懵,在java中有哪些訪問修飾符,還記得清嗎?今天想分享下訪問修飾符的哪些小事。

一、訪問修飾符有哪些

  在java中提到訪問修飾符,大家可能都不陌生,但對於訪問修飾符我還是想再重申下,這些看似很普通的概念,在多年後的某個瞬間總能激起我們某些想法。

  java中說白了就三種元素:類、方法、屬性,由這三種元素組合成了我們平時使用的API,來標識這三種元素的訪問許可權的字元就是訪問修飾符,通俗點理解就是我有一個方法我只想自己自己知道,我不想別人知道那麼我給它一個標識private,代表是私有的,那麼別人就無法訪問了,如果我想讓方圓5公里的人知道,我給它個標識protected,那麼就只有方圓5公里的人知道。訪問修飾符就是來控制類、方法、屬性的訪問範圍的

  在java中有四種訪問修飾符,分別是public、protected、default、private。上面說到java中有類、方法、屬性,下面看下這幾種訪問修飾符怎麼起作用的。

  先上一張圖,讓大家有個大體的印象,

1.1、public  

  public,公開的,公共的。可以修飾類、方法、屬性。在修飾類的時候,一個.java檔案中只能有一個類是公共的,且和.java檔案同名;重點看下最後這句話,

  看到了吧,在idea中給的提示很明確,Teacher是公共的(public),應該宣告到一個檔名為Teacher.java的檔案中。其實也很容易理解,在一個.java檔案中有多個公共的class,是無法區分哪個是主類的,所以在一個.java檔案中只能有一個公共的類。遺留一個小問題,在一個public的類中可以有其他修飾符修飾的類嗎?後面揭曉。

  public修飾方法和屬性,想必不用我多說了,在平時使用的比較多,public修飾方法和屬性不受包的限制,在任何包中均可訪問

1.2、protected

  protected,受保護的。可以修飾內部類、方法、屬性。這裡有個概念是內部類,當然和內部類相對應的就是外部類,所謂內部類就是在一個外部類中的類,外部類就是平時我們寫的類,其類名和檔名一樣。一個例子如下,

package com.example.day04;
/**
Teacher是外部類
 */
public class Teacher {
    /**
     * Inner是內部類
     */
    protected class Inner{
        
    }
}

重點來看下protected修飾的方法和屬性,

package com.example.day04;
/**
Teacher是外部類
 */
public class Teacher {
    protected String name;
    protected void method(){
        System.out.println(this.name);
    }
}

那麼name和method()方法可以被哪些類訪問吶?看下本包中的類,

package com.example.day04;

public class TeacherA {
    public static void main(String[] args) {
        Teacher teacher=new Teacher();
        teacher.name="tom";
        teacher.method();
    }
}

protected修飾的方法、屬性可以被本包中的類訪問,再來看下本包中的子類,

package com.example.day04;

public class TeacherB extends Teacher{
    public static void main(String[] args) {
        TeacherB teacherB=new TeacherB();
        teacherB.name="tom";
        teacherB.method();
    }
}

列印結果如下,

tom

Process finished with exit code 0

protected修飾的方法、屬性可以被本包中的子類訪問,再來看下不同包中的類,

protected修飾的方法、屬性不可以被不同包中的類訪問,那麼不同包的子類吶?

package cn.example.day04;

import com.example.day04.Teacher;

public class TeacherD extends Teacher {
    public static void main(String[] args) {
        TeacherD teacherD=new TeacherD();
        teacherD.name="tome";
        teacherD.method();
    }
}

結果如下,

tome

Process finished with exit code 0

protected修飾的方法、屬性可以被不同包中的子類訪問。

總結:protected修飾的屬性和方法可以被同包中的類、子類訪問;可以被不同包的子類訪問,不可以被不同包的類訪問。

1.3、default

這裡說default其實不是那麼嚴格,在java中不寫訪問修飾符,就是default,稱為default只為了好記,其實沒有“default”這個訪問修飾符

default,預設的訪問修飾符。可以用來修飾類、屬性、方法。

有default修飾的類、屬性、方法,

package com.example.day04;

class Address {
    String name;
    void method(){
        System.out.println(name);
    }
}

在本包下的類,

package com.example.day04;

public class AddressA {
    public static void main(String[] args) {
        Address address=new Address();
        address.name="china";
        address.method();
    }
}

結果如下,

china

Process finished with exit code 0

預設情況下的訪問修飾符,在本包下的類是可以訪問的。看下在本包下的子類,

package com.example.day04;

public class AddressB extends Address{
    public static void main(String[] args) {
        Address address=new Address();
        address.name="china";
        address.method();
    }
}

看程式碼正常編譯未出錯,肯定是可以的。

預設情況下的訪問修飾符,在本包下的子類是可以訪問的。不同包下的類和子類,這裡不再一一列出例子了,直接給出下面的結論,

預設情況下的訪問修飾符,在不同包下的類、子類都是不可以訪問的預設修飾符修飾的類、屬性、方法。

總結,預設情況下的訪問修飾符,在本包下的類、子類是可以訪問的;在不同包下的類、子類都是不可以訪問

1.4、private

private,私有的。可以修飾類、屬性、方法。

在private修飾類時,不可以修飾外部類,可以修飾內部類。重點看下修飾的屬性、方法,這個是我們在平時開發中用的最多的。

這裡有一個使用private修飾的屬性、方法,

package com.example.day04;

public class Person {

    private String name;
    private void method(){
        System.out.println(name);
    }
    private class A{
        
    }
}

看下圖,在本包中,

private修飾的屬性、方法在本包中的類中是無法訪問的。看下在本包的子類吶?

private修飾的屬性、方法在本包的子類中是無法訪問的。

總結,private修飾的屬性、方法在本包中的類、子類是無法訪問的,在不同包的類、子類是無法訪問的。

二、一些小趣事

上面說了很多乏味的基礎知識,在日常的開發中你可能都意識不到天天在用。下面看一下幾個有意思的小問題。

2.1、一個public修飾的類中可以有其他類嗎

我們知道一個public修飾的類的類名和.java檔名是一樣的,那麼在這個類中還可以有其他類嗎?

從上圖中可以看到,一個public修飾的類中僅可以有預設修飾符修飾的類,protected、private修飾的均不可以,public修飾的也不可以哦。

2.2、protected方法存在的意義

  protected修飾的方法可以在本包類、子類、不同包的子類訪問。這種方法存在的意義是什麼吶?在繼承中,子類可以訪問父類的protected方法,既然是繼承了,那麼沒繼承的類便不可訪問,protected很好的詮釋了繼承的意義。平時開發中使用protected方法是在抽象類中的抽象方法。

package com.example.day04;

/**
 * 抽象的Car工廠
 */
public abstract class AbstractCarFactory {
    protected abstract void generateCar();
}

那麼子類需要去覆蓋該抽象方法,非子類不需要覆蓋該方法,所以這個方法是protected訪問修飾符修飾的。有人會說是public修飾的可以嗎?當然可以,但是許可權肯定是越小越好啊,

package com.example.day04;

public class BiyadiCarFactroy extends AbstractCarFactory{
    @Override
    public void generateCar() {
        System.out.println("generate biyadi car");
    }
}

在子類中還可以改變覆蓋方法的訪問修飾符。

2.3、有了private為什麼還要public

在開發中寫的最多的可能就是類似下面的實體類,

package com.example.day04;

public class Address {
    private String name;
    private String code;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
}

  Address類中屬性是private,而getXXX和setXXX方法是public,這是為了保護屬性,方式使用例項.屬性的方式進行設定/獲取值,而是通過其提供的setXXX/getXXX方法來設定/獲取值。通過方法的方式,可以在設定值的過程中對值進行校驗、判斷等操作,而直接通過例項.屬性的方式則無法完成上面的操作,只不過在日常的開發中,都是直接賦值,沒有進行校驗、判斷等其他操作而已。例下方,

  public void setName(String name) {
        System.out.println("設定name的值為:"+name);
        if(name.equals("china")){
            this.name = name;
        }
        System.out.println("設定完成");
    }

2.4、子類無法訪問父類的私有屬性嗎

上面我們知道在子類中是無法訪問父類的私有屬性的,因為屬性是私有的即使子類也是無法訪問的。但我依然可以訪問到,

我們直接無法訪問到name屬性,但是我們可以通過其暴露的getXXX方法啊。

三、總結

  本文分享了在平時開發中很容易忽略的一個點,就是訪問修飾符,我們平時用的最多的要屬public、private,但是為什麼要使用,這樣使用的好處是什麼。有人說一個專案中都是自己專案內的人,沒必要考慮訪問修飾符,我直接都用public不是更好,這樣也沒錯,但是這樣帶來的後果是沒有任何的訪問限制,類比生活中人人都是想怎麼幹就怎麼幹,想去什麼地方就去什麼地方,這樣豈不是沒了規則,這個社會是不是無法正常運轉了。到了程式中雖然沒有那麼嚴重,但是遵循一定的原則,對程式碼的整體設計後續的擴充套件性也是好的。本文只是想做個引子,提醒小夥伴們日常的開發中多思考,多嘗試。

相關文章