###■ カプセル化とは
「隠蔽し、不正な操作や変更を防ぐ、また修正が必要になった場合にも原因箇所を特定しやすくなる」
具体的には、アクセス修飾子を用いて、クラス外からのフィールドへの読み書きやメソッドの呼び出しを制限する
######■ アクセス修飾子とは
フィールドやメソッドを宣言する際に、先頭に記述する「public」などで、4つのアクセス制御レベルに分かれる
・private:クラス内でのみアクセスが可能、クラス外からのアクセスを制限
・指定なし (package privateと呼ばれることもある):同じパッケージ内のクラスのみアクセスが可能
・protected:同じパッケージのクラスとサブクラス(自分を継承した子クラス)からアクセス可能
・public:すべてのクラスからアクセス可能
クラスに指定できるアクセス修飾子は「public」か「指定なし」
public class hello {
class hello {
フィールドやメソッドにはすべてのアクセス修飾子が指定できる
private String name;
public int age;
public void introduce() {
void greet() {
基本的にフィールドはすべて「private」
メソッドは「public」にするのがセオリー
###■ 制限したフィールドの利用方法( getter / setter )
privateなどでアクセスを制限したフィールドは、メソッドを経由してアクセスし使用することが可能
使用するメソッドは「 getter / setter 」
######■ getter
getter は制限されたフィールド値を取り出すことができるメソッド
Characterクラス
public class Character {
public String name;
private int age;
public int getAge() {
return this.age;
}
void greet() {
System.out.println("hello");
}
}
mainメソッドのクラス
public class Tameshi {
public static void main(String[] args) {
Character c = new Character();
c.name = "Tanaka";
int age = c.getAge();
System.out.println(c.name + ":" + age + "歳");
System.out.println(c.name + ":" + c.getAge() + "歳");
}
}
Characterクラスのフィールドは name は public なのでmainメソッドのクラスでインスタンス化した後に名前を代入できるが、 age は private なため、name のようには代入できず、取り出すこともできない
name と同じように c.age = 25; とすると
「フィールドc.ageは不可視です」とコンパイルエラーが出る
上記のCharacterクラスのようにget + フィールド名のメソッドを作成し、return this.○○(フィールド)、つまりメソッドを呼び出すと、このクラスの○○フィールドを返しますよ、という記述をすることで、mainメソッドのクラスで getter メソッドで指定したフィールドの値が取得できる
上記の場合は値が設定されていないため、そのままだとデフォルトの 0 のみ取得される
######■ setter
setter は制限されたフィールドに値を設定することができるメソッド
getter が値を取得するだけのメソッドであるのに対し、setter は値を設定するだけのメソッドであり、両方あわせて使用する
また getter のみ記述すればクラス外から取得はできるが書き換えはできない(Read Only)のフィールドにすることもできる
Characterクラス
public class Character {
public String name;
private int age;
private int number;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
void greet() {
System.out.println("hello");
}
}
mainメソッドのクラス
public class Tameshi {
public static void main(String[] args) {
Character c = new Character();
c.name = "Tanaka";
c.setAge(25);
int age = c.getAge();
System.out.println(c.name + ":" + age + "歳");
System.out.println(c.name + ":" + c.getAge() + "歳");
}
}
setAge(int age) メソッドで引数を受けて呼び出し
this.age = age; this.age(フィールド)に値を代入する
setAgeメソッド経由で private なフィールドに値を代入し、設定するのみ
###■ setter によって修正箇所を少なくできる
また setter を使用することで、例えばフィールド名を変更しようとした際に、フィールドが public な状態と、 private な状態では
【 public 】
name ⇒ empName
public class Character {
public String name;
//name ⇒ empName
}
public static void main(String[] args) {
Character c = new Character();
c.name = "Tanaka";
//① c.name ⇒ c.empName
System.out.println(c.name);
//② c.name ⇒ c.empName
}
}
上記のようにクラス外での修正箇所が多く発生してしまうが、private の場合
【 private 】
name ⇒ empName
public class Character {
private name;
// name ⇒ empName
public void getName() {
return this.name;
//this.name ⇒ this.empName
}
public void setName(String name) {
this.name = name;
//this.name ⇒ this.empName
}
}
public static void main(String[] args) {
Character c = new Character();
c.setName = "Tanaka";
system.out.println(c.getName());
}
上記の場合は、mainメソッド内のsetNameメソッドで渡す先の仮引数 name は、フィールドを name から emoName に変更したこととは関係がないため、クラス外での修正をせず、変更するフィールドが定義されているクラス内のみの修正で済む
###■ フィールドに設定されている値が妥当かどうかを確認できる
「クラス外からフィールドの値を書き換えることを制限する」ということを利用して、setter で値が設定される際に、その値が妥当かどうかを確認するための条件式を設定し、不当な値が設定されないようにもできる
private String password;
public void setPassword (String password) {
if(password == null) {
throw new IllegalArgumentException
("パスワードが入力されていません。");
}
if(password.length() <= 3) {
throw new IllegalArgumentException
("パスワードが短すぎます。") ;
}
if(password.length() >8) {
throw new IllegalArgumentException
("パスワードが長すぎます。");
}
this.password = password;
System.out.println("パスワードを設定しました。");
}
public static void main(String[] args) {
Character c = new Character();
c.setPassword("aiueo");
c.setPassword("ai");
}
}
上記のコードでは、条件式で null、または3文字以下、8文字より多い場合にはエラー(throw ~ で強制終了するメソッド)を出すようにし、妥当な文字列の入力が行われた場合には this.password = password で設定している
mainクラスの1つ目の文字列、"aiueo" は妥当だが、2つ目の"ai" は3文字以下のため、エラーが発生する
###■ クラスに対するアクセス修飾子( public / 指定なし< package private>)
クラスに対する修飾子は、ほかの全てのクラスから使用できる「public」と、そのパッケージ内でのみ利用が許されている「package private:指定なし」があり、package privateにした場合は、他のパッケージに属するクラスからのアクセスが制限される、つまり、あるクラスのフィールドやメソッドが public 指定されていたとしても、パッケージが package private であればそのフィールド、メソッドにはアクセスできない
package private のクラスの特徴は
1.ファイル名と名前が同一でなくてよい
2.1つのファイル内に複数クラスを宣言できる
「クラス名とファイル名が同じでなければならない」、および「1つのソースファイル内に宣言できるクラスは1つだけ」というルールは puclic なクラスの場合であり、package private なクラスは複数宣言でき、そのファイル内にpublic なクラスがなくても構わない、その場合はファイル名は何でもよいということになる