Java超|privateでメンバを守る

大事なフィールドは、むやみに外から触らせない。private を使えば、サイヤ人戦士の内部情報を守り、クラスを安全で信頼できる部品に育てられます。

前の記事では、クラスのメンバを外から自由に触れる状態にしておくと、不自然な値が入る危険があることを確認しました。

クラスには、フィールドとメソッドがあります。
この2つをまとめてメンバと呼びます。

フィールドには、オブジェクトの大事な情報が入ります。

ドラゴンボールの世界観でたとえると、悟空オブジェクトの名前、戦闘力、流派の印、流派名、気の量のようなものです。

もし、こうした情報をクラスの外から誰でも自由に書き換えられるとしたら、かなり危険です。

戦闘力がマイナスになる。
気の量が不自然な値になる。
流派名が空になる。
悟空の名前が勝手に変えられる。
どこで値が壊れたのか分からなくなる。

このような問題が起きる可能性があります。

そこで使うのが private です。

private をつけたメンバは、クラスの外から直接アクセスできなくなります。
つまり、外から勝手に触られないように守れるのです。

ドラゴンボールでたとえると、サイヤ人戦士の内部情報に保護シールドを張り、決められた場所からしか触れないようにするイメージです。

この記事では、private を使ってメンバを守る考え方を、Sample1.java と Sample1.java(修正後)を使って整理していきます。

問題の原因は外から自由に触れてしまうこと

まず、前の記事で使った形を確認します。

ファイル名:Sample1.java

class Saiyan
{
    String name;
    int power;
    String styleMark;
    String styleName;
    double kiEnergy;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
        System.out.println("気の量は" + kiEnergy + "です。");
    }
}

class Sample1
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();

        goku.name = "悟空";
        goku.power = 9000;
        goku.styleMark = "亀";
        goku.styleName = "亀仙流";
        goku.kiEnergy = 20.5;

        goku.show();
    }
}

このプログラムでは、Saiyan クラスの外にある main メソッドから、フィールドに直接値を入れています。

goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";
goku.kiEnergy = 20.5;

このように、オブジェクト名、ドット、フィールド名という形で、外からフィールドを直接操作しています。

値が自然な範囲なら、一見問題はなさそうに見えます。

フィールド入れている値状態
name悟空自然
power9000自然
styleMark自然
styleName亀仙流自然
kiEnergy20.5自然

実行すると、次のような表示になります。

戦士の名前は悟空です。
戦闘力は9000です。
流派の印は「亀」です。
流派名は亀仙流です。
気の量は20.5です。

ここだけを見ると、正しく動いているように見えます。

しかし、外から直接触れるということは、正しい値だけでなく、おかしな値も入れられてしまうということです。

たとえば、次のような代入も書けてしまいます。

goku.kiEnergy = -10.0;

気の量が -10.0 になるのは、サイヤ人戦士の状態としてかなり不自然です。

また、次のような値も危険です。

goku.power = -50;

戦闘力が -50 の悟空というのも、自然な状態ではありません。

さらに、流派情報も壊せてしまいます。

goku.styleMark = "";
goku.styleName = "";

これでは、悟空がどの流派に属しているのか分からなくなります。

ドラゴンボールでたとえると、戦士本人の状態を無視して、外部から無理やり「戦闘力はマイナス」「気の量はマイナス」「流派は空欄」と書き換えているようなものです。

これは、サイヤ人戦士というオブジェクトを自然に扱えているとは言えません。

private は外から直接触れないようにする指定

こうした危ない直接操作を防ぐために使うのが private です。

private は、メンバをクラスの外から直接使えないようにするための指定です。

フィールドに private をつけると、次のようになります。

ファイル名:Sample1.java(修正後)

class Saiyan
{
    private String name;
    private int power;
    private String styleMark;
    private String styleName;
    private double kiEnergy;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
        System.out.println("気の量は" + kiEnergy + "です。");
    }
}

class Sample1
{
    public static void main(String[] args)
    {
        Saiyan goku = new Saiyan();

        // goku.name = "悟空";
        // goku.power = 9000;
        // goku.styleMark = "亀";
        // goku.styleName = "亀仙流";
        // goku.kiEnergy = 20.5;

        goku.show();
    }
}

ここでは、name、power、styleMark、styleName、kiEnergy に private をつけています。

private String name;
private int power;
private String styleMark;
private String styleName;
private double kiEnergy;

これで、この5つのフィールドは private メンバになります。

private メンバは、クラスの外から直接アクセスできません。

そのため、次のような書き方はできなくなります。

goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";
goku.kiEnergy = 20.5;

この変化が、private の大きな役割です。

外から直接フィールドを書き換える道を閉じることで、危ない値が勝手に入ることを防ぎやすくなります。

private は隠して守るためのしくみ

private は、ひとことで言えば、メンバを隠して守るしくみです。

ただし、ここでいう「隠す」は、見えなくして困らせるという意味ではありません。

外から勝手に触れないようにする。
クラスの中で責任を持って管理する。
不自然な状態を作らせにくくする。

このような意味です。

ドラゴンボールでたとえると、悟空の名前、戦闘力、流派情報、気の量を、誰でも触れる場所に置かないようにすることです。

戦士データや気の状態記録は、大事な情報です。
誰でも自由に書き換えられると困ります。

だから、保護シールドやロックをかけて、決められた内部のしくみだけが扱えるようにします。

private の役割ドラゴンボールでたとえると
外から直接触れないようにする戦士情報に保護シールドを張る
内部で管理するSaiyan クラス自身が情報を扱う
危ない値を入りにくくする不自然な戦闘力や気の量を防ぐ
クラスを安全にする信頼できる戦士管理にする

private は、クラスの中身を守るための基本の道具です。

private をつけると何が変わるのか

private をつける前は、クラスの外からフィールドに直接アクセスできました。

goku.kiEnergy = -10.0;

この書き方ができると、気の量に不自然な値を入れられてしまいます。

しかし、kiEnergy を private にすると、外から直接アクセスできなくなります。

private double kiEnergy;

この状態では、main メソッドのようなクラスの外側から、次のような操作はできません。

goku.kiEnergy = -10.0;

つまり、private によって、外からの危ない直接代入を防げます。

状態外から直接代入できるか危険性
private なしできる不自然な値が入りやすい
private ありできない外からの直接操作を防げる

ここで大切なのは、private は「値の意味を自動で判断する魔法」ではないことです。

private をつけただけで、すべての不正な値を完全に防げるわけではありません。
しかし、外から直接フィールドを壊される入口を閉じられるので、安全な設計への大きな一歩になります。

図:private は外からの直接アクセスを防ぐ

この図が示していること

この図では、Sample1 の main から Saiyan クラスの private フィールド power や kiEnergy に直接アクセスしようとしている様子を表しています。

しかし、private がついているため、外からの直接アクセスは途中で遮られています。

ここから分かるのは、private はフィールドを完全に消すものではなく、外から勝手に触れないようにする守りのしくみだということです。

特に、power に -50、kiEnergy に -10.0 のような不自然な値を直接入れる道を閉じられるところが重要です。

なぜ private にすると安全に近づくのか

private にすると安全に近づく理由は、外から自由に触れなくなるからです。

たとえば、kiEnergy が外から直接触れる状態なら、次のような値をどれでも入れられます。

代入する値状態
20.5自然
0.0自然な可能性がある
-10.0不自然

外から直接触れる状態では、自然な値も不自然な値も同じように入れられてしまいます。

しかし private にすると、少なくともクラスの外からは次のような書き換えができなくなります。

goku.kiEnergy = -10.0;

これは、危ない操作の入口をふさぐということです。

ドラゴンボールでたとえると、戦士の気の量を誰でも書き換えられる紙にしておくのではなく、ロックされた戦士データベースにするようなものです。

ロックがあれば、外部の人が勝手にマイナスの気の量を書き込むことはできません。

クラスの中からは private メンバを使える

ここで大事なのは、private にしたメンバが完全に使えなくなるわけではないことです。

private メンバは、同じクラスの中からなら使えます。

次の show() メソッドを見てください。

void show()
{
    System.out.println("戦士の名前は" + name + "です。");
    System.out.println("戦闘力は" + power + "です。");
    System.out.println("流派の印は「" + styleMark + "」です。");
    System.out.println("流派名は" + styleName + "です。");
    System.out.println("気の量は" + kiEnergy + "です。");
}

name、power、styleMark、styleName、kiEnergy は private になっています。

private String name;
private int power;
private String styleMark;
private String styleName;
private double kiEnergy;

それでも、show() メソッドの中ではそのまま使えます。

なぜなら show() は Saiyan クラスの中にあるメソッドだからです。

場所private メンバにアクセスできるか
同じ Saiyan クラスの中できる
Sample1 クラスの main の中できない

ドラゴンボールでたとえると、戦士の内部情報は外部の人には触れません。
しかし、Saiyan クラス自身の内部処理や、クラスの中にある正規の機能からは扱えます。

つまり private は、完全に封印するものではありません。

外から勝手に触れないようにしつつ、クラスの中では責任を持って扱えるようにするしくみです。

private は見せるものと隠すものを分ける入口

private を理解するときに大切なのは、全部を外に見せる必要はないという感覚です。

クラスを設計するときは、次の2つを分けて考えます。

分けるもの内容
外から使わせたいもの必要な操作として公開するメソッド
外から直接触らせたくないもの内部で守るフィールド

たとえば、Saiyan クラスでは、show() は外から使わせてもよいメソッドです。

goku.show();

show() は、戦士の状態を表示するための自然な操作だからです。

一方で、name、power、styleMark、styleName、kiEnergy は、外から直接書き換えられると危険な情報です。

そのため、private をつけて守る候補になります。

メンバ外から直接触らせたいか理由
name注意が必要名前を勝手に壊される可能性がある
power直接触らせたくないマイナス戦闘力などが入りうる
styleMark直接触らせたくない流派の印が壊れる可能性がある
styleName直接触らせたくない流派名が不自然になる可能性がある
kiEnergy直接触らせたくないマイナスの気の量が入りうる
show()使わせてもよい状態を表示する自然な操作

ドラゴンボールでたとえると、戦士の状態を確認することは許してもよいです。
しかし、戦士の内部記録を書き換えることは、誰にでも許してよいものではありません。

private は、この「見せるもの」と「隠すもの」を分けるための入口です。

private にしただけでは値を設定できない問題もある

ここで、ひとつ大切な点があります。

フィールドを private にすると、外から直接値を入れられなくなります。

つまり、次のような代入はできません。

goku.name = "悟空";
goku.power = 9000;
goku.styleMark = "亀";
goku.styleName = "亀仙流";
goku.kiEnergy = 20.5;

これは安全性の面ではよいことです。

しかし、そのままだと外から戦士の名前、戦闘力、流派情報、気の量を設定する方法がなくなってしまいます。

この状態では、show() を呼び出しても、フィールドには初期値のままの値が入っています。

フィールド初期値のイメージ
String namenull
int power0
String styleMarknull
String styleNamenull
double kiEnergy0.0

つまり private は、外からの直接操作を防ぐ役割を持ちます。
ただし、必要な値を安全に設定するには、次の段階で「決められたメソッドを通して設定する」考え方が必要になります。

ここではまず、private によって外から直接触れなくなる、という基本を押さえることが大切です。

図:private メンバはクラスの中から使える

この図が示していること

この図では、private フィールドが Saiyan クラスの内部で守られている様子を表しています。

Sample1 の main から private フィールドへ直接触ろうとする赤い矢印は、途中で遮られています。
一方で、同じ Saiyan クラスの中にある show() からは、private フィールドへアクセスできています。

ここから分かるのは、private は「完全に使えなくする指定」ではないということです。

クラスの外からは隠し、クラスの中では責任を持って使えるようにする指定です。

クラスの中では private フィールドを自由に扱える

private の基本ルールをもう少し整理します。

Saiyan クラスの中では、private フィールドを使えます。

class Saiyan
{
    private String name;
    private int power;
    private String styleMark;
    private String styleName;
    private double kiEnergy;

    void show()
    {
        System.out.println("戦士の名前は" + name + "です。");
        System.out.println("戦闘力は" + power + "です。");
        System.out.println("流派の印は「" + styleMark + "」です。");
        System.out.println("流派名は" + styleName + "です。");
        System.out.println("気の量は" + kiEnergy + "です。");
    }
}

show() の中では、name、power、styleMark、styleName、kiEnergy をそのまま参照しています。

これは、show() が同じ Saiyan クラスの中にあるからです。

外からは触れない。
中からは使える。

この違いが private の中心です。

アクセスする場所private フィールドを使えるか
Saiyan クラスの中show() の中使える
Sample1 クラスの中main の中使えない

ドラゴンボールでたとえると、戦士の内部記録は外部の人には見せません。

しかし、Saiyan クラス自身が自分の状態を確認して報告することはできます。
show() は、その「本人からの報告」のような役割です。

8章の自由さから9章の安全さへ

8章では、クラスを作り、オブジェクトを作り、メンバにアクセスする基本を学びました。

そこでは、まず「どう使うか」が中心でした。

たとえば、オブジェクトを作って、フィールドに値を入れ、メソッドを呼び出す流れです。

しかし、9章ではそこに「どう守るか」という視点が加わります。

学習段階視点内容
8章使うクラスを作り、メンバにアクセスする
9章守るメンバを外から勝手に触らせない

ドラゴンボールでたとえると、8章は「サイヤ人戦士を作り、情報や技を持たせる段階」です。
9章は「戦士の大事な情報を守り、安全に扱う段階」です。

private は、その最初の一歩です。

フィールドを守る。
外からの勝手な書き換えを防ぐ。
自然な状態を保ちやすくする。

この3つにつながる、とても大切な指定です。

private があるとありえない状態を作りにくくなる

private の大きな価値は、外からありえない状態を作りにくくなることです。

たとえば kiEnergy が private でなければ、外から次のように書けます。

goku.kiEnergy = -10.0;

しかし private にしておけば、クラスの外から直接このような代入はできません。

これにより、少なくとも外部のコードが勝手に、

気の量がマイナスの戦士。
戦闘力が不自然な戦士。
流派情報が壊れた戦士。
内部状態が壊れた戦士。

を作ってしまう危険を減らせます。

もちろん、private だけで完全な安全が完成するわけではありません。

安全に値を設定するためには、次に、正しい入口となるメソッドを用意する考え方が必要になります。

ただ、最初の段階として「外から直接触れないようにする」ことは、とても強い守りになります。

ドラゴンボールでたとえると、private は戦士の内部情報を守る保護シールドです。
シールドを張ることで、外から勝手に戦闘力や気の量を書き換えられないようにします。

private を使うとクラスの責任がはっきりする

private を使うと、クラスの責任がはっきりします。

フィールドを外から自由に触らせる場合、値を正しく保つ責任が外側のコードにも広がってしまいます。

しかし private にすると、フィールドの管理はクラス自身が担当する、という考え方になります。

設計値を管理する責任
フィールドを外から直接触れる外側のコードにも責任が広がる
フィールドを private にするクラス自身が内部状態を管理する

ドラゴンボールでたとえると、悟空の戦闘力や気の状態は、外部の誰かが勝手に書き換えるものではありません。

Saiyan クラス自身、または決められた管理のしくみが責任を持って扱うものです。

Javaでも同じです。

フィールドを private にすることで、「この情報はこのクラスが責任を持って管理する」という設計になります。

図:private から安全な入口へ進む考え方

この図が示していること

この図は、private が安全なクラス設計の第一歩であることを示しています。

左側では、外から直接フィールドへ値を入れられるため、power に -50、kiEnergy に -10.0 のような不自然な値を入れられてしまいます。

中央では、private によってフィールドが守られ、外から直接触れなくなります。

右側では、次の段階として、決められたメソッドを通して安全に値を設定する考え方へ進んでいます。

ここから分かるのは、private は最終ゴールではなく、「外から勝手に壊される入口を閉じる」ための重要な第一歩だということです。

private を学ぶときの大切な見方

private を学ぶときは、次のように考えると分かりやすいです。

見るポイント意識すること
フィールド外から直接触らせてよいか
値の自然さ不自然な値が入る可能性はないか
クラスの責任内部状態を誰が管理するべきか
メソッド外から使わせる入口にするか
privateまず外からの直接操作を防ぐ

特にフィールドは、オブジェクトの状態そのものです。

戦士の名前、戦闘力、流派の印、流派名、気の量は、戦士の状態を表す大切な情報です。

これらが不自然な値になると、オブジェクト全体の意味が崩れてしまいます。

だからこそ、フィールドは private で守るという考え方が重要になります。

いちばん大事な感覚

privateでメンバを守る方法で大切なのは、次の感覚です。

ポイント内容
問題の原因外からメンバを無制限に触れてしまうこと
private の役割クラスの外から直接アクセスできないようにする
クラス内の扱い同じクラスの中からは private メンバを使える
守る意味不自然な値を外から入れられにくくする
設計の考え方中身は隠し、必要な操作だけ外に見せる
次につながること正しい入口となるメソッドを用意する考え方

ドラゴンボールでたとえると、戦士の大事な内部情報は、誰でも勝手にいじれるべきではありません。

戦闘力や気の量、流派情報のような重要な値は、外からむやみに触らせず、まず private で守ります。

そのうえで、必要な操作だけを安全な入口として用意していくことが、これからのクラス設計で大切になります。

private が分かると、クラスは単なる情報の入れ物ではなく、自分の中身を守りながら安全に使ってもらう部品として見えてきます。