1. 序章

ゲッターとセッターは、カプセル化クラスの外部の変数の値を取得および更新する際に重要な役割を果たします。 セッターは変数の値を更新し、ゲッターは変数の値を読み取ります。

このチュートリアルでは、 getters / setters を使用しない場合の問題、その重要性、およびJavaで実装する際に避けるべき一般的な間違いについて説明します。

2. Javaでのゲッターとセッターのない生活

ある条件に基づいてオブジェクトの状態を変更したい場合の状況を考えてみてください。 セッターメソッドなしでそれをどのように達成できますか?

  • 変数をpublic、protected、またはdefaultとしてマークする
  • ドット(。)演算子を使用して値を変更する

これを行うことの結果を見てみましょう。

3. ゲッターとセッターなしで変数にアクセスする

まず、ゲッター/セッターなしでクラスの外部の変数にアクセスするには、それらをpublic、protected、またはdefaultとしてマークする必要があります。 したがって、データの制御が失われ、基本的なOOPの原則であるカプセル化が損なわれます。

第二に、誰でもクラスの外部から非プライベートフィールドを直接変更できるため、不変性を実現することはできません。

第三に、変数の変更に条件付きロジックを提供することはできません。 フィールドretirementAgeを持つクラスEmployeeがあるとしましょう。

public class Employee {
    public String name;
    public int retirementAge;

// Constructor, but no getter/setter
}

ここでは、クラスEmployeeの外部からのアクセスを有効にするためにフィールドをpublicに設定していることに注意してください。 次に、従業員のretirementAgeを変更する必要があります。

public class RetirementAgeModifier {

    private Employee employee = new Employee("John", 58);

    private void modifyRetirementAge(){
        employee.retirementAge=18;
    }
}

ここで、 Employee クラスのクライアントは、retirementAgeフィールドを使用して簡単にやりたいことができます。 変更を検証する方法はありません。

第4に、クラス外からフィールドへの読み取り専用または書き込み専用アクセスを実現するにはどうすればよいでしょうか。

あなたの救助のためにゲッターとセッターが来ます。

4. Javaにおけるゲッターとセッターの重要性

多くの中から、ゲッターとセッターを使用することの最も重要な利点のいくつかを取り上げましょう。

  • これは、クラス内の構造化データオブジェクトの状態を非表示にするために使用されるカプセル化を実現し、それらへの不正な直接アクセスを防ぐのに役立ちます。
  • フィールドをプライベートとして宣言し、ゲッターのみを使用することで不変性を実現します
  • ゲッターとセッターでは、検証やエラー処理など、将来さらに簡単に追加できる追加機能も使用できます。 したがって、条件付きロジックを追加して、ニーズに応じた動作を提供できます
  • フィールドへのさまざまなアクセスレベルを提供できます。 たとえば、get(読み取りアクセス)はパブリックであり、set(書き込みアクセス)は保護されている可能性があります
  • プロパティの値を正しく設定するための制御
  • ゲッターとセッターを使用して、OOPのもう1つの重要な原則、つまり、実装の詳細を非表示にして、他のクラスやモジュールでフィールドを直接使用できないようにする抽象化を実現します。

5. 間違いを避ける

以下は、ゲッターとセッターを実装する際に避けるべき最も一般的な間違いです。

5.1. パブリック変数でのゲッターとセッターの使用

パブリック変数には、ドット(。)演算子を使用してクラスの外部からアクセスできます。 パブリック変数にゲッターとセッターを使用する意味はありません。

public class Employee {
    public String name;
    public int retirementAge;

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    } 
    // getter/setter for retirementAge
}

この場合、ゲッターとセッターで実行できることはすべて、フィールドを単純に公開することによっても実行できます。

経験則として、カプセル化を実現する必要性に基づいて、常に最も制限されたアクセス修飾子を使用する必要があります。

5.2. セッターメソッドでオブジェクト参照を直接割り当てる

セッターメソッドでオブジェクト参照を直接割り当てる場合、これらの参照は両方ともメモリ内の単一のオブジェクトを指します。 したがって、参照変数のいずれかを使用して行われた変更は、実際には同じオブジェクトに対して行われます。

public void setEmployee(Employee employee) {
    this.employee = employee;
}

ただし、ディープコピーを使用して、あるオブジェクトから別のオブジェクトにすべての要素をコピーできます。 このため、 this オブジェクトの状態は、既存の(渡された)従業員オブジェクトから独立します。

public void setEmployee(Employee employee) {
    this.employee.setName(employee.getName());
    this.employee.setRetirementAge(employee.getRetirementAge());
}

5.3. Getterメソッドから直接オブジェクト参照を返す

同様に、getterメソッドがオブジェクトの参照を直接返す場合、誰でも外部コードからこの参照を使用して、オブジェクトの状態を変更できます。

public Employee getEmployee() {
    return this.employee;
}

this getEmployee()メソッドを使用して、 retirementAge:を変更してみましょう。

private void modifyAge() {
    Employee employeeTwo = getEmployee();
    employeeTwo.setRetirementAge(65);
}

これにより、元のオブジェクトが回復不能に失われます。

したがって、getterメソッドから参照を返す代わりに、オブジェクトのコピーを返す必要があります。 そのような方法の1つは次のとおりです。

public Employee getEmployee() {
    return new Employee(this.employee.getName(), this.employee.getRetirementAge());
}

ただし、ゲッターまたはセッター内でオブジェクトのコピーを作成することが常にベストプラクティスであるとは限らないことにも注意する必要があります。 たとえば、ループで上記のgetterメソッドを呼び出すと、コストのかかる操作になる可能性があります。

一方、コレクションを変更できないようにしたい場合は、ゲッターからコレクションのコピーを返すのが理にかなっています。 次に、特定の状況でどのアプローチが最適かを判断する必要があります。

5.4. 不要なゲッターとセッターの追加

ゲッターとセッターを使用することで、メンバー変数のアクセスと割り当てを制御できます。 しかし、多くの場所で、それは不要であることがわかります。 さらに、コードを冗長にします。

private String name;

public String getName() {
    return name;
}

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

クラス内のプライベートフィールドのパブリックゲッターとセッターを単純に定義することは、ゲッターとセッターなしでフィールドをパブリックにすることと同じです。 したがって、すべてのフィールドにアクセサメソッドを定義するかどうかを慎重に決定することを常にお勧めします。

6. 結論

このチュートリアルでは、Javaでゲッターとセッターを使用することの長所と短所について説明しました。 また、ゲッターとセッターを実装する際に避けるべきいくつかの一般的な間違いと、それらを適切に使用する方法についても説明しました。