Меня учили, что интерфейс Marker в Java является пустым интерфейсом и используется, чтобы сигнализировать компилятору или JVM, что объекты класса, реализующие этот интерфейс, должны обрабатываться особым образом, как сериализация, клонирование и т. Д.
Но в последнее время я узнал, что это на самом деле не имеет ничего общего с компилятором или JVM. Например, в случае Serializable
интерфейса метода writeObject(Object)
из ObjectOutputStream
делает что - то вроде instanceOf Serializable
обнаруживать ли класс реализует Serializable
броски и NotSerializableException
соответственно. Все обрабатывается в коде, и это похоже на шаблон дизайна, поэтому я думаю, что мы можем определить наши собственные интерфейсы маркеров.
Теперь мои сомнения:
Является ли определение интерфейса маркера, упомянутое выше в 1-й точке, неправильным? Как мы можем определить интерфейс Маркер тогда?
И вместо того, чтобы использовать
instanceOf
оператор, почему метод не может быть чем-то вродеwriteObject(Serializable)
так, чтобы была проверка типов во время компиляции, а не во время выполнения?Чем аннотации лучше, чем интерфейс маркеров?
источник
Serializable
в качестве аннотации это нонсенс, а@NonNull
в качестве интерфейса - нонсенс. Я бы сказал: аннотации - это маркеры + метаданные. Кстати: предвестником аннотаций был XDoclet, родившийся в Javadoc, убитый аннотациями.Ответы:
writeObject(Serializable)
чтобы была проверка типа во время компиляции - это позволяет избежать загрязнения вашего кода именем интерфейса маркера, когда требуется «обычныйObject
». Например, если вы создаете класс, который должен быть сериализуемым и иметь члены-объекты, вы будете вынуждены либо выполнять приведение, либо создавать свои объектыSerializable
во время компиляции. Это неудобно, потому что интерфейс лишен какой-либо функциональности.источник
writeObject
является частным, это означает, что, например, класс не должен вызывать реализацию суперклассаCloneable
неясно, будет ли изменена обработка экземпляра в библиотеке или JVM.Это не представляется возможным применять
Serializable
наwriteObject
потому , что дети не сериализуемым класса может быть сериализации, но их экземпляры могут быть upcasted обратно в родительский класс. В результате, удержание ссылки на что-то не сериализуемое (напримерObject
) не означает, что указанный экземпляр не может быть действительно сериализован. Например, вродительский класс (
Object
) не сериализуем и будет инициализирован с использованием конструктора без параметров. Значение ссылаетсяx
,String
является сериализации и условный оператор будет работать.источник
Вышесказанное началось как копия поста в блоге, но было слегка отредактировано для грамматики.
источник
Я сделал простую демонстрацию, чтобы решить сомнения № 1 и 2:
У нас будет интерфейс Movable, который будет реализован
MobilePhone.java
Class, и еще один класс,LandlinePhone.java
который НЕ реализует интерфейс Movable.Наш маркер интерфейс:
LandLinePhone.java
иMobilePhone.java
Наш класс исключений: пакет com;
Наш тестовый класс:
TestMArkerInterface.java
Теперь, когда мы выполняем основной класс:
Так какой класс реализует интерфейс маркера
Movable
, пройдет тест, иначе будет отображено сообщение об ошибке.Это способ
instanceOf
проверки оператора для Serializable , Cloneable и т. Д.источник
Интерфейс маркера / A, как следует из его названия, существует только для того, чтобы уведомить все, что о нем известно, о том, что класс что-то объявляет. Все, что угодно, может быть классами JDK для
Serializable
интерфейса или любым классом, который вы пишете для своего собственного.b / Если это интерфейс маркера, это не должно подразумевать существование какого-либо метода - было бы лучше включить подразумеваемый метод в интерфейс. Но вы можете решить, как вы хотите, если вы знаете, почему вы это нужно
c / Существует небольшая разница между пустым интерфейсом и аннотацией, в которой нет значения или параметра. Но разница есть: аннотация может объявлять список ключей / значений, которые будут доступны во время выполнения.
источник
а. Я всегда рассматривал их как шаблон дизайна, и ничего особенного JVM Я использовал этот шаблон в нескольких ситуациях.
с. Я считаю, что использование аннотаций для пометки чего-либо является лучшим решением, чем использование маркерных интерфейсов. Просто потому, что интерфейсы в первую очередь предназначены для определения общих интерфейсов типов / классов. Они являются частью класса-иерархии.
Аннотации предназначены для предоставления метаинформации в код, и я думаю, что маркер - это метаинформация. Так что они как раз для этого варианта использования.
источник
Он не имеет никакого отношения (обязательно) к JVM и компиляторам, он имеет отношение к любому коду, который заинтересован и тестирует данный интерфейс маркера.
Это дизайнерское решение, и оно сделано по уважительной причине. Смотрите ответ от Аудрюса Мешкаускаса.
Что касается этой конкретной темы, я не думаю, что это вопрос быть лучше или хуже. Интерфейс маркера делает то, что должен делать просто отлично.
источник
Основное назначение интерфейсов маркеров - создание специальных типов, в которых сами типы не имеют собственного поведения.
Здесь метод save гарантирует, что сохраняются только объекты классов, которые реализуют интерфейс MarkerEntity, для других типов выбрасывается InvalidEntityFoundException. Итак, здесь интерфейс маркера MarkerEntity определяет тип, который добавляет специальное поведение к классам, реализующим его.
Хотя аннотации можно также использовать для маркировки классов для некоторых специальных обработок, но аннотации маркеров заменяют шаблон именования, а не интерфейсы маркеров.
Но аннотации маркеров не могут полностью заменить интерфейсы маркеров, потому что; интерфейсы маркера используются для определения типа (как уже объяснено выше), а аннотации маркера - нет.
Источник для комментария интерфейса маркера
источник
Прежде всего, я бы сказал, что Serializable и Cloneable - плохие примеры маркерных интерфейсов. Конечно, они являются интерфейсами с методами, но они подразумевают такие методы, как
writeObject(ObjectOutputStream)
. (Компилятор создастwriteObject(ObjectOutputStream)
метод для вас, если вы не переопределите его, и все объекты уже естьclone()
, но компилятор снова создаст реальныйclone()
метод для вас, но с оговорками. Оба из этих странных крайних случаев, которые на самом деле не являются хорошие примеры дизайна.)Маркерные интерфейсы обычно используются для одной из двух целей:
1) В качестве ярлыка, чтобы избежать чрезмерно длинного типа, что может случиться с большим количеством обобщений. Например, скажем, у вас есть подпись этого метода:
Это грязно и надоедливо набирать, а главное, трудно понять. Рассмотрим это вместо этого:
Тогда ваш метод выглядит так:
Мало того, что это стало понятнее, теперь вы можете Javadoc интерфейс Widget, а также легче искать все вхождения в вашем коде Widget.
2) Маркерные интерфейсы также можно использовать как способ обойти отсутствие в Java типов пересечений. С интерфейсом маркера вы можете требовать, чтобы что-то было двух разных типов, например, в сигнатуре метода. Скажем, у вас есть интерфейсный виджет в вашем приложении, как мы описали выше. Если у вас есть метод, который требует Widget, который также позволяет вам перебирать его (он придуман, но работайте со мной здесь), ваше единственное хорошее решение - создать интерфейс маркера, который расширяет оба интерфейса:
И в вашем коде:
источник
Serializable
илиCloneable
. Вы можете проверить это, проверив ваши файлы классов. Кроме того, создание «горячих интерфейсов» - это не то, чем занимаются маркерные интерфейсы. И это действительно плохая практика кодирования, так как она требует создания дополнительных классов реализации для выполнения дополнительных интерфейсов. Кстати, Java имеет типы пересечений уже десять лет. Узнайте о дженериках ...Если интерфейс не содержит какого-либо метода и реализует этот интерфейс, если наш объект получит некоторую возможность, такой тип интерфейсов называется маркерными интерфейсами.
источник