LoginSignup
0
0

More than 1 year has passed since last update.

カプセル化とは

Posted at

■ カプセル化とは

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

■ アクセス修飾子とは

フィールドやメソッドを宣言する際に、先頭に記述する「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 なクラスがなくても構わない、その場合はファイル名は何でもよいということになる

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0