16 勝手に変えられたくない...メンバへのアクセス制限

【第16回】勝手に変えられたくない...メンバへのアクセス制限

「クラス」について何度か触れてきましたが、
今回はその中でも重要な「メンバへのアクセス制限」について説明しましょう。

前提: 第9回第10回のイメージがつかめている。

「メンバ」とは、”フィールド(属性)”と”メソッド”を称して「メンバ」と呼びます。
今回は”フィールド(属性)”について説明していきます。

...なにやら始めから「クラス」「メンバ」「アクセス制限」「フィールド」...っと
難しそうな言葉が並んでいますが、他の人が書いたプログラムを読む上でも必要な知識なので、
ここは「ふ~ん。そういうものね」くらいの認識でも最後まで読み進めて行きましょう。

フィールドは、使用用途によってアクセス制限(使用制限)を行えます。
まずは、「第10回複数のクラスを扱う」で使用したプログラムを入力・実行してみましょう。

public class AnotherClassSample
{
    private String name;                                         // (A)

    // コンストラクタ
    public AnotherClassSample()                                  // (B)
    {
        System.out.println("AnotherClassSample Constructor!!");  // (C)
        name = "foo";                                            // (D)
    }

    // 名称設定
    public void setName(String newName)
    {
        name = newName;                                         // (E)
    }

    // 名称表示
    public void printName()
    {
        System.out.println("My name is " + name + ".");          // (F)
    }
}
public class ClassSample
{
    private String msg;                                  // (1)

    public ClassSample()
    {
        System.out.println("Constructor Was Called.");   // (2)
    }

    public void setMessage(String inMsg)
    {
        msg = inMsg;                                     // (3)
    }

    public void printMessage()
    {
        System.out.println("message:" + msg);            // (4)
    }

    public static void main(String[] args)
    {
        ClassSample classSample;                         // (5)

        classSample = new ClassSample();                 // (6)
        classSample.setMessage("Hello Java World!");     // (7)
        classSample.printMessage();                      // (8)

        AnotherClassSample anotherClass = new AnotherClassSample(); // (9)
        anotherClass.printName();                        // (10)
        anotherClass.setName("bar");                     // (11)
        anotherClass.printName();                        // (12)
    }
}

コンパイル・実行結果は以下の通りです。

C:\work>javac ClassSample.java AnotherClassSample.java

C:\work>java ClassSample
Constructor Was Called.
message:Hello Java World!
AnotherClassSample Constructor!!
My name is foo.
My name is bar.

C:\work>

1.private

ここで値の代入に着目してみましょう。

AnotherClassSampleクラスで値の代入を行っている(E)を見てみましょう。
「private String」で宣言されている「name」に対して代入を行っています。 これは、「name」がAnotherClassSampleクラスのprivateフィールド(またはprivate属性)である事を示します。

今までの講座では、メソッド内で宣言する「変数」を扱ってきましたね。

フィールドも変数の一種です。
何が違うのかと言うと、

・メソッド内で宣言される変数はメソッド内でのみ使用できる

・クラスのフィールドとして宣言した変数はクラス内、またはクラス外からの参照が可能。
(但し、アクセス制限による)

となります。

では、「private」は何をあらわすのでしょう。
これは「宣言されたクラス内でのみ参照が可能」である事をあらわします。

????...具体的に試してみる必要がありそうですね。

ClassSampleクラスは直接AnotherClassSampleクラスのフィールドにはアクセスせずに、
setNameメソッドを利用して値の代入を行っています。
ここで、AnotherClassSampleクラスのフィールドに直接代入を行うように書き換えてみましょう。

public static void main(String[] args)
{
    ClassSample classSample;                         // (5)

    classSample = new ClassSample();                 // (6)
    classSample.setMessage("Hello Java World!");     // (7)
    classSample.printMessage();                      // (8)

    AnotherClassSample anotherClass = new AnotherClassSample(); // (9)
    anotherClass.printName();                        // (10)
    anotherClass.setName("bar");                     // (11)

    anotherClass.name = "change";                    // (13)

    anotherClass.printName();                        // (12)
}

ClassSampleクラスのmainメソッドに(13)を追加して、コンパイルすると

C:\work>javac ClassSample.java
ClassSample.java:32: name は AnotherClassSample で private アクセスされます。
        anotherClass.name = "change";                    // (13)
                    ^
エラー 1 個

C:\work>

ご覧の通り、アクセスを制限されているために、エラーとなってしまいました。

2.public

では、AnotherClassSampleクラスのフィールド「name」を「public」で宣言してみましょう。

public class AnotherClassSample
{
    // private String name;                                      // (A)
    public String name;                                          // (A')

    // コンストラクタ
    public AnotherClassSample()                                  // (B)
    {
        System.out.println("AnotherClassSample Constructor!!");  // (C)
        name = "foo";                                            // (D)
    }

    // 名称設定
    public void setName(String newName)
    {
        name = newName;                                         // (E)
    }

    // 名称表示
    public void printName()
    {
        System.out.println("My name is " + name + ".");          // (F)
    }
}

コンパイルすると...。

C:\work>javac ClassSample.java AnotherClassSample.java

C:\work>

早速、実行してみましょう。

 
C:\work>java ClassSample
Constructor Was Called.
message:Hello Java World!
AnotherClassSample Constructor!!
My name is foo.
My name is change.

C:\work>

今度は成功しました。 もう、おわかりですね。
「public」と宣言れば、宣言したクラスの外部からも参照が可能となります。

では、どうしてこんなアクセス制限があるのでしょう。
「全部publicで良いじゃんっ!」と思う人も少なくないでしょう。

これは、「クラス内で宣言されているフィールドは、宣言したクラスが責任をもつ」ために
必要な事なのです。

例えば、以下のプログラムを見て下さい。

// 人間クラス
public class Man
{
    private String personalName;    // 登録されている名前

    // コンストラクタ(名前を指定)
    public Man(String name)
    {
        // 指定のnameを名前として登録する
        personalName = name;
    }

    // 名前取得メソッド
    public String getName()
    {
        return personalName;        // 登録されている名前を返す
    }
}

この「人間クラス」は生成に「名前」を設定します。
(「コンストラクタ」はクラス生成時に実行されるもの)
getNameメソッドがあるため、「名前」を確認する事はできます(名前を呼べば答えてもらえる)。
privateで宣言されたフィールドであるために他からの更新は行えませんし、
更新するメソッドもありません(そもそも、「名前」を勝手に変えられてたまるか!)。

そうです。他のクラスから変更させない為には「private」で宣言する必要があるのです。

どうですか?イメージできましたか?

ここでは、 “他のクラスで勝手に値を変えたくないから「private」”と覚えておきましょう。

「private」「public」の他にも、「protected」がありますが、これはもっと後で説明する事にしましょう。

~ まとめ ~

1.フィールドとして宣言した変数はクラス内で参照が可能となる
2.フィールドは宣言の方法によりアクセス制限が行える
3.クラス内で宣言されているフィールドは、宣言したクラスが責任をもつ

それでは、また次回にお会いしましょう。

→ 次へ(第17回:勝手に使われたくない...メソッドへのアクセス制限)