JAVAの初心者向け問題4-2:カプセル化を理解しよう
この問題を解くために必要な知識:
【レベル1~3の知識】
基礎文法、四則演算、演算子、分岐処理(if、if~else、switch)、繰り返し処理(for、while、do~while)、配列、List、ArrayList、オブジェクトの基礎、メソッドの基本、メソッドの戻り値、メソッドのオーバーロード、クラスの基本、コンストラクタ、クラスの継承、コレクションの基礎、HashMap、TreeMap、HashSet、TreeSet、
【レベル4の知識】
インスタンスメソッド、ゲッターとセッター、カプセル化、クラスメンバ、抽象クラス、インターフェース
<<前の問題 | 問題集Top |
次の問題>> |
JAVAの文法「カプセル化」とは
ここではカプセル化の意味や使い方を復習します。必要ない方はここをクリックして練習問題へ飛びましょう。
「カプセル化」という重要な概念について説明します。
カプセル化は、オブジェクト指向プログラミングにおける基本的な概念であり、コードを安全で効率的に保つために必要なテクニックです。
カプセル化とは?
カプセル化とは、オブジェクトのデータ(変数)とそれに関連する処理(メソッド)を一つにまとめ、その内部状態を外部から直接アクセスできないようにすることを指します。
これにより、データの不正な変更や誤用を防ぎ、プログラムの安全性が高まります。
具体的には、以下のような2つのポイントがカプセル化の目的です。
- データを隠す(情報隠蔽)
クラスの内部データ(フィールド)は外部から直接変更されるべきではありません。代わりに、適切な方法でデータを管理するメソッドを通して操作します。 - データへのアクセスを制御する
フィールドは基本的にprivate
に設定し、データを変更する際は、専用のメソッド(ゲッターとセッター)を通じて操作します。これにより、外部からの不正なアクセスや予期しない変更を防ぎます。
カプセル化の基本例
実際に、カプセル化がどのように機能するかをJavaのコードで見てみましょう。
以下は、ペットクラスをカプセル化した例です。
class Pet { // フィールドをprivateにして、外部から直接アクセスできないようにする private String name; private int age; // コンストラクタでフィールドの初期化 public Pet(String name, int age) { this.name = name; this.age = age; } // nameフィールドへのアクセスを提供するゲッターメソッド public String getName() { return name; } // nameフィールドを設定するセッターメソッド public void setName(String name) { this.name = name; } // ageフィールドへのアクセスを提供するゲッターメソッド public int getAge() { return age; } // ageフィールドを設定するセッターメソッド public void setAge(int age) { if (age > 0) { // 年齢が正の値であることを確認 this.age = age; } } // ペットの情報を表示するメソッド public void showInfo() { System.out.println("名前: " + name + ", 年齢: " + age + "歳"); } }
カプセル化のポイント解説
private
修飾子でフィールドを隠す
private String name; private int age;
name
と age
というフィールドは private
で定義されています。
これにより、クラスの外部から直接アクセスすることができなくなります。
カプセル化の目的は、データの不正な変更を防ぐことなので、フィールドを private
にするのが一般的です。
ゲッターメソッドとセッターメソッド
public String getName() { return name; } public void setName(String name) { this.name = name; }
getName
と setName
は、それぞれ name
フィールドへのアクセスを提供するメソッドです。
ゲッターメソッドはフィールドの値を取得するために使われ、セッターメソッドはフィールドの値を変更するために使われます。
このようにすることで、フィールドに対して直接アクセスするのではなく、メソッドを介して安全に操作できます。
データの制約を追加する
public void setAge(int age) { if (age > 0) { // 年齢が正の値であることを確認 this.age = age; } }
セッターメソッドにはデータの検証を追加することもできます。
ここでは、age
が負の値にならないように、0より大きい場合のみ値を設定しています。
このような制約をセッターメソッド内に加えることで、不正なデータがフィールドに設定されるのを防ぐことができます。
カプセル化の利点
カプセル化には以下のような利点があります。
- データの保護
private
修飾子を使ってデータへの直接アクセスを防ぎ、外部からの不正な変更を防止します。これにより、プログラムが意図しない動作をするリスクを減らすことができます。 - データの一貫性を保つ
セッターメソッドで入力値を検証することで、不正なデータがシステムに流れ込むのを防ぐことができます。例えば、年齢がマイナスになるような不正な値を設定するのを防ぐことができます。 - コードの可読性とメンテナンス性の向上
ゲッターやセッターを通じてフィールドの操作を行うことで、コードの変更が容易になります。後からフィールドの処理を変更したい場合も、ゲッターやセッターを変更するだけで済むため、他の部分に影響を与えにくくなります。
まとめ
カプセル化は、Javaのオブジェクト指向プログラミングにおいて重要な概念です。データを安全に保つだけでなく、コードの保守性を向上させるためにも不可欠な手法です。
- データ(フィールド)を
private
にして外部から隠す - ゲッターとセッターを使ってデータへのアクセスを管理する
- セッターでデータの検証を行い、システムの安全性を高める
これらを理解することで、より安全で信頼性の高いプログラムを作成することができるようになります。
カプセル化をしっかりと身につけ、効率的なプログラミングに活かしましょう!
JAVA練習問題4-2_カプセル化を使った学生情報管理プログラム
学生の情報を管理するプログラムを作成しましょう。
このプログラムでは、学生の名前と年齢を格納し、これらの情報をカプセル化を使って管理します。
また、複数の学生情報をリストに格納し、一覧表示する機能を実装します。
この問題の要件
以下の要件に従って作成して下さい。
Student
クラスを作成し、以下のフィールドを持つこと。name
(学生の名前):String
型age
(学生の年齢):int
型
Student
クラスには以下のメソッドを持つこと。getName
メソッド: 学生の名前を返す。setName
メソッド: 学生の名前を設定する。getAge
メソッド: 学生の年齢を返す。setAge
メソッド: 学生の年齢を設定する。
- メインプログラムで、複数の学生情報を格納するリストを作成し、学生情報を追加する機能を実装すること。
- 全ての学生情報を一覧表示する機能を実装すること。
ただし、以下のような実行結果となること。
----- ↓出力される結果の例↓ -----
学生の名前を入力してください(終了するには 'exit' と入力): 山田太郎 学生の年齢を入力してください: 20 学生の名前を入力してください(終了するには 'exit' と入力): 佐藤花子 学生の年齢を入力してください: 19 学生の名前を入力してください(終了するには 'exit' と入力): exit 登録された学生の情報: 名前: 山田太郎, 年齢: 20 名前: 佐藤花子, 年齢: 19
----- ↑出力される結果の例↑ -----
この問題を解くヒント
1からコードを組み立てることが難しい場合は、以下のヒントを開いて参考にしましょう。
正解のコードは上から順に以下のような構成となっています。
1.import文
1-1. ArrayListクラスのインポート
1-2. Scannerクラスのインポート
2.Studentクラスの定義
2-1. フィールドの定義
2-1-1. 名前を格納するnameフィールド(private)
2-1-2. 年齢を格納するageフィールド(private)
2-2. コンストラクタの定義
2-2-1. 名前と年齢を初期化するコンストラクタ
2-3. ゲッターメソッドの定義
2-3-1. 名前を取得するgetNameメソッド
2-3-2. 年齢を取得するgetAgeメソッド
2-4. セッターメソッドの定義
2-4-1. 名前を設定するsetNameメソッド
2-4-2. 年齢を設定するsetAgeメソッド
3.StudentManagementクラスの定義
3-1. mainメソッド
3-1-1. Scannerオブジェクトの作成
3-1-2. ArrayListオブジェクトの作成
3-1-3. whileループでユーザー入力を受け取る
3-1-3-1. ユーザーに学生の名前を入力させる
3-1-3-2. exitと入力された場合はループを終了
3-1-3-3. ユーザーに学生の年齢を入力させる
3-1-3-4. 新しいStudentオブジェクトを作成しリストに追加
3-1-4. 学生情報を一覧表示する
3-1-4-1. forループでリスト内の全てのStudentオブジェクトを表示
3-1-5. Scannerオブジェクトを閉じる
以下のコードをコピーし、コメントに従ってコードを完成させて下さい。
import java.util.ArrayList; import java.util.Scanner; // 学生情報を管理するクラス class Student { private String name; // 学生の名前 private int age; // 学生の年齢 // ***ここでコンストラクタを定義してください*** // ***ここで名前を取得するgetNameメソッドを定義してください*** // ***ここで名前を設定するsetNameメソッドを定義してください*** // ***ここで年齢を取得するgetAgeメソッドを定義してください*** // ***ここで年齢を設定するsetAgeメソッドを定義してください*** } 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(); // 改行を消費 // ***ここでStudentオブジェクトを作成してリストに追加してください*** } // 学生情報を一覧表示 System.out.println("登録された学生の情報:"); // ***ここでリスト内の全てのStudentオブジェクトを表示するコードを書いてください*** scanner.close(); } }
このヒントを見てもまだ回答を導き出すのが難しいと感じる場合は、先に正解のコードと解説を見て内容を理解するようにしましょう。
解答例
この問題の一つの正解例とそのコードの解説を以下に示します。
正解コードの例
例えば以下のようなプログラムが考えられます。
********************
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()); } scanner.close(); } }
********************
コードの解説
クラスとフィールドの定義
class Student { private String name; private int age; }
Student
クラスの name
と age
は、それぞれ学生の名前と年齢を保持するためのフィールドです。
ここでのポイントは、private
修飾子を使って、フィールドを外部から直接アクセスできないようにしている点です。
これがカプセル化の基盤です。カプセル化により、外部からフィールドが勝手に変更されることを防ぎ、安全性を高めます。
コンストラクタでの初期化
public Student(String name, int age) { this.name = name; this.age = age; }
コンストラクタは、Student
クラスのオブジェクトが生成されたときに呼ばれるメソッドです。
ここでは、name
と age
を設定しています。this.name = name
のようにして、オブジェクトのフィールドを初期化しています。
ゲッターメソッドとセッターメソッド
public String getName() { return name; } public void setName(String name) { this.name = name; }
ここで登場するのが、カプセル化において重要な役割を果たすゲッターメソッドとセッターメソッドです。
- ゲッターメソッド(
getName
など)は、private
に設定されたフィールドに外部からアクセスするためのメソッドです。フィールドの値を取得します。 - セッターメソッド(
setName
など)は、private
フィールドの値を安全に変更するために用います。name
フィールドに新しい値を設定します。
ゲッターとセッターを使うことで、データの変更や取得を管理でき、必要に応じて値に制約を加えたり、データの整合性を保つことが可能です。
学生情報の管理
ArrayList<Student> students = new ArrayList<>(); students.add(new Student("ポチ", 3));
この部分では、ArrayList
というデータ構造を使って複数の Student
オブジェクトを管理しています。
new Student("ポチ", 3)
により、名前が「ポチ」で年齢が3歳の学生オブジェクトを作成し、その後リストに追加しています。
まとめ
カプセル化は、データの保護や制御を行う上で重要な役割を果たす概念です。
この学生管理プログラムでは、name
や age
といったフィールドを private
に設定し、セッターとゲッターを通じて安全にデータの操作を行っています。
カプセル化を活用することで、プログラムの信頼性やメンテナンス性を高めることができるので、Javaのプログラミングにおいては必ず身につけるべき技術です。
<<前の問題 |
問題集Top |
次の問題>> |
この問題への質問・コメント
この問題を作成するにあたりAIを活用しています。
問題ないことは確認していますが、もし間違いや表現の違和感などありましたら、ご指摘頂けると大変助かります。