クラスやインターフェイスなどのアクセス修飾子にはpublicがあり、無し(パッケージ)を含め、2種類に分類されます。
publicなクラスやインターフェイスなどの特徴は以下の通り。
パッケージなクラスやインターフェイスなどの特徴は以下の通り。
パッケージなクラスの例としてはライブラリ MySystemや MyCanvas内を参照すれば、publicではないクラスが存在することを確認できるかと思います。
メソッド・フィールド・コンストラクタのアクセス修飾子にはpublic, protected, privateがあり、無し(パッケージ)を含め 4種類に分類されます。それぞれのアクセス制限は以下のような感じになっています。
同一クラス | 同一パッケージのクラス | 継承した他パッケージのクラス | 他パッケージのクラス | |
---|---|---|---|---|
public | ○ | ○ | ○ | ○ |
protected | ○ | ○ | ○ | × |
無し(パッケージ) | ○ | ○ | × | × |
private | ○ | × | × | × |
これまでのプログラムの中で、適宜、使い分けをしてきたことである程度、推測がついたのかもしれませんが、ここでは幾つかの例をあげて見たいと思います。
privateなメソッドは継承されません。したがって、あるメソッドの内容が巨大になった場合に、しばしば privateなメソッドを使って分割することがあります。この場合、もし、それを継承したクラスが存在しても、privateなメソッドをオーバーライドすることはできません。偶然にして同じ名前の別メソッドとして扱われます。
カプセル化の定番の組み合わせとも言えます。フィールドに直接アクセスするのではなく、メソッドを噛ませることによって、値のチェックなどの処理をすることができます。例えば、必要に応じて例外を投げるなどの処理をすることができます。
例えば、以下の例では、インスタンスフィールド scoreに任意の値を設定することができてしまいます。
public class A { public int score; }
しかし、以下の例では、インスタンスフィールド scoreの値の範囲は 0~100の間に限定されます。
public class A { private int score; public void setScore(int score) { if(score < 0 || score > 100) { throw new IllegalArgumentException(); } else { this.score = score; } } }
値の範囲の制限が必要になるかどうかは、プログラムの製作開始直後にはなかなか気づかないことがあります。そのため、極力、カプセル化をしたほうが良いとされています。
例えば、Mathクラスでは、すべてのメソッドが staticなメソッドです。したがって、Mathクラスのインスタンスを生成する必要がありません。このような場合、privateなコンストラクタを宣言することで、他のパッケージからこのクラスを利用する場合、インスタンスを生成できないようにすることができます。具体的には以下のようにprivateなコンストラクタを宣言します。
public class A { private A() { ; // 何もしない } public static void method(int value) { ; // 処理1 ; // 処理2 } }
サブクラス側でメソッドをオーバーライドする場合、基本的にはアクセス修飾子は同じにします。ただし、緩めることはできます。スーパークラス側がパッケージの場合には、protectedや publicに変更できます。スーパークラス側が protectedの場合には、publicに変更できます。逆に、アクセス範囲を狭めるようなオーバーライドはビルドエラーになります。