Previous | Next | Trail Map | Writing Java Programs | オブジェクト、クラス、インタフェース


クラスのメンバへのアクセス制御

「保留:我々はデフォルトのアクセスを「味方」と呼んでいる、しかし私はそれが実際に他に何かの呼び出し方を耳にする」。

クラスの利点の1つは、クラスが他のオブジェクトによるアクセスからメンバ変数とメソッドを守ることができるということである。 なぜこれは重要であるか? まあ、これを考慮してみる。 クラスを書いていて、例えばそれが会社の社員の記録や収入計算書のようなもので、それがあらゆる種類の秘密情報を含むデータベース上への問合せを意味する。

公的にアクセス可能なメソッドと変数がサポートするクラスに含まれる特定の情報と問い合わせは、そのシステムの他のオブジェクトに使われてもいいが、単に個人用のクラスに含まれる問い合わせは、そのクラスの操作だけをサポートする。これは保護すべき情報があるからである。言語レベルで個人用変数とメソッドを保護し、他のオブジェクトからのアクセスを拒否できることが望ましい。

Java では、クラスの変数とそのメソッドを宣言する時に、それら両方を保護するためにアクセス指示子を使用することができる。 Java 言語は、メンバ変数とメソッドのために 4 つのアクセスレベルをサポートする。それらは private、 protected、 public、そして指定されなければ「friendly」である。


注釈: Java 言語の1.0のリリースでは、5つのアクセスレベルをサポートした。上記の 4 つに加えて private protectedである。 private protected アクセスレベルは1.0以降のバージョンではサポートされない。もう Java プログラムでそれを使用するべきではない。


次のチャートは各指示子が許可するアクセスレベルを示す。

指示子クラスサブクラスパッケージ
-----------------------------------------------------
private         X
protected       X       X*         X
public          X       X          X         X
friendly        X                  X

1列目は、クラス自身がアクセス指示子が定義したメンバにアクセス権を持っていいるかどうかを示す。 見てわかるように、クラスは常にそれ自身のメンバにアクセスできる。 2 列目はクラスのサブクラスが(どのパッケージにあるかにかかわらず)、メンバにアクセスできるかどうかを示す。 3列目はクラスと同じパッケージのクラスが(それらの家柄にかかわらず)、メンバにアクセスできるかどうかを示す。 4列目は、すべてのクラスがメンバにアクセスできるかどうかを示す。

protected /サブクラスの所に”*”があることに注意しよう。この特定のアクセスの場合は特別な警告を持っているので、後で詳細に説明する。

各アクセスレベルの詳細を説明する。

Private

もっとも厳しいアクセス制限レベルは private である。 private のメンバは、それが定義されるクラスにのみアクセス可能である。 そのクラスだけが使えるメンバを宣言するために、このアクセスレベルを使用する。 これには、外部からアクセスされた場合にオブジェクトを矛盾状態にするための情報を含む変数、あるいは外部により起動された場合にオブジェクトまたは実行中であるプログラムを危険状態にするメソッドなどがある。 private のメンバは、決して誰にも話さない秘密のようなものである。

private のメンバを宣言するには、その宣言で private キーワードを使用する。 次のクラスは、1つの private メンバ変数と1つの private メソッドを含んでいる。

class Alpha {
    private int iamprivate;
    private void privateMethod() {
        System.out.println("privateMethod");
    }
}

Alpha 型のオブジェクトは、 iamprivate 変数を検査したり変更することができ、 privateMethod() を起動することができる。しかし他の型のオブジェクトではできない。 例えば、 Beta クラスを定義する。

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprivate = 10;      // illegal
        a.privateMethod();      // illegal
    }
}

Beta は Alpha 型ではないので、iamprivate 変数にアクセスしたり、 Alpha 型のオブジェクト上に privateMethod() を起動することができない。

クラスがアクセス権を持っていないメンバ変数にアクセスしようと試みていることを知るができる。コンパイラは次に類似したエラーメッセージをプリントして、プログラムをコンパイルすることを拒否する。

Beta.java:9: Variable iamprivate in class Alpha not accessible from class Beta.
        a.iamprivate = 10;     // illegal
         ^
1 error

同様に、プログラムがそれがアクセス権を持っていないメソッドにアクセスしようと試みると、次のようなコンパイラエラーが表示される。

Beta.java:12: No method matching privateMethod() found in class Alpha.
        a.privateMethod();         // illegal
1 error

初心者の Java プログラマが、Alpha オブジェクトが別の Alpha オブジェクトの private メンバをアクセスできるかどうか聞くかも知れない。 これは以下で例証する。 Alpha クラスが、現在の Alpha オブジェクト(this)と別の iamprivate 変数に基づいたオブジェクトとを比較したインスタンスメソッドを含んでいると仮定する。

class Alpha {
    private int iamprivate;
    boolean isEqualTo(Alpha anotherAlpha) {
        if (this.iamprivate
 == anotherAlpha.iamprivate)
                              return true;
                          else
                              return false;
                      }
                  }

これは完全に正当である。 同じ型のオブジェクト同士が互いに一方の private のメンバにアクセスできる。 これは、アクセス制限がオブジェクトレベル(このクラスの特定のインスタンス)よりむしろクラスあるいは型のレベル(すべてのクラスのインスタンス)において適用されるからである。

注意: this は現在のオブジェクトを参照する Java 言語キーワードである。 this の使用方法の詳細については、、 メソッド本体を参照のこと。

Protected

次のアクセスレベル指示子は protected である。protected により、クラス自身、サブクラス(前述した警告つき)、および同パッケージのすべてのクラスがメンバにアクセスすることができる。 無関係なクラスではなく、メンバにアクセスするのがクラスのサブクラスにとって適切な時は、 protected アクセスレベルを使用する。 protected メンバは家族の秘密のようである。つまり家族全体が知っていても気にしないが、家族以外の誰にも知られたくないということである。

protected メンバを宣言するためには、キーワード protected を使用する。 最初に、protected 指示子が同じパッケージのクラスへのアクセスにどのように影響を与えるかを考える。

パッケージ名 Greek 内に宣言されていて、その中で宣言されたprotected メンバ変数と protected メソッドを持つ Alpha クラスの次のバージョンを考慮する。

package Greek;

class Alpha {
    protected int iamprotected;
    protected void protectedMethod() {
        System.out.println("protectedMethod");
    }
}

ここで、クラス Gamma が同じく Greek パッケージのメンバであると宣言されている(そして Alpha のサブクラスではない)と仮定する。 Gamma クラスは、合法的に Alpha オブジェクトの iamprotected メンバ変数にアクセスすることができ、合法的にその protectedMethod ()を起動することができる。

package Greek;

class Gamma {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprotected = 10;    // legal
        a.protectedMethod();    // legal
    }
}

それはかなり簡単である。 では、protected 指示子が Alpha のサブクラスのアクセスにどのような影響を与えるか調査する。

新規のクラス、 Delta を導入する。Delta は Alpha から生じたが、異なるパッケージ − Latin − にいる。 Delta クラスは iamprotected protectedMethod ()の両方をアクセスすることができるが、Delta 型あるいはそのサブクラスのオブジェクト上に限定される。 Delta クラスは Alpha 型のオブジェクト上で iamprotected あるいは protectedMethod() をアクセスすることができない。次のコード例にあるaccessMethod() がAlpha 型のオブジェクトの iamprotected メンバ変数にアクセスしようとするのは、不正である。Delta 型のオブジェクトの iamprotected メンバ変数にアクセスするのは正当である。 同様に、 accessMethod() が Alpha オブジェクトの protectedMethod() を呼び出すのは不正である。

import Greek.
*;

package Latin;

class Delta extends Alpha {
    void accessMethod(Alpha a, Delta d) {
        a.iamprotected = 10;    // illegal
        d.iamprotected = 10;    // legal
        a.protectedMethod();    // illegal
        d.protectedMethod();    // legal
    }
}

もしクラスがサブクラスであり、 かつ protected メンバを持っているクラスと同じパッケージにいるのであれば、クラスは protected メンバにアクセスできる。

Public

最も容易なアクセス指示子は public である。 任意のクラスやパッケージにでも、クラスの public メンバにアクセスできる。 外部が public メンバを使用して、このようなアクセスが望ましい結果を作り出すことができる場合に限り、 public メンバを宣言する。 ここに個人的あるいは家族の秘密がない。これは他人が知っているのを気にしない要素のためである。

public メンバを宣言するためには、キーワード public を使用する。 例えば、

package Greek;

class Alpha {
    public int iampublic;
    public void publicMethod() {
        System.out.println("publicMethod");
    }
}

もう一度 Beta クラスを書き換えて、 Alpha と異なるパッケージにそれを置き、それが完全に Alpha と無関係である(サブクラスではない)ことを確認する。

import Greek.*;

package Roman;

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampublic = 10;       // legal
        a.publicMethod();       // legal
    }
}

上記のコードから見て分かるように、 Beta が合法的に Alpha クラスの iampublic 変数を検閲したり、変更したり、また合法的に publicMethod() を呼び出したりすることができる。

Friendly

最後のアクセスレベルは、明示的にメンバのアクセスを他のレベルに設定しない場合に得るものである。 このアクセスレベルにより、クラスと同じパッケージにあるクラスは、メンバにアクセスすることができる。 アクセスのこのレベルでは、同じパッケージのクラスは信頼できる友人であると想定する。 この信頼のレベルは、もっとも近い友人たちに及ぶが、家族さえも信用していないようなものである。

例えば、 Alpha クラスのこのバージョンが「友好的な(friendly)」メンバ変数と「友好的な」メソッドを宣言する。 Alpha は Greek パッケージにある。

package Greek;

class Alpha {
    int iamfriendly;
    void friendlyMethod() {
        System.out.println("friendlyMethod");
    }
}

Alpha クラスは iamfriendly friendlyMethod() の両方にアクセスできる。 さらに、Alpha と同じパッケージ内に宣言するすべてのクラスも iamfriendly friendlyMethod() にアクセスできる。 両方の Alpha と Beta が Greek パッケージの一部として宣言されたと仮定する。

package Greek;

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamfriendly = 10;     // legal
        a.friendlyMethod();     // legal
    }
}

その時 Beta は示すように、合法的に iamfriendly friendlyMethod() にアクセスすることができる。


Previous | Next | Trail Map | Writing Java Programs | オブジェクト、クラス、インタフェース