17 勝手に使われたくない...メソッドへのアクセス制限

【第17回】勝手に使われたくない...メソッドへのアクセス制限

前回はフィールドのアクセス制限について説明しました。
その続きとして、メソッドのアクセス制限について理解を深めていきましょう。

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

「メソッドへのアクセス制限」って何の事?
またまた「難しい」というイメージが先行してしまいそうですが、
「フィールドのアクセス制限」と同様に、「private」「protected」「public」の宣言によって、
そのアクセス(実行)を制限するものです。

第16回」で使用したプログラムを少し修正して、実際の動作を確認してみましょう。

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.アクセス制限

実行したプログラムでは、全て「public」なメソッドであるため、ClassSampleクラスから
AnotherClassSampleクラスのメソッドを呼び出す事ができます。 これはフィールドと同様に
宣言したクラスの外部からも呼び出す事が可能である事をあらわしています。

では、「privateメソッド」を呼び出す事はできるのでしょうか。

AnotherClassSampleを修正して試してみましょう。

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() ☆☆☆ ここを修正 ☆☆☆
    private void printName()
    {
        System.out.println("My name is " + name + ".");          // (F)
    }
}

コンパイルしてみると

C:\work>javac ClassSample.java AnotherClassSample.java
ClassSample.java:30: エラー: printName()はAnotherClassSampleでprivateアクセスさ
れます
        anotherClass.printName();                        // (10)
                    ^
ClassSample.java:32: エラー: printName()はAnotherClassSampleでprivateアクセスさ
れます
        anotherClass.printName();                        // (12)
                    ^
エラー2個

C:\work>

フィールドの時と結果は同じですね。それでは、自分で修正してみましょうか。
privateで宣言したprinNameメソッドをAnotherClassSampleクラス自身の中で呼び出してみましょう。
そうそう。呼び出すメソッド(printMyName)をpublicで宣言して、
ClassSampleクラスから呼び出す修正も忘れずに。

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()
    private void printName()
    {
        System.out.println("My name is " + name + ".");          // (F)
    }

    // 名称表示(呼び出し可)
    public void printMyName()                                    // ☆追加☆
    {
        printName();
    }
}
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();                     // ☆ 修正 ☆
        anotherClass.printMyName();                      // (10´)
        anotherClass.setName("bar");                     // (11)
        // anotherClass.printName();                     // ☆ 修正 ☆
        anotherClass.printMyName();                      // (12´)
    }
}

うまく動きましたか?

結果は始めと同じになりましたよね。
結局のところ、private, publicの意味はメソッドになっても変わらない事がわかりました。

でも、どうしてprivateなメソッドが必要なのでしょうか。それは
「クラスが責任を持っているフィールドを自由に変更させない」ためなのです。
つまり、privateで宣言したフィールドにアクセスできるメソッドを最小限にして
万全を期しているわけです。
例えば

「人間クラス」に「年齢更新メソッド」を用意した。「人間クラス」の中でのみ使うものとして用意したが、外部から「年齢更新メソッド」を勝手に呼ばれると...。

かえって難しくなりましたか?

~まとめ~
1.メソッドのアクセス制限もフィールドのアクセス制限とかわりはない
2.クラスが責任を持っているフィールドは、アクセスできるメソッドを最小限にして万全を期す

前回、今回の講座は実感がわかないかもしれませんが、
将来、きっとわかる日が来ますので、それまでは心に留めておく事にしましょう。

→ 次へ(第18回:プログラムを整理する(オーバーロード))