【Java】レッスン5-03:カプセル化とは?データを安全に保つための基本を学ぼう

一つ前のページではコンストラクタについて学習しました。
今回は カプセル化 について見ていきましょう。
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のカプセル化とは|アクセス制御とデータ保護の基本

プログラミングではクラスを使用してデータを安全に管理するために「カプセル化」を利用します。
カプセル化によりデータが不正に操作されることを防ぎ、クラス内部のデータを安全に保つことが可能です。
カプセル化の定義と目的|Javaにおけるデータの隠蔽とは
カプセル化(Encapsulation)はクラス内のデータ(フィールド)や処理を他のクラスから隠し、アクセス制御を行うことを言います。
これにより外部のコードが直接データに触れることができなくなり、不正なデータ操作や意図しないエラーを防ぎます。
Javaではデータを保護するために、アクセス修飾子を使用して変数やメソッドの可視性を制御します。
例えばprivate
修飾子を使うと、その変数は同じクラス内からのみアクセス可能になり、外部からは直接変更できません。
このようにしてクラス内部のデータが隠蔽され、データの保護が実現します。
アクセス修飾子で制御する可視性の仕組み
Javaではアクセス修飾子を用いてクラスやそのメンバ(変数、メソッドなど)へのアクセス範囲を設定できます。代表的な修飾子として以下が挙げられます。
- private:同じクラス内でのみアクセス可能
- protected:同じパッケージ内やサブクラスからアクセス可能
- public:どこからでもアクセス可能
public class Test { // テストクラスのフィールド private int a; //変数aはこのTestクラスの中からのみアクセス可能。 protected int b; // 変数bは同じパッケージ内やサブクラスからアクセス可能。 public String c; //変数cはどこからでもアクセス可能。 }
カプセル化は通常はprivate
で変数宣言され、外部には公開しません。
その代わりに、クラス外部からデータを取得・更新するためのメソッド(ゲッター、セッター)をpublic
として提供します。
ゲッターとセッターの使い方|外部からの安全なアクセス方法
カプセル化されたデータにアクセスするために、Javaでは「ゲッター」と「セッター」というメソッドを使用します。
ゲッターは変数の値を取得するためのメソッドで、セッターは変数の値を設定するためのメソッドです。
以下にprivate
で定義されたscore
変数に対するゲッターとセッターを例として示します。
public class Player { // カプセル化されたフィールド private int score; // ゲッターメソッド(scoreの値を取得) public int getScore() { return score; } // セッターメソッド(scoreの値を設定) public void setScore(int score) { // scoreが0以上の場合のみ設定 if (score >= 0) { this.score = score; } } }
この例ではscore
フィールドはprivate
として宣言され、直接アクセスできないようにしています。
getScore()
メソッドでscore
の値を取得でき、setScore(int score)
メソッドで値を更新できます。
またsetScore
ではscore
の値が0以上の場合のみ更新されるため、データの整合性も保たれます。
private変数に直接アクセスするとどうなる?典型的なエラー例を解説
カプセル化ではフィールドがprivate
で定義されるため、クラス外から直接アクセスするとエラーが発生します。
以下はPlayer
クラスのscore
フィールドにゲッターを使わずにアクセスしようとする例です。
public class Player { private int score; public Player(int score) { this.score = score; } } public class Main { public static void main(String[] args) { Player player = new Player(100); // ゲッターを使わずにscoreに直接アクセスしようとする System.out.println(player.score); // コンパイルエラー } }
このコードを実行すると、以下のようなコンパイルエラーメッセージが表示されます。
error: score has private access in Player System.out.println(player.score); ^
このエラーはscore
がprivate
で宣言されているため、Player
クラスの外部から直接アクセスできないことが原因です。
解決するためにはPlayer
クラス内にゲッター(getScore()
)メソッドを定義し、score
にアクセスできるようにします。
public class Player { private int score; public Player(int score) { this.score = score; } // ゲッターメソッド public int getScore() { return score; } } public class Main { public static void main(String[] args) { Player player = new Player(100); // ゲッターを使用してscoreにアクセス System.out.println(player.getScore()); // 正常に出力される } }
これによりMain
クラスからもgetScore()
メソッドを通じてscore
の値にアクセスできるようになり、エラーが解消されます。
カプセル化のまとめ|保守性と安全性を高める鍵
カプセル化はデータを保護し、クラスの一貫性を保つための重要な概念です。
アクセス修飾子とゲッター・セッターを組み合わせることで、外部からの不正な操作を防ぎ、オブジェクト指向プログラミングの基本である「データの安全性」を確保できます。
カプセル化を理解することで、より堅牢でメンテナンス性の高いコードを書くことができるでしょう。
練習問題|カプセル化を使って学生情報を安全に管理するプログラムを作成しよう

学生の情報を管理するプログラムを作成しましょう。
このプログラムでは、学生の名前と年齢を格納し、これらの情報をカプセル化を使って管理します。
また、複数の学生情報をリストに格納し、一覧表示する機能を実装します。
この問題の要件
以下の要件に従ってコードを完成させてください。
Student
クラスを作成し、以下のフィールドを持つこと。name
(学生の名前):String
型age
(学生の年齢):int
型
Student
クラスには以下のメソッドを持つこと。getName
メソッド: 学生の名前を返す。setName
メソッド: 学生の名前を設定する。getAge
メソッド: 学生の年齢を返す。setAge
メソッド: 学生の年齢を設定する。
- メインプログラムで、複数の学生情報を格納するリストを作成し、学生情報を追加する機能を実装すること。
- 全ての学生情報を一覧表示する機能を実装すること。
ただし、以下のような実行結果となること。
学生の名前を入力してください(終了するには 'exit' と入力): 山田太郎 学生の年齢を入力してください: 20 学生の名前を入力してください(終了するには 'exit' と入力): 佐藤花子 学生の年齢を入力してください: 19 学生の名前を入力してください(終了するには 'exit' と入力): exit 登録された学生の情報: 名前: 山田太郎, 年齢: 20 名前: 佐藤花子, 年齢: 19
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
- ヒント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メソッドを使用して情報を出力
- ヒント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()); } } }
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
練習問題の解答と解説
この問題の正解コードとその解説は以下の通りです。
クリックして開いて確認してください。
- 正解コード
-
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()); } } }
- 正解コードの解説
-
コードをブロックごとに分割して解説します。
Student
クラスの定義class Student { private String name; // 学生の名前 private int age; // 学生の年齢 }
Student
クラスは学生の情報を管理するクラスで、「カプセル化」を使って名前と年齢のデータを保護しています。ここで
private
修飾子を使うことで、このクラスの外部からname
とage
に直接アクセスできないようにしています。これによりデータが意図しない方法で変更されるのを防ぐことができます。
コンストラクタの定義
public Student(String name, int age) { this.name = name; this.age = age; }
コンストラクタは
Student
クラスのオブジェクトが生成されるときに呼び出され、渡されたname
とage
をフィールドに設定します。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; }
ここで「カプセル化」の重要な役割がさらに明らかになります。
getName
やsetAge
といったメソッドは「ゲッター」「セッター」と呼ばれ、それぞれフィールドの値を取得・設定するためのメソッドです。フィールドを
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の「カプセル化」の概念を使って Student
クラスのデータを保護しています。
private
フィールドと public
なゲッター・セッターの組み合わせにより、クラス外からの不正なアクセスを防ぎ、コードの安全性が向上します。
カプセル化はJavaにおける重要な概念であり、これを理解することでより安全で保守性の高いプログラムが書けるようになります。