アクセス指定子

メンバへのアクセスの許可

6日目では、クラスおよびインスタンスの生成について説明しました。ここでは、さらにその内容を深めていこうとしていくことにします。クラスには、フィールドおよび、メソッドと呼ばれるものがあることはすでに説明しました。

このフィールドおよびメソッドには、アクセス許可を指定することにより、アクセスできる範囲を指定することができます。そのために必要なのが、アクセス指定子です。ここでは、アクセス指定子を利用して、メンバの可視性を指定する方法について説明します。

サンプルプログラム

以下のプログラムを実行してみてください。

SampleClass02.java
package day7;

public class SampleClass02 {

	//	コンストラクタ
	public SampleClass02(){
		System.out.println("コンストラクタ");
	}
	//	privateメソッド
	private void method1(){
		System.out.println("method1(private)");
	}
	//	publicメソッド①
	public void method2(){
		System.out.println("method2(public)");
	}
	//	publicメソッド②
	public void method3(){
		//	privateメソッドの呼び出し
		method1();
		System.out.println("method3(public) : num=" + this.num);
	}
	//	privateフィールド
	private int num = 1;

}
Sample701.java
package day7;

public class Sample701 {

	public static void main(String[] args) {
		SampleClass02 s = new SampleClass02();
		//	method1()は、privateなので、外部からはアクセスできない。
		//s.method1();
		//	method2呼び出し
		s.method2();
		//	method3呼び出し
		s.method3();
		//numは、privateフィールドなので、外部からはアクセスできない。
		//s.num = 1;
	}

}
実行結果
コンストラクタ
method2(public)
method1(private)
method3(public) : num=1

SampleClass02のメンバの先頭に、publicprivateなどといった文字が書かれています。これが、アクセス修飾子(しゅうしょくし)です。

アクセス修飾子の種類

すでに説明したとおり、アクセス修飾子は、フィールドおよびメソッドへのアクセスの制限を指定します。Javaのアクセス修飾子は、以下のようなものがあります。(表7-1)

表7-1.Javaのアクセス指定子
アクセス指定子 呼び名 意味
public パブリック どこからでも呼び出せる。
(default) デフォルト アクセス指定子が省略されている場合。同じパッケージ内からしか呼び出せない。
protected プロテクティッド 同じパッケージか、そのサブクラスからしか呼び出せない。
private プライベート 同じクラス内からしか呼び出せない。

この第6日目のサンプルでは、アクセス修飾子が省略されています。そのため、デフォルトであり、同一パッケージないからのアクセスが可能です。ここでは、publicおよび、privateが使われています。

サンプルの解説

以上を踏まえて、サンプルの解説をしてききます。SampleClass02において、method2()および、mehtod3()は、publicなので、外部のクラスである、Sample701.javaからアクセス可能なので、10行目および12行目でアクセスしています。

しかし、メソッドmethod1()および、フィールドnumには、privateがついているので、クラスの外からアクセスできません。8行目および14行目のコメントを外すと、以下のようなエラーメッセージが出ます。

privateのメンバに外部からアクセスした場合のエラー
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
    メソッド method1() は型 SampleClass02 で不可視です
    フィールド SampleClass02.num は不可視です

    at day7.Sample701.main(Sample701.java:8)

しかし、SampleClass02.javaの20行目および、21行目では、method1()および、numにアクセスしています。ここでエラーが出ないのは、同一クラス内だからです

クラスの可視性

また、クラスの先頭に、publicがついていますが、このように、クラス全体の可視性を指定することも可能です。ただ、クラスの場合、指定できる可視性は、publicおよび、デフォルトだけです。publicで指定したクラスは、他のパッケージからアクセスすることができ、デフォルトのクラスは、同一パッケージ内からしかアクセス出来ません。

コンストラクタ

クラス名と同一の名前のメソッド

ところで、SampleClass02.javaの6行目に、クラス名と同一のメソッドがあります。これを、コンストラクタと言います。コンストラクタは、戻り値の指定がありません。そして、特徴としては、インスタンス生成時に、一度だけ呼び出されるという特殊なメソッドです。

実は、インスタンス生成時に、newの後にクラス名を指定しているのは、実はこの、コンストラクタを呼び出していたのです。

コンストラクタの呼び出し
SampleClass02 s = new SampleClass02();

カプセル化

サンプルプログラム

Java言語でのプログラムの慣例として、通常フィールドは、privateで隠蔽し、外部からアクセスするメソッドを介して値の変更・取得を行います。これを、カプセル化と言います。以下にサンプルを示しますので、まずは実行してみてください。

SampleClass03.java
package day7;

public class SampleClass03 {
	//	int型のフィールド(privateで隠ぺいされている)
	private int number = 0;
	//	String型のフィールド(privateで隠されている)
	private String str = "";
	//	コンストラクタ(引数つき)
	public SampleClass03(String str){
		this.str = str;
	}
	//	number変数のセッター
	public void setNumber(int number){
		this.number = number;
	}
	//	number変数のゲッター
	public int getNumber(){
		return this.number;
	}
	//	str変数のゲッター
	public String getStr(){
		return this.str;
	}

}
Sample702.java
package day7;

public class Sample702 {

	public static void main(String[] args) {
		//	引数つきコンストラクタの呼び出し
		SampleClass03 s = new SampleClass03("HelloWorld.");
		//	SampleClass03 s = new SampleClass03();
		//	numberのセッターで、値を設定
		s.setNumber(100);
		//	ゲッターで値を呼び出し、内容を表示
		System.out.println(s.getNumber());
		System.out.println(s.getStr());
	}

}
実行結果
100
HelloWorld.

セッターとゲッター

SampleClass03.javaを見てもわかる通り、フィールドnumberおよびstrは、privateで隠ぺいされており、外部からアクセスすることはできません。privateで隠ぺいされたフィールドに値を書き込むメソッドを、セッター、値を取得するメソッドのことを、ゲッターと呼びます。(表7-2、図7-1参照)

表7-2.参照
フィールド名 セッター ゲッター
number void setNumber(int number) int getNumber()
str - String getStr()
図7-1.セッターとゲッター
セッターとゲッター

セッターは、setの後に、変数名がきます。この場合、最初の文字が大文字になる(number→Numberのように)になるのが通例です。ゲッターについても同様です。セッターの引数は、また、決まりではありませんが、セッターの引数に指定する変数は、フィールドと同じ名前を付けるケースが多いようです。

また、表からわかるとおり、一つのフィールドに対し、必ずしもセッターとゲッターが両方つくとは限りません。必要に応じ、セッターのみ、あるいはゲッターのみの場合もあります。

引数つきのコンストラクタ

SampleClass03.javaの9行目から11行目に、SampleClass03クラスのコンストラクタが定義されています。このコンストラクタには、引数が付いています。このように、コンストラクタは、他のメソッド同様、引数をつけることが可能です。このように、コンストラクタは、引数がついたものを指定することも可能です。このようなコンストラクタを使用する場合には、newをするときにも、引数を与える必要があります。

引数付きコンストラクタと、newの指定の方法
public SampleClass03(String str) ← 引数付きコンストラクタ
            
SampleClass03 s = new SampleClass03("HelloWorld."); ← 呼び出し方

クラスに、引数つきのコンストラクタが定義されている場合、引数なしのコンストラクタを呼び出すことはできません。ためしに、Sample702.javaの8行目のコメントを削除してください。次のようなエラーが出ます。

Exception in thread "main" java.lang.Error: Unresolved compilation problems:
    重複ローカル変数 s
    コンストラクター SampleClass03() は未定義です

    at day7.Sample702.main(Sample702.java:8)

これは、引数なしのコンストラクタが定義されていないという意味です。

デフォルトコンストラクタ

ところで、第6日目で紹介した、Sample01.javaには、コンストラクタがありませんでした。クラスにコンストラクタが存在しないのに、どうしてコンストラクタが呼び出せるのでしょうか?

SampleClass01.java(再掲)
package day6;

public class SampleClass01 {
	//	フィールド
	int n = 10;
	String s = "field";
	//	メソッド
	int add(int a,int b){
		return a + b;
	}
	String add(String s){
		return this.s + s;
	}
	void showNum(){
		System.out.println("n = " + n);
	}
}

実は、このような場合、Javaでは、デフォルトコンストラクタと呼ばれる、見えないコンストラクタがあると考えます。このコンストラクタないでは、何も処理はされませんが、newで呼び出すのは、このコンストラクタであるというのが、Javaの考え方です。

図7-2.デフォルトコンストラクタ
Javaのデフォルトコンストラクタ

練習問題 : 問題5.