Javaのアクセス修飾子には最もアクセス制限の緩いpublicから制限の厳しいprivateまで、以下の4種類があります。
修飾子 | UMLの可視性 | 説明 |
---|---|---|
public | + | すべてのクラスからアクセス可能 |
protected | # | 同じパックージ内のクラス、もしくはパッケージ外のサブクラスからアクセス可能 |
指定なし(デフォルト) | ~ | 同じパックージ内のクラスからのみアクセス可能 |
private | – | 同一クラス内からのみアクセス可能 |
クラス宣言に使えるアクセス修飾子は、publicと指定なしの2種類です。privateはインナークラスの宣言時に限って利用できます。
フィールドやメソッドは、4種類とも指定可能です。
それでは、parentパッケージにpublic指定したParentクラスを作り、そのクラスにpublic、protected、指定なしの3種類の指定をしたメソッドを作り、それらメソッドをパッケージ外に作るChildクラスから呼んでアクセス制限がどのようにかかるか見てみましょう。
まず、parentパッケージにスパークラス(親クラス)としてParent.javaを作り、オーバーロードしたメソッドを三つ作って、それぞれに異なるアクセス修飾子を指定します。
package parent; public class Parent { private String msg; public void setmsg(String msg) { this.msg = msg; } public void getmsg() { System.out.println(msg); } protected void getmsg(String msg) { System.out.println(msg); } void getmsg(String nashi, String msg) { System.out.println(msg); } }
次にparentパケージ外にParentのサブクラス(子クラス)として作るChild.java
import parent.Parent; public class Child extends Parent { public Child() { super.setmsg("子から親のpublicメソッドは呼べる"); super.getmsg(); super.getmsg("子から親のprotectedメソッドも呼べる"); super.getmsg("アクセス修飾子なし", "子から親のアクセス修飾子なしメソッドは呼べない"); } }
Childクラスをコンパイルすると、以下のようにChild.javaの8行目、親クラスの「アクセス修飾子なし」のメソッドを呼んでいる所で「メソッドにアクセス出来ない」というコンパイルエラーが出ます。
C:\work\java>javac Child.java Child.java:8: エラー: Parentのgetmsg(String,String)はpublicではありません。パッ ケージ外からはアクセスできません super.getmsg("アクセス修飾子なし", "子から親のアクセス修飾子なしメソッドは呼べない"); ^ エラー1個 C:\work\java>
つまり、アクセス修飾子なし指定の親クラスのメソッドはパケージ外の子クラスからはアクセスできません。
一方、Child.javaの8行目をコメントアウトして再度コンパイルすると、エラーは出ずクラスファイルが出来るので、Childクラスのインスタンスを作るメインクラスChild_Main.javaを作り、実行します。
するとpublic及びprotectedを指定したメソッドはパケージ外の子クラスからでもアクセスできることが分かります。
public class Child_Main { public static void main(String args[]) { Child cd = new Child(); } }
C:\work\java>java Child_Main 子から親のpublicメソッドは呼べる 子から親のprotectedメソッドも呼べる C:\work\java>
それでは、最後にアクセス修飾なし指定でアクセス可能な場合を調べてみましょう。
アクセス修飾なし指定されたメソッドは同じパッケージ内の別クラスからはアクセスできるはずなので、Parent.Javaと同じparentパケージ内にParent_Main.javaを作り、実行してみます。
package parent; public class Parent_Main { public static void main(String args[]) { Parent cd = new Parent(); cd.setmsg("同じパケージのpublicメソッドは呼べる"); cd.getmsg(); cd.getmsg("同じパケージのprotectedメソッドは親子関係がなくても呼べる"); cd.getmsg("アクセス修飾子なし", "同じパケージのアクセス修飾子なしメソッドは呼べる"); } }
C:\work\java>java parent.Parent_Main 同じパケージのpublicメソッドは呼べる 同じパケージのprotectedメソッドは親子関係がなくても呼べる 同じパケージのアクセス修飾子なしメソッドは呼べる C:\work\java>
このように、4つのアクセス修飾子のうち、区別が付きにくいのはprotectedと指定なしの違いです。
整理しておくと、protectedなフィールドやメソッドは、パッケージ外のサブクラスからでもアクセスできるのに対し、
アクセス修飾子を指定しなかった場合は、パッケージ外のサブクラスからはアクセスできず、同一パケージ内のクラスからのみアクセスできます。