この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:guest
更新日時:2026-06-11 07:12:00

タイトル: アクセス修飾子
SEOタイトル: アクセス修飾子完全ガイド — public/private/protected

この記事の要点
  • アクセス修飾子は クラス・メソッド・フィールドの公開範囲を制御する
  • Java: public / protected / package-private (デフォルト) / private の 4 段階
  • C# は internal (同アセンブリ内) も持つ
  • 原則: 最小公開 — フィールドは private、外部 API は最小限の public
  • Python は規約ベース (_protected, __private)、本当の隠蔽はできない

Java のアクセス修飾子

修飾子同一クラス同一パッケージ子クラス (他パッケージ)他パッケージ
public
protected
package-private (なし)
private
package com.example.app;

public class User {
    public  String name;          // どこからでも見える
    protected int age;            // 同パッケージ + 子クラス
    String email;                 // package-private (同パッケージのみ)
    private String password;      // クラス内のみ

    public void publicMethod()        { }
    protected void hookForSubclass()  { }
    void packageMethod()              { }   // package-private
    private void internalLogic()      { }
}

クラスへの適用

クラス宣言は public または package-private のみ (トップレベルクラス):

// ファイル User.java
public class User { }       // public — どこからでも参照可
class UserHelper { }        // package-private — 同パッケージのみ
// private class X { }      // ★ トップレベルでは NG (内部クラスでは可)

// 内部クラスはどの修飾子も使える
public class Outer {
    public  class A { }
    protected class B { }
    class C { }
    private class D { }    // 外から参照不可
}

フィールドのカプセル化

// ❌ public フィールドは外部から自由に書き換え可能 → 不変条件を破られる
public class BadUser {
    public int age;   // age = -100 等の不正値を防げない
}

// ✅ private + getter/setter
public class User {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("age out of range");
        }
        this.age = age;
    }
}

// 完全に書き換えさせたくない場合は setter 削除 + final
public class ImmutableUser {
    private final String name;
    private final int age;

    public ImmutableUser(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge()     { return age; }
}

protected の使いどころ

// テンプレートメソッドパターン — フックを protected で公開
public abstract class Report {
    public final void render() {
        printHeader();
        printBody();    // ★ 子に必ず実装させる
        printFooter();
    }

    protected void printHeader() { System.out.println(&quot;===HEADER===&quot;); }
    protected abstract void printBody();
    protected void printFooter() { System.out.println(&quot;===FOOTER===&quot;); }
}

class SalesReport extends Report {
    @Override
    protected void printBody() {
        System.out.println(&quot;Sales: 1000&quot;);
    }
}

JavaBeans 規約

Java のフレームワーク (Spring / Jackson / JSP EL) が認識する標準パターン:

  • 引数なし public コンストラクタ
  • フィールドは private
  • アクセサ getXxx() / setXxx(value)public
  • boolean は isXxx() でも OK
public class User {
    private String name;
    private boolean active;

    public User() {}

    public String getName()              { return name; }
    public void   setName(String name)   { this.name = name; }

    public boolean isActive()            { return active; }
    public void    setActive(boolean a)  { this.active = a; }
}

テスト時の private 問題

public class Calculator {
    private int internalState = 0;
    private int compute(int x) { return x * 2; }
}

// ★ 直接テストできない (private)
// 解決策:
// 1. ロジックを抽出して別クラスに (推奨)
// 2. アクセス修飾子を package-private に緩和 + テストを同パッケージへ
// 3. Reflection でアクセス (最終手段)

import java.lang.reflect.Method;
import java.lang.reflect.Field;

@Test
void test() throws Exception {
    Calculator c = new Calculator();

    // private メソッド呼び出し
    Method m = Calculator.class.getDeclaredMethod(&quot;compute&quot;, int.class);
    m.setAccessible(true);
    int r = (int) m.invoke(c, 5);
    assertEquals(10, r);

    // private フィールドアクセス
    Field f = Calculator.class.getDeclaredField(&quot;internalState&quot;);
    f.setAccessible(true);
    f.set(c, 42);
}

言語別比較

言語修飾子備考
Javapublic / protected / (なし) / private4 段階
PHPpublic / protected / privateJava 同等 (パッケージ概念なし)
C#public / protected / internal / protected internal / private / private protected★ 6 段階
Python慣習: _x / __x★ 言語レベルの強制なし
JavaScript慣習 → ES2022 #field で真の privateクラスフィールドの prefix で隠蔽
Kotlinpublic / internal / protected / privateinternal は同モジュール
class User {
    public  string $name;
    protected int $age;
    private  string $password;

    public function getName(): string    { return $this->name; }
    private function hashPassword(): string { ... }
}
class User:
    def __init__(self, name, password):
        self.name = name           # public 扱い
        self._internal = 0         # protected 慣習 (アンダースコア 1 つ)
        self.__password = password # private 慣習 (アンダースコア 2 つ → name mangling)

u = User(&quot;Taro&quot;, &quot;secret&quot;)
print(u.name)        # OK
print(u._internal)   # ★ 警告なくアクセス可 (慣習違反)
print(u.__password)  # ★ AttributeError
print(u._User__password)  # ★ name mangling で実は読める (完全な隠蔽ではない)
public class User {
    public  string Name { get; set; }
    protected int Age;
    internal string SessionId;            // 同アセンブリのみ
    protected internal string Region;     // 同アセンブリ or 子クラス
    private string password;
    private protected string secret;      // 同アセンブリ かつ 子クラス
}

JavaScript ES2022 真の private フィールド

class User {
    #password;          // ★ # は真の private

    constructor(name, password) {
        this.name = name;
        this.#password = password;
    }

    checkPassword(input) {
        return this.#password === input;
    }
}

const u = new User(&quot;Taro&quot;, &quot;abc&quot;);
console.log(u.name);        // OK
console.log(u.#password);   // ★ SyntaxError (構文レベルで弾かれる)

設計指針

  • 原則: 最小公開。必要になったら緩和、最初は private に
  • フィールドは原則 private。可視化が必要なら getter/setter または record
  • API は public、内部実装は private/package-private
  • 継承想定のフックは protected で公開
  • 同パッケージ専用ヘルパーは package-private
  • テストはプロダクションコードと同じパッケージに置くことで package-private にもアクセス可

FAQ

Q: Java で「同じプロジェクト内なら見える」修飾子は?
A: 存在しない。internal は C# / Kotlin の機能。Java はパッケージ単位 (package-private) でしか共有できない。

Q: private メソッドはオーバーライドできる?
A: できない (子クラスから見えないため)。同名メソッドを子で書くことは可能だが、オーバーライドではなく別物 (隠蔽でもない)。

Q: public final フィールドは安全?
A: 基本型や不変オブジェクトなら OK (例: public static final int MAX = 100)。可変オブジェクトでは中身を変更されるので避ける。