未来エンジニア養成所Blog

プログラミングを皆に楽しんでもらうための情報をお届けします。

【Java】アクセス制御

title

アクセス修飾子

「クラスの作成」で、オブジェクトのフィールドにアクセスした場合とメソッドにアクセスした場合、両方のパターンを見ました。

どちらも可能だったわけですが、オブジェクトの情報であるフィールドに他のオブジェクトから直接アクセスするのは作り方として良くない、とされています。

アクセス方法


なぜ、直接フィールドにアクセスするのが良くないのかといいますと、部品の中身(どのような名前の変数があり、データ型が何か、など)を知らないと使えないからです。


これでは部品化した意味がありません。

部品の中身を変更したら、部品を使用している側も変更しなければならなくなってしまいます。


ですから一般的にはフィールドにはクラス外からのアクセスをしません。

さらに、勝手にアクセスされては困るので、アクセスを認めないという指定ができます。

これを「アクセス指定」といい、アクセス指定を行うキーワードを「アクセス修飾子」といいます。


アクセス指定子 意味
public そのメンバをすべてに公開
private そのメンバを同じクラス内のみに公開
protected そのメンバを同じクラス内と、継承したクラス、
同一パッケージのクラスのみに公開
(何も書かない)
パッケージ指定
そのメンバを同じパッケージのみに公開


ここではpublicとprivateについて見ていきます。

publicとしたメンバはすべてのクラスからアクセスできますが、privateとしたメンバはクラス外からのアクセスができません。

アクセスしようとするとコンパイルエラーになってしまいます。

アクセス方法2


アクセス指定
アクセス指定はメンバごとに決めていきます。
publicなフィールドやprivateなメソッドを作ることもできますし、実際にそうすることもあります。ただし、

  • クラス内のフィールドはすべてprivateとする
  • クラス内のメソッドはすべてpublicとする

というのが基本的なやり方です。


【アクセス指定子を使ってフィールドを隠す】

public class Human{
    private String name;
    private int age;
    private double height;

    public void selfIntroduce( ){
        System.out.println("私の名前は" + name + "です");
        System.out.println("私の年齢は" + age + "です");
        System.out.println("私の身長は" + height + "です");
    }
}
public class UseHuman{
    public static void main(String args[ ]){
        Human taro = new Human( );

        taro.name = "太郎";
        taro.age = 30;
        taro.height = 175.5;
        /*
            System.out.println(taro.name);
            System.out.println(taro.age);
            System.out.println(taro.height);
        */
        taro.selfIntroduce( );
    }
}


上記のコードだと下記のようにコンパイルエラーが発生します。

コンパイルエラー


Humanクラスのname、age、heightの各フィールドにはアクセス修飾子privateが付いています。

アクセス修飾子privateは、宣言したクラス内でのみアクセスが可能です。

ここではHumanクラスとは別の、UseHumanクラスから「taro.name」とアクセスしようとしていますが、private指定されているため、UseHumanからは「不可視」(見えない状態)になっているので、アクセスができず、コンパイルエラーになります。


では、Humanクラスを編集して、privateフィールドにアクセスできるpublicメソッドを追加します。

public class Human{
    private String name;
    private int age;
    private double height;

    public void setName(String n){
        name = n;
    }

    public void setAge(int a){
        age = a;
    }

    public void setHeight(double h){
        height = h;
    }

    public void selfIntroduce( ){
        System.out.println("私の名前は" + name + "です");
        System.out.println("私の年齢は" + age + "です");
        System.out.println("私の身長は" + height + "です");
    }
}


UseHumanクラスの編集します。

public class UseHuman{
    public static void main(String args[ ]){
        Human taro = new Human( );

        //taro.name = "太郎";
        //taro.age = 30;
        //taro.height = 175.5;
        taro.setName("太郎");
        taro.setAge(30);
        taro.setHeight(175.5);

        taro.selfIntroduce( );
    }
}


実行結果

私の名前は太郎です
私の年齢は30です
私の身長は175.5です


privateなメンバはクラス外からアクセスできませんので、そのかわりsetNameというメソッドに渡した文字列をHumanクラス内で代入しています。

これだけを見ると何の意味があるのか分かりにくいかもしれません。

しかし、まさにここがオブジェクト指向の根幹を成す部分なのです。


責任とメッセージ

オブジェクト指向言語ではアプリケーションを「全部完成してはじめて成り立つ」のではなく、「それぞれが独立したオブジェクト(部品)」の集まりとして作っていきます。

それぞれの部品はそのアプリケーション専用ではなく、他のアプリケーションでも使うことができます。

例えばStringクラスなどを考えてみてください。

どこでもオブジェクトを宣言して使うことができていることが思い出されるでしょう。

そうすると問題は、どういう部品を作るべきかということになります。

個々の部品同士の関係や、アプリケーション全体と部品の関係はとても重要です。

これは「責任」「メッセージ」という概念で説明されます。


責任とは
まず、責任とは何でしょうか。

ある処理を行うのは、それに責任をもつオブジェクトのみです。

これを現実の世界にあてはめてみましょう。

アプリケーションの代わりに、ある企業があるとして考えてみましょう。

もちろん企業はいろいろな機能を持っています。

物を作ったり、売ったり、社員を管理したりなどがその例ですが、それぞれの機能を遂行するのはそれぞれ違う部署です。

  • 製品を作る 技術部の責任
  • 製品を売る 営業部の責任
  • 社員を管理する 人事部の責任

といったところがよく見られるでしょう。

それぞれの部は責任を持ちます。

責任を持つ仕事は遂行するべきであり、逆に責任のない仕事、他の部署の仕事にはあまり関与すべきではありません。

他の部署の内情は知らなくてもよいはずです。

逆に自分が責任を持つ部分を他の部署に漏らすのも問題があります。

このような理由によって情報を意図的に隠すことを情報隠蔽といいます。


情報隠蔽の考え方

  • モジュールの利用者には、そのモジュールを利用するために必要なすべての情報を与え、それ以外の情報はいっさい見せない

  • モジュールの作成者には、そのモジュールを実装するために必要なすべての情報を与え、それ以外の情報はいっさい見せない


Stringというモジュールは文字列をどうやって内部で処理しているかを隠蔽しています。

例えば、"Hello"という文字列は5つの文字を持っていますが、これをどのように保存しているかは知る必要がありません。

Stringクラスの中でchar型の配列を作っているかもしれないし、char型の変数を5つバラバラに作っているかもしれません。

それは利用者には関係ありません。

利用するために必要な情報ではないので、Stringの責任で処理してくれればいいことです。

このように、前の例では企業の中での部署、というのはアプリケーションの中でのクラスにあたります。


メッセージとは
クラスが情報を隠蔽している(つまり変数をprivateにしている)ので、外からはその情報を直接利用することができません。

勝手に人の部署に手を出してはいけないのと同じことです。

では、その情報が欲しいときにはどうしたら良いでしょうか。

その場合はオブジェクトに対して情報が欲しいことを伝えます。

「勝手に見る」のではなく、「見せてください」「利用させてください」と依頼するのです。

これを、「メッセージを送る」と言います。

企業の話に戻せば、各部署間で書類を回すことに似ています。

他部署に依頼したい内容や、こちらから与えたい情報を書類に書くのです。

書類を受け取った部署が、自分の部署で責任がある部分を遂行します。

その中でも自分に責任がない部分は、さらに他部署にメッセージを送ります。


メッセージはどのようにやり取りするのでしょうか?


Javaでは、これは単に「メソッド呼び出し」といいます。

他の部署に依頼したい内容はメソッドの名前であり、こちらから与えたい情報は引数です。

メッセージのやりとり


まとめ

  • アクセス指定子
    • クラスのメンバに対するアクセスは制御できます。
    • 基本的にはフィールドをprivate、メソッドをpublicにします。


  • 責任とメッセージ
    • アプリケーションを大きな1つのものとして作らず、責任によってオブジェクトに分割します。
    • オブジェクト同士はメッセージをやり取りすることによって互いの情報を利用します。


参考図書



独学で挫折しそうになったら、オンラインプログラミングスクール
未来エンジニア養成所Logo



あわせて学習したい

phoeducation.work phoeducation.work