パパの勉強部屋

勉強の記録をつけています。Java、ネットワーク、Excel、etc.

スッキリわかるJava入門 第10章 カプセル化①

第10章 カプセル化

カプセル化とは?

  • フィールドへの読み書きや、メソッドの呼び出しを制限する機能。
  • 情報へのアクセスや動作の実施について「誰に何を許すか」を定めて制限することを、アクセス制御(access control)と言う。
  • Javaにおけるカプセル化とは、大切な情報(フィールド)や操作(メソッド)についてアクセス制御をかけることにより、悪意や間違いによるメンバの利用を予防し、想定しない利用が発生したならば、その原因箇所を特定しやすくするための仕組み。

アクセス制御されない怖さ

不具合
  • Heroクラスを使ったゲームのテスト中の不具合
  • ①一度もモンスターと戦っていないのに勇者のHPがマイナス100になっている。
  • 別開発者の「宿屋クラス」の不具合で「h.hp = -100;」とコーディングされていた。(コンパイルエラーにならない)
  • ②冒険中にお城で会話をすると、なぜか勇者が理由もなく急死してゲームオーバーになる。
  • 別開発者の「王様クラス」の不具合で「bye()」ではなく「die()」メソッドが呼ばれていた。
必要なアクセス制御
  • ①Heroクラス以外からはhpフィールドに値を設定できない
  • ②die()メソッドを呼べるのはHeroクラスだけ

4つのアクセス制御レベル

  • Javaでは、それぞれのメンバ(フィールド及びメソッド)に対してアクセス制御の設定を行うことができる。
  • ですが、それぞれのメンバに「Aクラスからの利用は許す」のように細かく指定すると、とても手間がかかってしまう。
  • ざっくりと4段階からアクセス制御の方法を選ぶようになっている。
Javaにおけるアクセス制御の範囲と指定方法(メンバ編)
名前 プログラム中の指定方法 アクセスを許可する範囲
private private 自分自身のクラスのみ
package private (何も書かない) 自分と同じパッケージに属するクラス
protected protected 自分と同じパッケージに属するか、自分を継承した子クラス
public public すべてのクラス
  • privateやpublicなどはアクセス修飾子(access modifier)と呼ばれ、フィールドやメソッドを宣言する際、先頭に記述する事でアクセス制御が可能となる。

privateを利用する

必要なアクセス制御①の対応として、HPはprivateにする。

public class Hero {
	private int hp;	
	String name;
	Sword sword;
	static int money;	
	
	Hero(){			
		this("ダミー");	
	}

	Hero(String name){		
		this.hp = 100;	
		this.name = name;	
	}

	void sleep() {		
		this.hp = 100;
		System.out.println(this.name + "は、眠って回復した!");
	}
}
  • hpフィールドにprivateを指定したため、宿屋クラスのcheckIn()メソッドでは「hpフィールドにアクセスできない」コンパイルエラーが発生する。
  • 勇者のhpフィールドが、いっさい変更できなくなる訳ではない。
  • atack()やsleep()のように、同じheroクラスのメソッドからはhpフィールドにアクセスできる。
  • 宿屋クラスのcheckIn()メソッドからは、勇者のsleep()メソッドを呼ぶように修正すればよい。
  • privateであっても、this.~での読み書きは可能。
必要なアクセス制御②の対応として、die()はprivateにする。
  • die()メソッドも、王様などほかのクラスからみだりに呼び出される事がないようにprivateにする。
  • 外部のクラスからは呼び出せなくなるが、同じクラス内にあるattack()メソッドからの呼び出しは問題ない。

public class Hero {
	private int hp;	
	String name;
	Sword sword;
	static int money;	
	
	Hero(){			
		this("ダミー");	
	}

	Hero(String name){		
		this.hp = 100;	
		this.name = name;	
	}

	void bye(){
		System.out.println("勇者は別れを告げた");
	}

	private void die() {
		System.out.println(this.name + "は死んでしまった!");
		System.out.println("GAME OVERです。");
	}
}