Javaのマーカーインターフェイス

1. 前書き

このクイックチュートリアルでは、Javaのマーカーインターフェイスについて学習します。

2. マーカーインターフェイス

マーカーインターフェイスは、https://www.baeldung.com/java-interfaces [インターフェイス]であり、*その中にメソッドや定数はありません*。 *オブジェクトに関する*実行時の型情報*を提供するため、コンパイラとJVMは*オブジェクトに関する追加情報を持っています*。
マーカーインターフェイスは、タグ付けインターフェイスとも呼ばれます。
マーカーインターフェイスはまだ使用されていますが、コードの匂いを指している可能性が高いため、慎重に使用する必要があります。 これの主な理由は、マーカーは動作を定義しないため、インターフェイスが表すものに関する線を曖昧にすることです。 新しい開発では、同じ問題のいくつかを解決するために注釈が好まれています。

[[jdk examples]]
=== 3. JDKマーカーインターフェイス

Javaには、_Serializable _、_ Cloneable_、および_Remote._など、多くの組み込みマーカーインターフェイスがあります。
link:/java-deep-copy[_Cloneable_ interface]の例を見てみましょう。 このインターフェイスを実装していないオブジェクトを複製しようとすると、JVMは_CloneNotSupportedException_をスローします。 したがって、_Cloneable_ * markerインターフェイスは、_Object.clone()_メソッドを呼び出すことができることを示すJVM *のインジケータです。
同様に、_ObjectOutputStream.writeObject()_メソッドを呼び出すときに、* JVMはオブジェクトが__Serializable __markerインターフェイスを実装しているかどうかをチェックします*。 そうでない場合は、_NotSerializableException_がスローされます。 したがって、オブジェクトは出力ストリームにシリアル化されません。

4. カスタムマーカーインターフェイス

独自のマーカーインターフェイスを作成しましょう。
たとえば、データベースからオブジェクトを削除できるかどうかを示すマーカーを作成できます。
public interface Deletable {
}
データベースからエンティティを削除するには、このエンティティを表すオブジェクトが__Deletable __markerインターフェイスを実装する必要があります。
public class Entity implements Deletable {
    // implementation details
}
データベースからエンティティを削除するメソッドを持つDAOオブジェクトがあるとします。 マーカーインターフェイスを実装するオブジェクトのみを削除できるように、_delete()_メソッドを記述することができます。
public class ShapeDao {

    // other dao methods

    public boolean delete(Object object) {
        if (!(object instanceof Deletable)) {
            return false;
        }

        // delete implementation details

        return true;
    }
}
ご覧のとおり、* JVMにオブジェクトの実行時の動作について指示を与えています。*オブジェクトがマーカーインターフェイスを実装している場合、データベースから削除できます。

[[marker annotations]]
=== 5. マーカーインターフェイスと アノテーション

アノテーションを導入することにより、Javaはマーカーインターフェイスと同じ結果を達成するための代替手段を提供してくれました。 さらに、マーカーインターフェイスと同様に、任意のクラスに注釈を適用でき、特定のアクションを実行するためのインジケーターとして使用できます。
それでは、重要な違いは何ですか?
アノテーションとは異なり、インターフェイスを使用すると、**ポリモーフィズムを活用**できます。 その結果、**マーカーインターフェイスに追加の制限を追加できます。**
たとえば、データベースから__Shape __typeのみを削除できるという制限を追加しましょう。
public interface Shape {
    double getArea();
    double getCircumference();
}
この場合、マーカーインターフェイスを呼び出して、_DeletableShape、_は次のようになります。
public interface DeletableShape extends Shape {
}
次に、クラスはマーカーインターフェイスを実装します。
public class Rectangle implements DeletableShape {
    // implementation details
}
したがって、* all _DeletableShape_実装も__Shape __implementations *です。 明らかに、*注釈を使用してそれを行うことはできません*。
ただし、設計上の決定にはすべてトレードオフがあり、*ポリモーフィズムはマーカーインターフェイスに対する反論*として使用できます。 *この例では、_Rectangle_を拡張するすべてのクラスが自動的に実装されます_DeletableShape ._ *

6. マーカーインターフェイスと 典型的なインターフェース

前の例では、DAOの_delete()_メソッドを変更して、オブジェクトが_Deletable:_であるかどうかをテストする代わりに、__ Shape __またはnot __、__であるかどうかをテストすることで、同じ結果を得ることができます。
public class ShapeDao {

    // other dao methods

    public boolean delete(Object object) {
        if (!(object instanceof Shape)) {
            return false;
        }

        // delete implementation details

        return true;
    }
}
では、通常のインターフェイスを使用して同じ結果を達成できるのに、なぜマーカーインターフェイスを作成するのでしょうか。
_Shape_型に加えて、データベースから_Person_型も削除したいと考えてみましょう。 この場合、それを達成するための2つのオプションがあります。
最初のオプションは、削除するオブジェクトが__Personのインスタンスであるかどうかを確認するために、以前の_delete()_メソッドに追加のチェックを追加することです。
public boolean delete(Object object) {
    if (!(object instanceof Shape || object instanceof Person)) {
        return false;
    }

    // delete implementation details

    return true;
}
しかし、データベースからも削除したい型がもっとあるとしたらどうでしょうか? 明らかに、新しいタイプごとにメソッドを変更する必要があるため、これは適切なオプションではありません*。
2番目のオプションは、** make * * _Person_ typeが__Shape ___ interface *を実装することです。これは、マーカーインターフェイスとして機能します。 しかし、_Person_オブジェクトは本当に_Shape_ですか? 答えは明らかに「いいえ」です。2番目の選択肢は最初の選択肢よりも悪くなります。
したがって、通常のインターフェイスをマーカーとして使用することで同じ結果を得ることができますが、デザインが貧弱になります。*

7. 結論

この記事では、マーカーインターフェイスとは何か、どのように使用できるかについて説明しました。 次に、このタイプのインターフェースの組み込みJavaの例と、それらがJDKでどのように使用されるかを調べました。
次に、独自のマーカーインターフェイスを作成し、アノテーションを使用して比較検討しました。 最後に、いくつかのシナリオで従来のインターフェイスの代わりにマーカーインターフェイスを使用するのが良い習慣である理由を確認しました。
いつものように、コードはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-lang-oop-2[GitHub]にあります。