メンバとアクセス修飾子


前回は「クラス宣言とアクセス修飾子」についてみました。今回はメンバのアクセス修飾子についてみていきます。

なぜアクセス修飾子が必要?

【サンプル】

public class Bank {
    int money;

    Bank(){
        this.money = 0;
    }
    //入金処理
    void inMoney(int in_money){
        if(in_money >= 0){
            this.money += in_money;
        }else{
            System.out.println("Error:in_money");
        }
    }
    //出金処理
    void outMoney(int out_money){
        if(if(out_money >= 0 && out_money <= this.money){
            this.money -= out_money;
        }else{
            System.out.println("Error:out_money");
        }
    }
    //残高
    int nowMoney(){
        return this.money;
    }
}

銀行口座クラスです。このクラスをインスタンスすることで口座開設ができ、inMoneyメソッドで入金処理、outMoneyメソッドで出金処理、そしてnowMoneyメソッドで残高が確認できます。

int money;

まずはフィールドにアクセス修飾子をつけません。この場合どのような問題点が起こるかみていきます。

public class Sample{
    public static void main(String[] args) {
    	Bank Bank_Obj = new Bank();
    	Bank_Obj.money += 1000;  //入金処理
    	Bank_Obj.money -= 2000;  //出金処理
    	System.out.println(Bank_Obj.money);  //残高
    }
}
-1000

フィールドにアクセス修飾子をつけないと同パッケージ内の全てのクラスから直接参照することができます。上記「Sampleクラス」では入金・出金・残高メソッドを利用しないで、4行目でオブジェクト変数moneyに直接加えて入金処理を行い、5行目では直接減らして出金処理を行い、そして6行目で直接に値をみて表示しています。
結果をみると残高が-1000とマイナスになっています。本来なら残高以上の出金はできないようにすべきですが、直接値を書き換えられると制御できません。
そこで直接フィールドには参照できないようにアクセス修飾子を付けアクセス制限をすることにします。

Bankクラスの2行目を次のように変更してみます。

private int money;

今度はSampleクラスを実行されるとエラーになります。

Exception in thread "main" java.lang.Error: Unresolved compilation problem
フィールド Bank.money は不可視です

private修飾子は同クラス内でしか参照できなくします。外部のSampleクラスからはアクセス権限がないのでエラーになります。
ではSampleクラスの内容を入金・出金・残高メソッドを使って同じ処理をしてみます。

public class Sample{
    public static void main(String[] args) {
        Bank Bank_Obj = new Bank();
        Bank_Obj.inMoney(1000);  //入金
        Bank_Obj.outMoney(2000); //出金
        System.out.println(Bank_Obj.nowMoney()); //残高
    }
}
Error:out_money
1000

出金メソッドでは残高以上の出金ができないように制御しているので出金エラーを表示しています。このようにフィールドの値の変更は、直接参照できなくしてメソッドを利用させることにより安定したシステムと予想しないバグの防止に繋がります。

メンバで使えるアクセス修飾子

アクセス修飾子には、「public 、protected 、private」 があります。
各アクセス制限の範囲はこの後みていきますので、まずはメンバで指定できるアクセス修飾子の種類をみます。
メンバとはフィールドとメソッドのことです。

public class AccessCheck {
              int field_1;
    public    int field_2;
    protected int field_3;
    private   int field_4;

              void method_1(){}
    public    void method_2(){}
    protected void method_3(){}
    private   void method_4(){}
}

全てのアクセス修飾子のフィールドとメソッドを含めたクラスを作ってみました。エラーも発生せず保存できます。メンバに関してはアクセス修飾子の指定に制限はないようです。前回みた「クラス宣言とアクセス修飾子」も含めてまとめてみます。

指定なし public protected private
クラス × ×
フィールド
メソッド

アクセス制限の範囲

java101

全てのアクセス修飾子のフィールドとメソッドを含めた「AccessCheck」クラスをデフォルトパッケージとmakeAパッケージに作りました。そしてデフォルトパッケージのSampleクラスから各クラスのフィールドとメソッドを参照してみます。Sampleクラスを実行した結果は次のようになりました。

Exception in thread "main" java.lang.Error: Unresolved compilation problem
フィールド AccessCheck.field_4 は不可視です
メソッド method_4() は型 AccessCheck で不可視です
フィールド AccessCheck.field_1 は不可視です
フィールド AccessCheck.field_3 は不可視です
フィールド AccessCheck.field_4 は不可視です
メソッド method_1() は型 AccessCheck で不可視です
メソッド method_3() は型 AccessCheck で不可視です
メソッド method_4() は型 AccessCheck で不可視です

結果を見るとエラーがいくつか出ています。エラー内容はすべて「不可視」なのでアクセス権限がないことを表しています。

結果をまとめると

同パッケージ内の他クラスへはprivateのフィールド、メソッドだけがアクセルができない。
別パッケージの他クラスへは、Publicのフィールド、メソッドだけがアクセスできる

となります。

指定なし public protected private
同パッケージ他クラス・フィールド ×
同パッケージ他クラス・メソッド ×
別パッケージ他クラス・フィールド × × ×
別パッケージ他クラス・メソッド × × ×

表をみると、アクセス修飾子を指定しない場合とprotectedを指定した場合とで差がありません。この2つの違いについてみていきます。

java102

パッケージmakeAに、アクセス修飾子を指定しないメンバとprotectedを指定したメンバを含むクラス「SuperClass」を作ります。そして、「SuperClass」を継承したクラス「SubClass」をデフォルトパッケージに作ります。では「SubClass」から「SuperClass」のメンバを参照するとどうなるかみてみます。

Exception in thread "main" java.lang.Error: Unresolved compilation problem
フィールド SuperClass.field_1 は不可視です
メソッド method_1() は型 SuperClass で不可視です

「SubClass」と「SuperClass」の関係は、「別パッケージ他クラス」であるのでフィールドもメソッドもアクセスできないことを期待します。しかし、結果からみてもわかるように、エラーになっているのはアクセス修飾子を指定しない場合だけであって、protected指定の場合はアクセスができています。そこがアクセス修飾子を指定しない場合とprotectedを指定した場合との違いで、protectedは

継承関係にあれば、「別パッケージ他クラス」間でもアクセスできる。

となります。

最後にprivateについてみていきます。

public class PrivateClass {
    private int field;
    private void method(){}

    void ascessCheck(){
        this.field = 1;
        this.method();
    }
}

privateは最も厳しいアクセス権限で自クラスからしかアクセスできません。自分自身のフィールやメソッドにthis(省略可)指定でアクセスします。自クラスからは全てのアクセス修飾子でアクセス可能です。

全てをまとめると次のようになります。

指定なし public protected private
自クラス
同パッケージ他クラス・フィールド ×
同パッケージ他クラス・メソッド ×
別パッケージ他クラス・フィールド
※継承関係なし
× × ×
別パッケージ他クラス・メソッド
※継承関係なし
× × ×
別パッケージ他クラス・フィールド
※継承関係あり
× ×
別パッケージ他クラス・メソッド
※継承関係あり
× ×


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です