本ページはプロモーションが含まれています

Java入門

Javaアクセス修飾子4つの違いと使い分けを完全解説

Javaアクセス修飾子4つの違いと使い分けを完全解説

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

Javaのアクセス修飾子は、クラスやフィールド、メソッドを「どこから使えるか」を決めるキーワードです。public・protected・default(修飾子なし)・privateの4種類があります。

迷ったときは、狭いほうから選ぶのが基本です。フィールドはprivateにし、外から呼ばせたいメソッドだけpublicにします。protectedとdefaultは、継承先や同じパッケージの中だけで使わせたい場面に絞って使います。

私も学び始めのころは、publicやprivateを意味を考えずに「おまじない」のように書いていました。この記事では、4種類の違いをアクセス範囲の表とコード例で確かめ、実務でよくある選び方の失敗まで説明します。

アクセス修飾子とは?Javaにおける基本概念を理解しよう

Javaのアクセス修飾子とは何かを示す基本概念の図解

Javaにおけるアクセス修飾子とは、クラスやフィールド、メソッドへのアクセスをどこから許可するかを制御するためのキーワードです。

文字通り、アクセスを「修飾」し、制限をかける役割を持っています。

アクセス修飾子の役割と必要性

アクセス修飾子の最も重要な役割は、プログラムの安全性を高めることです。

もし、どこからでも自由にクラスの内部データにアクセスできてしまうと、意図しない場所で値が書き換えられ、予期せぬバグやエラーの原因になります。

たとえば、銀行口座の残高を管理するプログラムを考えてみましょう。残高という重要なデータを誰でも直接変更できたら、システムは成り立ちません。

「入金」や「出金」といった決められた手続き(メソッド)を通してのみ操作できるように制限する必要があります。

アクセス修飾子は、外部から勝手に触られたくない重要なデータを守り、決められたルールで安全にプログラムを動かすための仕組みなのです。

Javaのアクセス修飾子一覧(4種類)

Javaには、アクセスの制限範囲が異なる4種類のアクセス修飾子が存在します。

ポイント

  1. public (パブリック)
  2. protected (プロテクテッド)
  3. default (デフォルト) ※キーワードの記述は不要
  4. private (プライベート)

これらのアクセス修飾子は、制限が緩いものから厳しいものへと段階的に設定されており、状況に応じて使い分けることが重要です。

カプセル化とアクセス修飾子の関係

カプセル化は、オブジェクト指向プログラミングにおける重要な概念の一つです。

これは、クラスの内部データ(フィールド)と、そのデータを操作する手続き(メソッド)を一つにまとめ、内部の詳細を外部から隠蔽する考え方を指します。

このカプセル化を実現するために、アクセス修飾子が活躍します。具体的には、フィールドをprivateにして外部から直接アクセスできないように隠蔽します。

そのうえで、そのフィールドを操作するためのpublicなメソッド(ゲッターやセッター)を公開します。

これにより、クラスの利用者は内部構造を意識することなく、公開されたメソッドを通じて安全にデータを操作できます。

カプセル化は、プログラムの独立性を高め、仕様変更に強い、保守性の高いコードを作成するための基本原則です。

あわせて読む
アクセス修飾子ごとの公開範囲
同じクラス
同じパッケージ
サブクラス
どこからでも
private
○
×
×
×
(default)
○
○
×
×
protected
○
○
○
×
public
○
○
○
○
上から下へ行くほど公開範囲が広い。基本は「必要最小限」から選ぶ。

Javaのアクセス修飾子の種類と違い

Javaの4種類のアクセス修飾子とそれぞれの違いを示す図解

ここでは、4種類のアクセス修飾子が持つアクセス制限の範囲と、それぞれの違いについて詳しく見ていきましょう。

修飾子同一クラス内同一パッケージ内サブクラス(別パッケージ)どこからでも
public○○○○
protected○○○×
default○○××
private○×××

public(パブリック)|どこからでもアクセス可能

publicは、最もアクセス制限が緩い修飾子です。

publicが付けられたクラス、フィールド、メソッドは、プロジェクト内のどのクラスからでもアクセスできます(モジュール(module-info.java)を使う場合は、そのパッケージがexportsされている必要があります)。

ライブラリとして提供されるクラスや、プログラムの主要なエントリーポイントとなるメソッドなど、外部に公開して自由に使ってもらいたい機能に対して使用します。

APIとして機能する部分と考えると分かりやすいでしょう。

protected|継承先からアクセス可能

protectedは少し特殊なアクセス修飾子です。

同一パッケージ内のクラス、または別パッケージであってもそのクラスを継承したサブクラスからアクセスが可能です。ただし、別パッケージのサブクラスからアクセスできるのは、サブクラス自身(thisやサブクラス型の変数)を通した場合に限られます。親クラス型の変数(例: Animal a = new Animal(); a.protectedSound)を通したアクセスはコンパイルエラーになります。

この特性から、主に継承関係にあるクラス間で、特定の情報や機能を共有したい場合に使われます。

フレームワークやライブラリなどで、拡張性を考慮した設計を行う際によく見られます。

あわせて読む

default|同一パッケージのみアクセス可能

defaultは、クラスのフィールドやメソッドなどでアクセス修飾子を何も記述しなかった場合に適用されるアクセスレベルです。ただし、インターフェースのメンバーは何も書かなくても暗黙的にpublicになります。

package-private(パッケージプライベート)とも呼ばれます。

defaultのメンバーは、同じパッケージに所属するクラスからのみアクセス可能です。

パッケージというまとまりの中でだけ利用される補助的なクラスや、内部的な処理で利用するメソッドなどに適しています。

パッケージの外に公開する必要はないが、パッケージ内では共有したい、という場面で有効です。

private(プライベート)|クラス内のみアクセス可能

privateは、最もアクセス制限が厳しい修飾子です。

privateが付けられたメンバーは、そのメンバーが定義されているクラスの内部からしかアクセスできません。

クラスの外部に公開する必要のない、内部的な状態を保持するフィールドや、そのクラス内だけで使われる補助的なメソッドに使用します。

前述したカプセル化の原則に従い、フィールドは原則としてprivateにするのがJavaプログラミングの基本です。

これにより、クラスの安全性が大幅に向上します。

アクセス修飾子の使い分け方と実例

Javaでアクセス修飾子を使い分ける実例を示す図解

理論を学んだところで、次に実際のプログラミングでどのようにアクセス修飾子を使い分ければよいのか、具体的な例を挙げて解説します。

クラスとメソッドでのアクセス修飾子の使い方

トップレベルのクラスに付けられるアクセス修飾子はpublicかdefaultの2種類です(privateやprotectedを付けるとコンパイルエラーになります)。なお、クラスの中に定義する内部クラス(ネストしたクラス)には、メンバーとして4種類すべてを付けられます。

  • publicクラス: パッケージの外部に公開し、誰でも利用できるようにしたいクラスに使います。ほとんどの主要なクラスはpublicで定義されます。
  • defaultクラス: 同じパッケージ内でのみ利用される、補助的なクラスに使います。そのパッケージの機能を実装するための「部品」のようなイメージです。

メソッドのアクセス修飾子は、そのメソッドの役割によって決まります。

  • publicメソッド: 外部に公開する操作(API)です。例えば、オブジェクトの状態を取得するゲッターや、状態を設定するセッターなどが該当します。
  • privateメソッド: クラス内部の複雑な処理を分割するためのヘルパーメソッドなど、外部に公開する必要がない処理に使われます。リファクタリングの際に、長大なpublicメソッドを複数のprivateメソッドに分割することはよくあります。

フィールドへの修飾子の付け方の注意点

繰り返しになりますが、フィールド(インスタンス変数)には原則としてprivate修飾子を付けます。これは、カプセル化(情報隠蔽)の原則を守るためです。

もしフィールドをpublicにしてしまうと、どこからでも値を直接書き換えられるようになり、オブジェクトの状態が予期せぬ形で変更されてしまう危険性があります。

値の取得や設定が必要な場合は、publicなゲッターメソッドやセッターメソッドを用意しましょう。

セッターメソッド内で値の妥当性チェック(例えば、年齢に負の値が設定されないようにするなど)を実装することで、オブジェクトの状態を常に正しく保てます。

コンストラクタのアクセス修飾子

コンストラクタにもアクセス修飾子を付けられます。

通常はpublicにして外部から自由にインスタンス化できるようにしますが、privateにすると外部からのnewを禁止できます。

この特性は、インスタンスを1つだけに制限する「シングルトンパターン」を実現する手段の1つとして使われます。

コンストラクタをprivateにし、代わりにクラス内のstaticメソッドを通してインスタンスを取得させることで、外部からの無秩序なインスタンス生成を防げます。

アクセス修飾子を使い分けるときの判断基準

どのアクセス修飾子を選べばよいか迷ったときは、「可能な限りアクセス範囲を狭くする」という原則に立ち返りましょう。これを最小権限の原則と呼びます。

  1. 最初にprivateで定義できないか検討する。
  2. 同一パッケージ内の他クラスからのアクセスが必要な場合はdefaultにする。
  3. 継承したサブクラスに公開する必要がある場合はprotectedにする。
  4. 上記以外で、どうしても外部に公開する必要がある場合にのみpublicを選択する。

この思考プロセスを習慣づけることで、自然と堅牢で安全なクラス設計ができるようになります。

アクセス修飾子を理解するためのコード例

Javaのアクセス修飾子を使ったコード例を示す図解

ここでは、具体的なコードを見ながらアクセス修飾子の動作を確認していきましょう。

public/privateの組み合わせ例

ゲッター/セッターは、publicとprivateの役割を理解するための最も典型的な例です。

java
public class User {
    // フィールドはprivateで外部から隠蔽する
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        // セッターを経由して初期値を設定する
        this.setAge(age);
    }

    // publicなゲッターで値を取得する
    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    // publicなセッターで値を設定する
    // 不正な値が設定されないようにチェックできる
    public void setAge(int age) {
        if (age >= 0) {
            this.age = age;
        } else {
            System.out.println("年齢に負の値は設定できません。");
        }
    }
}

このコードでは、nameとageフィールドをprivateにすることで、直接のアクセスを防いでいます。

年齢ageに負の値のような不正なデータがセットされないよう、setAgeメソッド内でチェック処理を入れている点がポイントです。

protected/defaultの比較例

protectedとdefaultの違いは、パッケージをまたいだ継承関係で顕著になります。

パッケージ1: com.example.animal

java
package com.example.animal;

public class Animal {
    // 同一パッケージとサブクラスからアクセス可能
    protected String protectedSound = "鳴き声";
    
    // 同一パッケージからのみアクセス可能
    String defaultName = "動物";

    public void cry() {
        System.out.println(this.protectedSound);
    }
}

パッケージ2: com.example.main

java
package com.example.main;

import com.example.animal.Animal;

// Animalを継承したサブクラス
public class Dog extends Animal {
    public void accessTest() {
        // protectedメンバーには別パッケージのサブクラスからアクセスできる
        System.out.println(this.protectedSound); // OK

        // defaultメンバーには別パッケージからはアクセスできない
        // System.out.println(this.defaultName); // コンパイルエラー!
    }
}

DogクラスはAnimalクラスを継承しています。

別パッケージにありますが、サブクラスなのでprotectedなprotectedSoundフィールドにアクセスできます。

一方、defaultのdefaultNameフィールドにはアクセスできず、コンパイルエラーが発生します。

アクセス制限エラーの原因と対処法

Javaでプログラミングをしていると、以下のようなコンパイルエラーに遭遇することがあります。

The field [フィールド名] is not visible(Eclipseの表示)

[メンバー名] has private access in [クラス名](javacの表示。defaultのメンバーに別パッケージからアクセスした場合は「[メンバー名] is not public in [クラス名]; cannot be accessed from outside package」、protectedのメンバーに別パッケージの無関係なクラスからアクセスした場合は「[メンバー名] has protected access in [クラス名]」と表示されます)

これらのエラーは、アクセスが許可されていないメンバー(フィールドやメソッド)にアクセスしようとしたときに発生します。

原因:

アクセスしようとしているメンバーのアクセス修飾子によって、アクセスが制限されている。

対処法:

  1. 設計を見直す: なぜそのメンバーにアクセスする必要があるのかを考えます。privateなメンバーに直接アクセスしようとしている場合、それはクラスの設計思想に反している可能性があります。代わりに用意されているpublicなメソッドを使うべきではないか検討しましょう。
  2. アクセス修飾子を変更する: 設計上、どうしてもアクセスが必要な場合は、アクセス修飾子をより緩いもの(例: private -> defaultやpublic)に変更します。ただし、これは安易に行うべきではなく、なぜそのアクセスレベルが必要なのかを明確に説明できる場合に限ります。
あわせて読む

アクセス修飾子を正しく使うためのベストプラクティス

Javaでアクセス修飾子を正しく使うためのベストプラクティスを示す図解

最後に、アクセス修飾子を効果的に活用し、より質の高いコードを書くためのベストプラクティスを紹介します。

最小限のアクセス権にする原則(情報隠蔽の重要性)

繰り返し強調しますが、常に最小限のアクセス権を付与することを心がけてください。

これは「情報隠蔽」や「最小権限の原則」として知られる、オブジェクト指向設計の基本中の基本です。

  • 変更の影響範囲を限定できる: 内部実装をprivateで隠蔽しておけば、将来その実装方法を変更しても、クラスの外部(利用者側)に影響が及びません。
  • クラスの利用者が迷わない: publicなメソッドだけを見れば、そのクラスの使い方が分かります。内部の複雑な実装を気にする必要がなくなり、利用しやすさが向上します。
  • バグの混入を防ぐ: 意図しない使われ方を防ぎ、オブジェクトの状態を健全に保つことで、デバッグが容易で安定したプログラムになります。

チーム開発でのアクセス修飾子の設計ルール

チームで開発を行う場合、アクセス修飾子の使い方は、個人の裁量だけでなく、チームとしてのコーディング規約で定めることが望ましいです。

  • APIとして公開する範囲を明確にする: どのクラスやメソッドをpublicにするか(つまり、チーム内の他のメンバーが使ってよい機能か)を設計段階で合意します。
  • パッケージの設計: 関連性の高いクラスを同じパッケージにまとめ、defaultアクセス修飾子を有効に活用することで、パッケージ内での連携を密にしつつ、パッケージ外への不要な情報流出を防げます。

明確なルールを設けることで、コードの意図が伝わりやすくなり、開発効率とメンテナンス性が向上します。

よくある誤用パターンとその修正例

誤用パターン1: とりあえず全部publicにしてしまう

初心者によく見られるパターンです。

アクセスエラーが出るたびにpublicに変更していくと、最終的にすべてのメンバーがpublicになってしまい、カプセル化が完全に崩壊します。

  • 修正例: フィールドは原則としてprivateにします。メソッドもまずはprivateで考え、外部に公開する必要があるものだけをpublicに変更していく、という手順を踏みましょう。

実際に、銀行口座系のドメインでpublicフィールドを使っていたコードを引き継いだことがあります。

すると、別チームのメンバーが残高フィールドを直接書き換えるコードを書いていました。

フィールドをprivateにしてゲッター・セッターに統一したところ、同種のバグは0件になりました。

冒頭で触れた「銀行口座の残高」という例は、決して大げさな仮定ではありません。

誤用パターン2: protectedの乱用

継承が便利だからといって、安易にprotectedを使うべきではありません。

protectedはクラス間の結合度を強め、サブクラスが親クラスの実装に強く依存してしまう原因になります。

  • 修正例: 継承は強力ですが、結合度が高い諸刃の剣です。本当に継承が必要な設計なのか、委譲(コンポジション)で代替できないかを検討しましょう。protectedは、フレームワークのように拡張を前提とした設計など、明確な意図がある場合に限定して使用するのが賢明です。

finalとの組み合わせで継承・変更を禁止する

アクセス修飾子は、finalと組み合わせて使われることもよくあります。finalはアクセス範囲ではなく「変更・拡張の可否」を制御する修飾子です。

例えばpublic finalクラスにすると、「誰からでもアクセスできるが、継承はできない」クラスになります。

protected finalメソッドであれば、「サブクラスからアクセスはできるが、オーバーライドはできない」メソッドになります。

アクセス範囲と変更可否を別々にコントロールしたい場合に活用しましょう。

よくある質問

Q1. Javaのアクセス修飾子は何種類ありますか?

A1. public・protected・default・privateの4種類です。この順にアクセス制限が緩いものから厳しいものへと段階的に設定されています。

Q2. アクセス修飾子を何も書かない場合はどうなりますか?

A2. defaultアクセスレベル(package-private)になります。同じパッケージに所属するクラスからのみアクセス可能です。ただし、インターフェースのメンバーは暗黙的にpublicになります。

Q3. protectedとdefaultの違いは何ですか?

A3. どちらも同一パッケージ内からアクセス可能ですが、protectedは別パッケージであってもそのクラスを継承したサブクラスからアクセスできます(サブクラス自身を通したアクセスに限ります)。defaultは別パッケージからは一切アクセスできません。

Q4. フィールドにはどのアクセス修飾子を使うべきですか?

A4. 原則としてprivateにします。カプセル化の原則に従い、外部から直接アクセスできないように隠蔽し、必要な場合はpublicなゲッター・セッターを用意します。

Q5. アクセス修飾子を選ぶときの判断基準は何ですか?

A5. 「可能な限りアクセス範囲を狭くする」という最小権限の原則に従います。まずprivateで定義できないか検討し、必要に応じてdefault、protected、publicへと段階的に範囲を広げます。

Q6. コンストラクタをprivateにするとどうなりますか?

A6. クラス外部から直接newできなくなります。インスタンスを1つに制限するシングルトンパターンなど、生成方法を制御したい設計で使われます。

まとめ|アクセス修飾子を理解して安全なコードを書く

最後に、重要なポイントをまとめます。

4つのアクセス修飾子の使い分けを再確認

  • public: 誰でもアクセスOK。外部に公開するAPI。
  • protected: パッケージ内 + 別パッケージのサブクラス。継承が前提。
  • default: パッケージ内のみ。パッケージの部品。
  • private: クラス内のみ。クラスの内部実装。原則これを使う。

迷ったときは、最も厳しいprivateから検討し、必要に応じて少しずつアクセス範囲を広げていくのが鉄則です。

アクセス修飾子を意識することが設計力の第一歩

アクセス修飾子を適切に使い分けることは、単なる文法ルールの話ではありません。

それは、クラスの責務を考え、いかにして安全で変更に強い部品を作るかという、ソフトウェア設計そのものに深く関わっています。

「この情報はどこまで見せるべきか?」と常に自問自答する習慣が、あなたのコードを一段上のレベルへと引き上げてくれるでしょう。

ぜひ、今日からのコーディングで意識してみてください。

REVISIONS / 改訂履歴
REV.DATE内容
32026-10-04記載内容の事実確認と修正
22026-09-042026年9月時点の情報で全体を見直し
12025-10-26初版
  • この記事を書いた人
  • 最新記事

トム

SESで約8年、環境を変えられないもどかしさの中にいました。32歳で自社開発企業に転職し、今はClaude Codeと自動化で、仕事も時間も組み直している途中です。
・Javaバックエンドエンジニア(Java歴12年以上)
・資格:基本情報技術者/応用情報技術者/Java Silver/Python3エンジニア認定基礎
詳細なプロフィール

-Java入門