【Java】レッスン5-3:カプセル化を理解しよう

ながみえ

一つ前のページではコンストラクタについて学習しました。

今回は カプセル化 について見ていきましょう。

Lesson1:基礎文法編
Lesson2:制御構造編
Lesson3:メソッド編
Lesson4:コレクション編
Lesson5:クラス

 ・Lesson5-1:クラスの基本を確認しよう
 ・Lesson5-2:コンストラクタを理解しよう
 ・Lesson5-3:カプセル化を理解しよう ◁今回はココ
 ・Lesson5-4:クラスメンバとインスタンスメンバを理解しよう
 ・Lesson5-5:クラスの継承を理解しよう
 ・Lesson5-6:メソッドのオーバーライドを理解しよう
 ・Lesson5-7:抽象クラスを理解しよう
 ・Lesson5-8:インターフェースを理解しよう
 ・確認問題5-☆1:モンスター捕獲ゲームを作ろう
 ・確認問題5-☆2:モンスターとのバトルゲームを作ろう
 ・確認問題5-☆3:マルバツゲーム(Tic-Tac-Toe)を作成しよう

<<前のページ

学習記事一覧

次のページ>>

カプセル化とは|アクセス修飾子とゲッター・セッターによるデータ保護の基本

Javaにおけるカプセル化とは、クラスの内部データを外部から直接操作できないようにし、安全性と保守性を高める仕組みです。

アクセス修飾子(privatepublicなど)を使ってデータを隠し、必要に応じてゲッター(getter)やセッター(setter)メソッドを通じてアクセスを制御します。

本記事では、カプセル化の基本概念から実装方法、ゲッター・セッターの使い方までを初心者にもわかりやすく解説します。

これを学べば、安全で拡張性のあるクラス設計ができるようになり、オブジェクト指向プログラミングの理解が一段と深まるでしょう。

カプセル化とは何か?|アクセス修飾子の種類と公開範囲の早見表

カプセル化(Encapsulation)とは、クラス内のデータ(フィールド)や処理を他のクラスから隠し、アクセス制御を行うことを言います。

これにより外部のコードが直接クラス内データに触れることができなくなり、不正なデータ操作や意図しないエラーを防ぎます。

Javaでは アクセス修飾子 を用いて、そのデータにアクセスできる範囲がどこまでかを設定できます。

代表的な修飾子として以下が挙げられます。

  • private:同じクラス内でのみアクセス可能
  • package-private:同じパッケージ内からアクセス可能
  • protected:同じパッケージ内や子クラスからアクセス可能
  • public:どこからでもアクセス可能

アクセス可能範囲を表にまとめると以下のようになります。

修飾子同じクラス内同じパッケージ内子クラスその他のクラス
publicアクセス可能アクセス可能アクセス可能アクセス可能
protectedアクセス可能アクセス可能アクセス可能アクセス不可
package-private
(省略時)
アクセス可能アクセス可能アクセス不可アクセス不可
privateアクセス可能アクセス不可アクセス不可アクセス不可

パッケージとはクラスをフォルダ分けする仕組みのことです。実際のフォルダ構造と対応していて、クラスを整理するために使います。

すなわち「同じパッケージ内」とは、同じフォルダに保存したJavaファイルのことを指します。

また子クラスについては レッスン5-5:クラスの継承を理解しよう で学習します。

アクセス修飾子は、変数の宣言時にその型の前に記述して使用します。

public class Test {
    private int a;	 // 変数aはこのTestクラスの中からのみアクセス可能。
  	int b;			 // 省力するとpackage-privateとなる。同じパッケージ内からアクセス可能。
    protected int c; // 変数cは同じパッケージ内や子クラスからアクセス可能。
    public String d; // 変数dはどこからでもアクセス可能。
}

そしてこの修飾子をprivateに指定し、外部に公開しないことをカプセル化と言います。

ゲッターとセッターの使い方|安全なアクセス方法とコード例

カプセル化することで外部から直接データを書き換えられないようになり、不正な値の代入や、予期しない動作を防ぐことができます。

しかし完全に遮断してしまうと不便なので、外部から安全にデータをやりとりするための ゲッター と セッター を使用しましょう。

  • ゲッター:カプセル化されたプロパティの値を取得するためのメソッド
  • セッター:カプセル化されたプロパティに値を設定するためのメソッド

以下のコードは、privateで定義されたscore変数を操作するためのゲッターとセッターの例です。

public class Player {		// Playerクラスの定義
    private int score;		// カプセル化されたフィールド
  
    public int getScore() { // ゲッターメソッドの定義
        return score;		// scoreの値を取得(クラス内なのでOK)し、戻り値として返す
    }
    public void setScore(int score) {	// セッターメソッドの定義
        this.score = score;				// 引数をフィールドのscoreに代入(クラス内なのでOK)
    }
}

public class Main {	// メインクラス
    public static void main(String[] args) {
        Player player = new Player();	// インスタンス生成
        
        // セッターを使用してscoreにアクセス
        player.getScore(100);
      	// ゲッターを使用してscoreにアクセス
        System.out.println(player.getScore());
      	// ゲッターを使わずにscoreに直接アクセスしようとする
        System.out.println(player.score); // コンパイルエラー
    }
}

scoreフィールドはprivateなので直接アクセスできません。

例えばメインクラス内でこのクラスをインスタンス生成し、値を操作しようとしてもエラーとなります。

メインクラス内から値を操作するには、定義したgetScore()メソッドやsetScore(int score)メソッドを呼び出す必要があります。

まとめ|安全で保守性の高いクラス設計の基礎

今回の学習ではカプセル化の概念とその目的、アクセス修飾子による公開範囲の制御方法、そしてゲッター・セッターを用いた安全なデータアクセス方法について学びました。

これにより、クラス内部のデータを不正な変更から守りつつ、必要な機能だけを外部に公開できる設計が可能になります。

こうした安全で保守性の高いコード設計は、規模の大きなシステム開発や長期運用にも対応できる重要なスキルです。

ここで得た知識を土台に、より高度なオブジェクト指向設計へとステップアップしていきましょう。

練習問題|カプセル化を使って学生情報を安全に管理するプログラムを作成しよう

学生の情報を管理するプログラムを作成しましょう。

このプログラムでは、学生の名前と年齢を格納し、これらの情報をカプセル化を使って管理します。

また、複数の学生情報をリストに格納し、一覧表示する機能を実装します。

この問題の要件

以下の要件に従ってコードを完成させてください。

  1. Student クラスを作成し、以下のフィールドを持つこと。
    • name(学生の名前): String
    • age(学生の年齢): int
  2. Student クラスには以下のメソッドを持つこと。
    • getName メソッド: 学生の名前を返す。
    • setName メソッド: 学生の名前を設定する。
    • getAge メソッド: 学生の年齢を返す。
    • setAge メソッド: 学生の年齢を設定する。
  3. メインプログラムで、複数の学生情報を格納するリストを作成し、学生情報を追加する機能を実装すること。
  4. 全ての学生情報を一覧表示する機能を実装すること。

ただし、以下のような実行結果となること。

学生の名前を入力してください(終了するには 'exit' と入力):
山田太郎
学生の年齢を入力してください:
20
学生の名前を入力してください(終了するには 'exit' と入力):
佐藤花子
学生の年齢を入力してください:
19
学生の名前を入力してください(終了するには 'exit' と入力):
exit
登録された学生の情報:
名前: 山田太郎, 年齢: 20
名前: 佐藤花子, 年齢: 19

この問題を解くヒント

1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。

Q
ヒント1【コードの構成を見る】

正解のコードは上から順に以下のような構成となっています。

1:ArrayListとScannerクラスをインポート
2:Studentクラスの定義
  □ Studentクラス内でnameとageフィールドをprivateで宣言
  □ Studentクラスのコンストラクタの定義(nameとageを初期化)
  □ getNameメソッドの定義(nameフィールドを取得)
  □ setNameメソッドの定義(nameフィールドを設定)
  □ getAgeメソッドの定義(ageフィールドを取得)
  □ setAgeメソッドの定義(ageフィールドを設定)
3:StudentManagementクラスの定義
  □ mainメソッドの定義
  □ □ Scannerオブジェクトscannerを初期化
  □ □ ArrayListオブジェクトstudentsを初期化
  □ □ whileループの開始
  □ □ □ 「学生の名前を入力してください(終了するには ‘exit’ と入力):」と出力
  □ □ □ ユーザー入力を受け取り、変数nameに代入
  □ □ □ if文でnameが「exit」と同じかを判定
  □ □ □ □ nameが「exit」と同じ場合、breakでループを終了
  □ □ □ 「学生の年齢を入力してください:」と出力
  □ □ □ ユーザーから年齢を入力し、変数ageに代入
  □ □ □ scanner.nextLine()で改行を消費
  □ □ □ Studentオブジェクトを生成し、studentsリストに追加
  □ 「登録された学生の情報:」と出力
  □ forループでstudentsリストの各Studentオブジェクトを取得
  □ □ StudentオブジェクトのgetNameとgetAgeメソッドを使用して情報を出力

Q
ヒント2【穴埋め問題にする】

以下のコードをコピーし、コメントに従ってコードを完成させて下さい。

import java.util.ArrayList;
import java.util.Scanner;

// 学生情報を管理するクラス
class Student {
    /*【穴埋め問題1】
    ここにnameとageフィールドをprivateで宣言してください。
    */

    // コンストラクタ
    public Student(String name, int age) {
        /*【穴埋め問題2】
        ここでnameとageフィールドに引数の値を代入するコードを書いてください。
        */
    }

    // 名前を取得するメソッド
    /*【穴埋め問題3】
    ここにnameフィールドを取得するgetNameメソッドをpublicで定義してください。
    */

    // 名前を設定するメソッド
    /*【穴埋め問題4】
    ここにnameフィールドを設定するsetNameメソッドをpublicで定義してください。
    */

    // 年齢を取得するメソッド
    /*【穴埋め問題5】
    ここにageフィールドを取得するgetAgeメソッドをpublicで定義してください。
    */

    // 年齢を設定するメソッド
    /*【穴埋め問題6】
    ここにageフィールドを設定するsetAgeメソッドをpublicで定義してください。
    */
}

public class StudentManagement {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Student> students = new ArrayList<>();

        // 学生情報を入力してリストに追加
        while (true) {
            System.out.println("学生の名前を入力してください(終了するには 'exit' と入力):");
            String name = scanner.nextLine();
            if (name.equalsIgnoreCase("exit")) {
                break;
            }

            System.out.println("学生の年齢を入力してください:");
            int age = scanner.nextInt();
            scanner.nextLine(); // 改行を消費

            // 学生オブジェクトを作成してリストに追加
            students.add(new Student(name, age));
        }

        // 学生情報を一覧表示
        System.out.println("登録された学生の情報:");
        for (Student student : students) {
            System.out.println("名前: " + student.getName() + ", 年齢: " + student.getAge());
        }
    }
}

このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。

練習問題の解答と解説

この問題の正解コードとその解説は以下の通りです。

クリックして開いて確認してください。

Q
正解コード
import java.util.ArrayList;
import java.util.Scanner;

// 学生情報を管理するクラス
class Student {
    private String name; // 学生の名前
    private int age;     // 学生の年齢

    // コンストラクタ
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 名前を取得するメソッド
    public String getName() {
        return name;
    }

    // 名前を設定するメソッド
    public void setName(String name) {
        this.name = name;
    }

    // 年齢を取得するメソッド
    public int getAge() {
        return age;
    }

    // 年齢を設定するメソッド
    public void setAge(int age) {
        this.age = age;
    }
}

public class StudentManagement {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Student> students = new ArrayList<>();

        // 学生情報を入力してリストに追加
        while (true) {
            System.out.println("学生の名前を入力してください(終了するには 'exit' と入力):");
            String name = scanner.nextLine();
            if (name.equalsIgnoreCase("exit")) {
                break;
            }

            System.out.println("学生の年齢を入力してください:");
            int age = scanner.nextInt();
            scanner.nextLine(); // 改行を消費

            // 学生オブジェクトを作成してリストに追加
            students.add(new Student(name, age));
        }

        // 学生情報を一覧表示
        System.out.println("登録された学生の情報:");
        for (Student student : students) {
            System.out.println("名前: " + student.getName() + ", 年齢: " + student.getAge());
        }

    }
}
Q
正解コードの解説

コードをブロックごとに分割して解説します。

Student クラスの定義

class Student {
    private String name; // 学生の名前
    private int age;     // 学生の年齢
}

Student クラスは学生の情報を管理するクラスで、「カプセル化」を使って名前と年齢のデータを保護しています。

ここでprivate 修飾子を使うことで、このクラスの外部から nameage に直接アクセスできないようにしています。

これによりデータが意図しない方法で変更されるのを防ぐことができます。

コンストラクタの定義

public Student(String name, int age) {
    this.name = name;
    this.age = age;
}

コンストラクタは Student クラスのオブジェクトが生成されるときに呼び出され、渡された nameage をフィールドに設定します。

this.name のように this キーワードを使うことで、フィールドと引数を区別しています。

ゲッターとセッター

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

ここで「カプセル化」の重要な役割がさらに明らかになります。

getNamesetAge といったメソッドは「ゲッター」「セッター」と呼ばれ、それぞれフィールドの値を取得・設定するためのメソッドです。

フィールドを private にすることで外部から直接アクセスできなくし、代わりに public なゲッターとセッターを通じて安全にアクセスできるようにしています。

この方法によりage フィールドの値を外部のコードから意図しない方法で変更されないようにすることが可能です。

StudentManagement クラスと main メソッドの開始

public class StudentManagement {
    public static void main(String[] args) {

StudentManagement クラスには main メソッドが含まれ、Javaプログラムのエントリーポイントとなっています。

このメソッドでプログラムの実行が始まり、ユーザーから学生の情報を入力し、管理する機能を提供します。

スキャナーとリストの初期化

Scanner scanner = new Scanner(System.in);
ArrayList<Student> students = new ArrayList<>();

Scanner クラスを使ってユーザー入力を取得し、ArrayList を使って複数の Student オブジェクトをリストに格納します。

学生情報の入力と追加

while (true) {
    System.out.println("学生の名前を入力してください(終了するには 'exit' と入力):");
    String name = scanner.nextLine();
    if (name.equalsIgnoreCase("exit")) {
        break;
    }

    System.out.println("学生の年齢を入力してください:");
    int age = scanner.nextInt();
    scanner.nextLine(); // 改行を消費

    students.add(new Student(name, age));
}

この部分ではユーザーに学生の名前と年齢を入力させ、入力された情報を基に新しい Student オブジェクトを作成して students リストに追加します。

while ループを使いexit と入力されるまで繰り返し情報を追加できます。

学生情報の表示

System.out.println("登録された学生の情報:");
for (Student student : students) {
    System.out.println("名前: " + student.getName() + ", 年齢: " + student.getAge());
}

最後にfor-each ループを使って students リスト内のすべての Student オブジェクトの名前と年齢を表示します。

ここで getName()getAge() メソッドを使用して Student オブジェクトのデータを取得し、安全に表示します。

もっと分かりやすい学習サイトにするために

この記事を読んで「ここが分かりにくかった」「ここが難しかった」等の意見を募集しています。

世界一わかりやすいJava学習サイトにするため、ぜひ 問い合わせフォーム からご意見下さい。

<<前のページ

学習記事一覧

次のページ>>

記事URLをコピーしました