カプセル化とは

***
###■　カプセル化とは
「隠蔽し、不正な操作や変更を防ぐ、また修正が必要になった場合にも原因箇所を特定しやすくなる」
具体的には、アクセス修飾子を用いて、クラス外からのフィールドへの読み書きやメソッドの呼び出しを制限する


######■　アクセス修飾子とは
フィールドやメソッドを宣言する際に、先頭に記述する「public」などで、4つのアクセス制御レベルに分かれる

・private：クラス内でのみアクセスが可能、クラス外からのアクセスを制限
・指定なし (package privateと呼ばれることもある)：同じパッケージ内のクラスのみアクセスが可能
・protected：同じパッケージのクラスとサブクラス（自分を継承した子クラス）からアクセス可能
・public：すべてのクラスからアクセス可能

クラスに指定できるアクセス修飾子は「public」か「指定なし」

```Java
public class hello {

class hello {
```

フィールドやメソッドにはすべてのアクセス修飾子が指定できる

```Java
private String name;
public int age;

public void introduce() {
void greet() {
```

基本的にフィールドはすべて「private」
メソッドは「public」にするのがセオリー

***
###■　制限したフィールドの利用方法（ getter / setter ）
privateなどでアクセスを制限したフィールドは、メソッドを経由してアクセスし使用することが可能
使用するメソッドは「 getter / setter 」

######■　getter
getter は制限されたフィールド値を取り出すことができるメソッド

Characterクラス

```Java
public class Character {
    public String name;
    private int age;

    public int getAge() {
        return this.age;
    }

    void greet() {
        System.out.println("hello");
    }
}
```

mainメソッドのクラス

```Java
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クラス

```Java
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メソッドのクラス

```Java
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

```Java
public class Character {
    public String name;
    //name ⇒ empName
}
```

```Java
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

```Java
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
    }
}
```

```Java
public static void main(String[] args) {
    Character c = new Character();
    c.setName = "Tanaka";
    system.out.println(c.getName());
}
```

上記の場合は、mainメソッド内のsetNameメソッドで渡す先の仮引数 name は、フィールドを name から emoName に変更したこととは関係がないため、クラス外での修正をせず、変更するフィールドが定義されているクラス内のみの修正で済む

***
###■　フィールドに設定されている値が妥当かどうかを確認できる
「クラス外からフィールドの値を書き換えることを制限する」ということを利用して、setter で値が設定される際に、その値が妥当かどうかを確認するための条件式を設定し、不当な値が設定されないようにもできる

```Java
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("パスワードを設定しました。");
}   
```

```Java
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 なクラスがなくても構わない、その場合はファイル名は何でもよいということになる