1. 序章

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

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

マーカーインターフェイスはインターフェイスであり、にはメソッドや定数がありません。 オブジェクトに関する実行時型情報を提供するため、コンパイラとJVMにはオブジェクトに関する追加情報があります。

マーカーインターフェイスは、タグ付けインターフェイスとも呼ばれます。

マーカーインターフェイスはまだ使用されていますが、コードの臭いを示している可能性が高いため、慎重に使用する必要があります。 これの主な理由は、マーカーが動作を定義しないため、インターフェイスが表すものについての線がぼやけることです。 新しい開発では、同じ問題のいくつかを解決するために注釈が優先されます。

3. JDKマーカーインターフェイス

Javaには、 Serializable Cloneable Remoteなどの多くの組み込みマーカーインターフェイスがあります。

クローン可能インターフェースの例を見てみましょう。 このインターフェースを実装していないオブジェクトのクローンを作成しようとすると、JVMはCloneNotSupportedExceptionをスローします。 したがって、 Cloneable マーカーインターフェイスは、 Object.clone()メソッドを呼び出すことができるJVMへのインジケーターです。

同様に、 ObjectOutputStream.writeObject()メソッドを呼び出すと、JVMはオブジェクトがSerializableマーカーインターフェイスを実装しているかどうかを確認します。 そうでない場合は、NotSerializableExceptionがスローされます。 したがって、オブジェクトは出力ストリームにシリアル化されません。

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

独自のマーカーインターフェイスを作成しましょう。

たとえば、オブジェクトをデータベースから削除できるかどうかを示すマーカーを作成できます。

public interface Deletable {
}

データベースからエンティティを削除するには、このエンティティを表すオブジェクトが削除可能なマーカーインターフェイスを実装する必要があります。

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に指示を出します。オブジェクトがマーカーインターフェイスを実装している場合は、データベースから削除できます。

5. マーカーインターフェイスと 注釈

アノテーションを導入することにより、Javaはマーカーインターフェースと同じ結果を達成するための代替手段を提供してくれました。 さらに、マーカーインターフェイスと同様に、任意のクラスに注釈を適用でき、特定のアクションを実行するためのインジケーターとしてそれらを使用できます。

では、主な違いは何ですか?

注釈とは異なり、インターフェースを使用すると、ポリモーフィズムを利用できます。 その結果、マーカーインターフェイスに追加の制限を追加できます。

たとえば、Shapeタイプのみをデータベースから削除できるという制限を追加しましょう。

public interface Shape {
    double getArea();
    double getCircumference();
}

この場合、マーカーインターフェイスを DeletableShapeと呼びましょう。は、次のようになります。

public interface DeletableShape extends Shape {
}

次に、クラスはマーカーインターフェイスを実装します。

public class Rectangle implements DeletableShape {
    // implementation details
}

したがって、すべてのDeletableShape実装はShape実装でもあります。 明らかに、アノテーションを使用してそれを行うことはできません。

ただし、すべての設計上の決定にはトレードオフがあり、ポリモーフィズムはマーカーインターフェイスに対する反論として使用できます。 この例では、Rectangleを拡張するすべてのクラスが自動的にDeletableShapeを実装します。

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

前の例では、DAOの delete()メソッドを変更して、オブジェクトが Shape かどうか 削除可能かどうかをテストする代わりに:

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つのオプションがあります。

最初のオプションはで、以前のdelete()メソッドに追加のチェックを追加して、削除するオブジェクトがPersonのインスタンスであるかどうかを確認します。

public boolean delete(Object object) {
    if (!(object instanceof Shape || object instanceof Person)) {
        return false;
    }
    
    // delete implementation details
        
    return true;
}

しかし、データベースから削除したいタイプが他にもある場合はどうなるでしょうか。 明らかに、これは良いオプションではありません。新しいタイプごとにメソッドを変更するがあるからです。

2番目のオプションは、 Personタイプに、マーカーインターフェイスとして機能するShapeインターフェイスを実装させることです。 しかし、 Personオブジェクトは本当にShapeですか? 答えは明らかにノーであり、それは2番目のオプションを最初のオプションよりも悪くします。

したがって、通常のインターフェイスをマーカーとして使用しても同じ結果を得ることができますが、デザインが貧弱になります。

7. 結論

この記事では、マーカーインターフェイスとは何か、およびそれらをどのように使用できるかについて説明しました。 次に、このタイプのインターフェースのいくつかの組み込みJavaの例と、それらがJDKでどのように使用されるかを調べました。

次に、独自のマーカーインターフェイスを作成し、アノテーションを使用して比較検討しました。 最後に、一部のシナリオで従来のインターフェイスの代わりにマーカーインターフェイスを使用することがなぜ良い習慣であるかを理解することになります。

いつものように、コードはGitHubにあります。