Рубрики
Без рубрики

Интерфейсы маркеров в Java

Узнайте об интерфейсах маркеров Java и о том, как они сравниваются с типичными интерфейсами и аннотациями

Автор оригинала: baeldung.

1. введение

В этом кратком руководстве мы узнаем об интерфейсах маркеров в Java.

2. Маркерные интерфейсы

Интерфейс маркера-это интерфейс , в котором нет методов или констант . Он предоставляет информацию о типе среды выполнения об объектах , поэтому компилятор и JVM имеют дополнительную информацию об объекте .

Интерфейс маркера также называется интерфейсом маркировки.

Хотя интерфейсы маркеров все еще используются, они, скорее всего, указывают на запах кода и должны использоваться осторожно. Основная причина этого заключается в том, что они размывают линии о том, что представляет собой интерфейс, поскольку маркеры не определяют никакого поведения. Более новая разработка предпочитает аннотации для решения некоторых из тех же проблем.

3. Интерфейсы маркеров JDK

Java имеет множество встроенных маркерных интерфейсов, таких как Сериализуемый , Клонируемый и Удаленный.

Возьмем пример Клонируемого интерфейса . Если мы попытаемся клонировать объект, который не реализует этот интерфейс, JVM выдаст исключение CloneNotSupportedException . Следовательно, интерфейс Cloneable marker является индикатором для JVM , что мы можем вызвать метод Object.clone () .

Точно так же при вызове метода ObjectOutputStream.writeObject() JVM проверяет, реализует ли объект Сериализуемый маркерный интерфейс . Когда это не так, возникает исключение 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 о поведении наших объектов во время выполнения. Если объект реализует наш интерфейс маркера, он может быть удален из базы данных.

5. Маркерные интерфейсы по сравнению с Примечания

Вводя аннотации, Java предоставила нам альтернативу для достижения тех же результатов, что и интерфейсы маркеров. Более того, как и интерфейсы маркеров, мы можем применять аннотации к любому классу и использовать их в качестве индикаторов для выполнения определенных действий.

Так в чем же ключевая разница?

В отличие от аннотаций, интерфейсы позволяют нам использовать преимущества полиморфизма . В результате мы можем добавить дополнительные ограничения в интерфейс маркера.

Например, давайте добавим ограничение, что из базы данных можно удалить только Shape type:

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

В этом случае наш интерфейс маркера, назовем его Удаляемой формой, будет выглядеть следующим образом:

public interface DeletableShape extends Shape {
}

Тогда наш класс будет реализовывать интерфейс маркера:

public class Rectangle implements DeletableShape {
    // implementation details
}

Поэтому все Удаляемые формы реализации также являются формами реализациями . Очевидно, что мы не можем сделать это с помощью аннотаций .

Однако каждое дизайнерское решение имеет компромиссы, и полиморфизм может быть использован в качестве контраргумента против маркерных интерфейсов. В нашем примере каждый класс, расширяющий Прямоугольник , автоматически реализует Удаляемую форму.

6. Маркерные интерфейсы по сравнению с Типичные интерфейсы

В предыдущем примере мы могли бы получить те же результаты, изменив метод delete() нашего DAO, чтобы проверить, является ли наш объект Формой или нет , вместо того, чтобы проверять, является ли он удаляемым:

public class ShapeDao { 

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

Так зачем создавать интерфейс маркера, когда мы можем достичь тех же результатов, используя обычный интерфейс?

Давайте представим, что в дополнение к типу Shape мы также хотим удалить тип Person из базы данных. В этом случае есть два варианта для достижения этой цели:

Первый вариант – добавить дополнительную проверку к нашему предыдущему delete() методу , чтобы проверить, является ли объект для удаления экземпляром Person или нет.

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

Но что, если у нас есть еще типы, которые мы также хотим удалить из базы данных? Очевидно, что это не будет хорошим вариантом, потому что мы должны менять наш метод для каждого нового типа .

Второй вариант – сделать тип |/Person реализующим Shape интерфейс , который действует как интерфейс маркера. Но действительно ли Человек объект Форма ? Ответ явно отрицательный, и это делает второй вариант хуже первого.

Следовательно, хотя мы можем достичь тех же результатов, используя типичный интерфейс в качестве маркера, мы в конечном итоге получим плохой дизайн.

7. Заключение

В этой статье мы обсудили, что такое интерфейсы маркеров и как их можно использовать. Затем мы рассмотрели некоторые встроенные примеры Java этого типа интерфейсов и то, как они используются JDK.

Затем мы создали свой собственный интерфейс маркеров и сравнили его с использованием аннотации. Наконец, мы заканчиваем тем, что видим, почему в некоторых сценариях рекомендуется использовать интерфейс маркера вместо традиционного интерфейса.

Как всегда, код можно найти на GitHub .