Java「パブリック」アクセス修飾子

1. 概要

この簡単な記事では、_public_修飾子を詳細に説明し、クラスおよびメンバーでそれをいつどのように使用するかについて説明します。
さらに、パブリックデータフィールドを使用することの欠点についても説明します。
アクセス修飾子の一般的な概要については、https://www.baeldung.com/java-access-modifiers [Javaのアクセス修飾子]の記事をご覧ください。

2. パブリックアクセス修飾子を使用する場合

パブリックメンバーおよびパブリッククラスとインターフェイスは、APIを定義します。 他の人がオブジェクトの動作を制御するために表示および使用できるのは、コードのその部分です。
ただし、パブリック修飾子を使いすぎると、オブジェクト指向プログラミング(OOP)のカプセル化の原則に違反し、いくつかの欠点があります。
  • APIのサイズが大きくなり、クライアントが使用しにくくなります

  • クライアントがそれに依存しているため、コードを変更するのが難しくなっています—
    将来の変更はコードを壊す可能性があります

3. パブリックインターフェイスとクラス

3.1. パブリックインターフェイス

*パブリックインターフェイスは、1つまたは複数の実装を持つことができる仕様を定義します。*これらの実装は、当社が提供するか、他者が作成することができます。
たとえば、Java APIは_Connection_インターフェイスを公開してデータベース接続操作を定義し、実際の実装を各ベンダーに任せます。 実行時に、プロジェクトのセットアップに基づいて目的の接続を取得します。
Connection connection = DriverManager.getConnection(url);
_getConnection_メソッドは、テクノロジー固有の実装のインスタンスを返します。

3.2. パブリッククラス

クライアントがインスタンス化と静的参照によってメンバーを使用できるように、パブリッククラスを定義します。
assertEquals(0, new BigDecimal(0).intValue()); // instance member
assertEquals(2147483647, Integer.MAX_VALUE); // static member
さらに、オプションのlink:/java-abstract-class[_abstract_]修飾子を使用して、継承用のパブリッククラスを設計できます。 * _abstract_修飾子を使用している場合、クラスは、各サブクラスが実装する必要のある抽象メソッドに加えて、具体的な実装が使用できるフィールドと事前実装メソッドを含むスケルトンのようなものです。
たとえば、Javaコレクションフレームワークは、カスタマイズされたリストを作成するための基礎として_AbstractList_クラスを提供します。
public class ListOfThree<E> extends AbstractList<E> {

    @Override
    public E get(int index) {
        //custom implementation
    }

    @Override
    public int size() {
        //custom implementation
    }

}
したがって、_get()_メソッドと_size()_メソッドを実装するだけです。 _indexOf()_や_containsAll()_などの他のメソッドは既に実装されています。

3.3. 入れ子になったパブリッククラスとインターフェイス

パブリックなトップレベルのクラスとインターフェイスと同様に、ネストされたパブリックなクラスとインターフェイスはAPIデータ型を定義します。 ただし、これらは特に次の2つの点で役立ちます。
  • それらは、APIエンドユーザーに、最上位の型を囲むことを示します
    そしてその囲まれた型は論理的な関係を持ち、一緒に使用されます

  • ソースの数を減らすことでコードベースをよりコンパクトにします
    トップレベルのクラスとインターフェイスとして宣言した場合に使用したコードファイル

    例は、コアJava APIの_Map.Entry_インターフェイスです。
for (Map.Entry<String, String> entry : mapObject.entrySet()) { }
_Map.Entry a_ネストされたインターフェースを作成すると、_java.util.Map_インターフェースに強く関連付けられ、_java.util_パッケージ内に別のファイルを作成する必要がなくなりました。
詳細については、https://www.baeldung.com/java-nested-classes [nested classes]の記事をご覧ください。

4. パブリックメソッド

パブリックメソッドを使用すると、ユーザーは既製の操作を実行できます。 例は、_String_ APIのpublic _toLowerCase_メソッドです。
assertEquals("alex", "ALEX".toLowerCase());
インスタンスフィールドを使用しない場合、パブリックメソッドを静的に安全に作成できます。 _Integer_クラスの_parseInt_メソッドは、パブリック静的メソッドの例です。
assertEquals(1, Integer.parseInt("1"));
コンストラクタは通常パブリックなので、オブジェクトをインスタンス化して初期化できますが、https://www.baeldung.com/java-singleton [singletons]のようにプライベートな場合もあります。

5. パブリックフィールド

パブリックフィールドを使用すると、オブジェクトの状態を直接変更できます。 *経験則では、パブリックフィールドを使用すべきではありません。*これには、これから説明するいくつかの理由があります。

5.1. スレッドセーフ

非最終フィールドまたは最終可変フィールドでパブリック可視性を使用することは、スレッドセーフではありません。 異なるスレッドでの参照または状態の変更を制御することはできません。
スレッドセーフコードの記述の詳細については、https://www.baeldung.com/java-thread-safety [thread-safety]の記事をご覧ください。

5.2. 変更に対するアクションの実行

参照または状態は直接設定できるため、非最終パブリックフィールドを制御することはできません。
代わりに、プライベート修飾子を使用してフィールドを非表示にし、パブリックセッターを使用することをお勧めします。
public class Student {

    private int age;

    public void setAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException();
        }

        this.age = age;
    }
}

5.3. データ型の変更

パブリックフィールドは、可変または不変であり、クライアントの契約の一部です。 クライアントは実装をリファクタリングする必要がある可能性があるため、これらのフィールドのデータ表現を将来のリリースで変更することは困難です。
フィールドにプライベートスコープを与え、アクセサーを使用することで、古いデータ型も維持しながら、内部表現を変更できる柔軟性があります。
public class Student {

    private StudentGrade grade; //new data representation

    public void setGrade(int grade) {
        this.grade = new StudentGrade(grade);
    }

    public int getGrade() {
        return this.grade.getGrade().intValue();
    }
}
パブリックフィールドを使用する場合の唯一の例外は、定数を表す静的な最終不変フィールドの使用です。
public static final String SLASH = "/";

6. 結論

このチュートリアルでは、パブリック修飾子がAPIの定義に使用されることを確認しました。
また、この修飾子を過度に使用すると、実装に改善を導入する能力が制限される可能性があることを説明しました。
最後に、フィールドにパブリック修飾子を使用することが悪い習慣である理由について説明しました。
そして、いつものように、この記事のコードサンプルはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-lang-oop-3[GitHubで]から入手できます。