オブジェクト指向プログラミングで頻出する単語に「カプセル化」があります。ソースコードをその名の通り「カプセル」に入れるイメージで外部からデータを保護することを指す用語です。
Javaではカプセル化を実現するためにアクセス修飾子というものを使用します。アクセス修飾子とは、クラスのメンバー(フィールドやメソッド)に対するアクセスの範囲を制限するキーワードで、主なアクセス修飾子には、public
、protected
、default
(修飾子なし)、private
の4種類あります。
アクセス修飾子 | 内容 | アクセス範囲 |
---|---|---|
public | すべてのクラスからアクセス可能 | プロジェクト全体 |
protected | 同じパッケージおよびサブクラスからアクセス可能 | パッケージとサブクラス |
default (なし) | 同じパッケージ内でアクセス可能 | パッケージ内 |
private | 同じクラス内でのみアクセス可能 | クラス内 |

このページでは、アクセス修飾子を理解するために必要となるカプセル化の概念から説明し、Javaにおけるpublic/protected/privateなどのアクセス修飾子の基本を1からわかりやすく解説します。
前提:カプセル化とは?わかりやすく
カプセル化とは、簡単に言うとデータやメソッドを「カプセル」に入れて必要な部分だけを外に見せるという手法。データを直接外部からアクセスできる状態にしておくと、誤って変更されたり、悪意のある操作が行われたりするリスクがありうるため、カプセル化してそのデータを他からいじれないようにする!というのが基本的な考え方です。

例えば、銀行口座の残高を誰でも自由に変更できたら、大変なことになりますよね。このとき、「銀行口座の残高」は外からみえない(=操作できない)ようにするというのが基本的な考え方。
ただし、銀行口座の残高を直接操作することはできなくても、必要に応じて残高を知ったり、残高を増減させる必要があるシーンは出てきます。このため、カプセル化したデータは専用のメソッド(データ参照用のメソッド&データ操作用のメソッド)を用いて取得できるようにする必要があります。
カプセル化の基本的な考え方
- データの隠蔽(外から見えなくする)
- データを直接外部からアクセスできないようにする。→データが誤って変更されるのを防ぐ。
- プログラムの中では、データをクラス内に隠して、外部から直接見えないようにする。
- メソッドを使ったデータアクセス
- データにアクセスするためには特別なメソッドを用意。→これらのメソッドを使うことで、データの読み取りや変更を行います。
- こうすることで、データの操作方法をコントロールでき、データの一貫性や安全性を保つことが可能に。
Java:アクセス修飾子の使い方
アクセス修飾子は、カプセル化したい変数やメソッドに対してアクセスの範囲を制御するためのキーワードです。これを使うことで、どこからそのメンバーにアクセスできるかを決めることができます。

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 } }
ゲッターとセッターを使うことで、データを安全に操作し、プログラムが正しく動作するように保つことができます。初心者の方でも、この基本的な仕組みを理解し、実践することで、より良いプログラムを作成できるようになります。