カプセル化とは、プログラムを作るときにデータを安全に保つための重要な考え方で、その名の通りソースコード(特にデータ=変数)をカプセルにいれるようなイメージで外部からデータを保護することを指します。
Javaではカプセル化を実現するためにアクセス修飾子を使用。アクセス修飾子とは、クラスのメンバー(フィールドやメソッド)に対するアクセスの範囲を制限するキーワードで、主なアクセス修飾子には、public
、protected
、default
(修飾子なし)、private
の4種類がある、というのがこのページの結論です。
アクセス修飾子 | 内容 | アクセス範囲 |
---|---|---|
public | すべてのクラスからアクセス可能 | プロジェクト全体 |
protected | 同じパッケージおよびサブクラスからアクセス可能 | パッケージとサブクラス |
default (なし) | 同じパッケージ内でアクセス可能 | パッケージ内 |
private | 同じクラス内でのみアクセス可能 | クラス内 |
ここでは↑のアクセス修飾子の使い方=カプセル化の概念についてわかりやすく1からご説明していきます。
関連 Javaの1stステップ:基本的な構文ルールを1分で復習!
カプセル化とは?わかりやすく
カプセル化は簡単に言うと、データを「カプセル」に入れて必要な部分だけを外に見せるという手法。データを直接外部からアクセスできる状態にしておくと、誤って変更されたり、悪意のある操作が行われたりするリスクがありるため、カプセル化してそのデータを他からいじれないようにする!というのが基本的な考え方です。
例えば、銀行口座の残高を誰でも自由に変更できたら、大変なことになりますよね。このとき、「銀行口座の残高」は外からみえないようにするというのが基本的な考え方。
ただし、銀行口座の残高を直接操作(「残高」が格納されている変数を直接値を変えたり読み込んだり)することはできなくても、必要に応じて残高を知ったり、残高を増減させる必要があるシーンは出てきます。このため、カプセル化したデータは専用のメソッド(データ参照用のメソッド&データ操作用のメソッド)を用いて取得できるようにする必要があります。
カプセル化の基本的な考え方
- データの隠蔽(外から見えなくする)
- データを直接外部からアクセスできないようにする。→データが誤って変更されるのを防ぎます。
- プログラムの中では、データをクラス内に隠して、外部から直接見えないようにします。
- メソッドを使ったデータアクセス
- データにアクセスするためには特別なメソッドを用意。→これらのメソッドを使うことで、データの読み取りや変更を行います。
- こうすることで、データの操作方法をコントロールでき、データの一貫性や安全性を保つことが可能に。
アクセス修飾子の使い方
アクセス修飾子は、カプセル化したい変数やメソッドに対してアクセスの範囲を制御するためのキーワードです。これを使うことで、どこからそのメンバーにアクセスできるかを決めることができます。
Javaには以下4種類のアクセス修飾子があります。
アクセス修飾子 | 内容 | アクセス範囲 |
---|---|---|
public | すべてのクラスからアクセス可能 | プロジェクト全体 |
protected | 同じパッケージおよびサブクラスからアクセス可能 | パッケージとサブクラス |
default (なし) | 同じパッケージ内でアクセス可能 | パッケージ内 |
private | 同じクラス内でのみアクセス可能 | クラス内 |
これらの修飾子を使うことで、クラスやメンバー(フィールドやメソッド)に対するアクセスの範囲を設定できます。以下、それぞれの修飾子の使い方と動作を具体例を交えて説明します。
public(パブリック)
public
を使うと、そのクラスやメンバーはプロジェクト内のどこからでもアクセス可能です。
public class Example { public int data; // パブリックフィールド public void display() { // パブリックメソッド System.out.println("Public Method"); } } public class Main { public static void main(String[] args) { Example obj = new Example(); obj.data = 10; // 直接アクセス可能 obj.display(); // 直接アクセス可能 } }
この例では、data
フィールドもdisplay
メソッドもpublic
なので、他のクラスから自由にアクセスすることができます。要はザックリいえば、どこからでも自由にアクセスしてOK!という場合に使うキーワードです。
protected(プロテクテッド)
protected
を使うと、同じパッケージ内とそのクラスを継承したサブクラスからアクセス可能です。
参考 クラスの「継承」とは?
public class SuperClass { protected void display() { System.out.println("Protected Method"); } } public class SubClass extends SuperClass { public static void main(String[] args) { SubClass obj = new SubClass(); obj.display(); // サブクラスからprotectedメソッドにアクセス可能 } }
が、別のパッケージにあるクラスからは、protected
メソッドにアクセスできません。
public class SuperClass { protected void display() { System.out.println("Protected Method"); } } public class Main { public static void main(String[] args) { SuperClass obj = new SuperClass(); obj.display(); // エラー:別のパッケージからアクセス不可 } }
default(デフォルト)
アクセス修飾子を指定しない場合、そのメンバーはデフォルトで同じパッケージ内からアクセス可能です。
class Example { int data; // デフォルトフィールド void display() { // デフォルトメソッド System.out.println("Default Method"); } } public class Main { public static void main(String[] args) { Example obj = new Example(); obj.data = 10; // 同じパッケージ内でアクセス可能 obj.display(); // 同じパッケージ内でアクセス可能 } }
が、別のパッケージにあるクラスからは、デフォルトのメンバーにアクセスできません。
package package1; class Example { int data; // デフォルトフィールド void display() { // デフォルトメソッド System.out.println("Default Method"); } } // 別パッケージのクラス package package2; import package1.Example; public class Main { public static void main(String[] args) { Example obj = new Example(); obj.data = 10; // エラー:別パッケージからアクセス不可 obj.display(); // エラー:別パッケージからアクセス不可 } }
private(プライベート)
private
を使うと、そのクラス内でのみアクセス可能です。つまり、他のクラスからは直接アクセスできません。
① アクセスできるパターン
public class Example { private int data; // プライベートフィールド public int getData() { // パブリックゲッターメソッド return data; } public void setData(int data) { // パブリックセッターメソッド this.data = data; } } public class Main { public static void main(String[] args) { Example obj = new Example(); obj.setData(10); // セッターメソッドでアクセス System.out.println(obj.getData()); // ゲッターメソッドでアクセス } }
② アクセスできないパターン
public class Example { private int data; // プライベートフィールド public int getData() { // パブリックゲッターメソッド return data; } public void setData(int data) { // パブリックセッターメソッド this.data = data; } } public class Main { public static void main(String[] args) { Example obj = new Example(); obj.data = 10; // エラー:直接アクセス不可 } }
特別なメソッドの使い方
カプセル化の考え方では、クラスの中のデータ(フィールド)を外部から直接操作できないように隠します。これにより、データが不正に変更されるのを防ぎます。例えば、クラス内にあるカプセル化されたデータは、クラスの外から直接触れません。その代わりに以下の特別なメソッドを使ってデータを操作します。
- ゲッター(getter): データを取得するためのメソッド
- セッター(setter): データを設定するためのメソッド
例として、Person
というクラスにname
とage
という2つのデータを持たせます。このデータをカプセル化し、ゲッターとセッターを作成します。
public class Person { // データを隠す(カプセル化) private String name; private int age; // ゲッターメソッド public String getName() { return name; // nameのデータを返す } public int getAge() { return age; // ageのデータを返す } // セッターメソッド public void setName(String name) { // 名前がnullや空文字でない場合に設定 if (name != null && !name.isEmpty()) { this.name = name; } } public void setAge(int age) { // 年齢が0以上の場合に設定 if (age >= 0) { this.age = age; } } }
この作成したPerson
クラスを使って、データを設定したり取得したりしてみましょう。
public class Main { public static void main(String[] args) { // Personオブジェクトを作成 Person person = new Person(); // セッターメソッドでデータを設定 person.setName("John"); person.setAge(30); // ゲッターメソッドでデータを取得 System.out.println("Name: " + person.getName()); // 出力: Name: John System.out.println("Age: " + person.getAge()); // 出力: Age: 30 } }
ゲッターとセッターを使うことで、データを安全に操作し、プログラムが正しく動作するように保つことができます。初心者の方でも、この基本的な仕組みを理解し、実践することで、より良いプログラムを作成できるようになります。