1. 概要

この簡単な記事では、 public 修飾子について詳しく説明し、クラスやメンバーでいつどのように使用するかについて説明します。

さらに、パブリックデータフィールドを使用することの欠点についても説明します。

アクセス修飾子の一般的な概要については、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

さらに、オプションの 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エンドユーザーに、囲んでいる最上位の型とその囲まれている型が論理的な関係にあり、一緒に使用されることを示します。
  • これらは、トップレベルのクラスおよびインターフェイスとして宣言した場合に使用するソースコードファイルの数を減らすことで、コードベースをよりコンパクトにします。

例として、コアJavaAPIのMapEntryインターフェースがあります。

for (Map.Entry<String, String> entry : mapObject.entrySet()) { }

MapEntry a ネストされたインターフェースを作成すると、 java.util.Map インターフェースと強く関連し、別のファイルを作成する必要がなくなります。 java.utilパッケージ内。

詳細については、ネストされたクラスの記事をお読みください。

4. パブリックメソッド

パブリックメソッドを使用すると、ユーザーは既成の操作を実行できます。 例として、 StringAPIのパブリックtoLowerCaseメソッドがあります。

assertEquals("alex", "ALEX".toLowerCase());

インスタンスフィールドを使用しない場合は、パブリックメソッドを安全に静的にすることができます。 IntegerクラスのparseIntメソッドは、パブリック静的メソッドの例です。

assertEquals(1, Integer.parseInt("1"));

コンストラクターは通常パブリックであるため、オブジェクトをインスタンス化して初期化できますが、シングルトンのようにプライベートな場合もあります。

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

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

5.1. スレッドセーフ

非最終フィールドまたは最終可変フィールドでパブリックビジビリティを使用することは、スレッドセーフではありません。 異なるスレッドでの参照または状態の変更を制御することはできません。

スレッドセーフコードの記述について詳しくは、スレッドセーフに関する記事を確認してください。

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を定義していることを確認しました。

また、この修飾子を使いすぎると、実装に改善を導入する機能が制限される可能性があることも説明しました。

最後に、フィールドにパブリック修飾子を使用することがなぜ悪い習慣であるかについて説明しました。

そして、いつものように、この記事のコードサンプルはGitHubから入手できます。