In this chapter marker interfaces and marker annotations are discussed. A marker interface is an interface that has no method declarations but simply is used to mark an implementing class as having a certain attribute. An example of a marker interface is the Serializable
interface built into the core of Java. Another similar thing you may hear about is of marker annotations. These serve a similar purpose of marking a specific item as having an attribute but, as the name suggests, uses an annotation instead of an interface to accomplish its task. So should we use one versus the other?
Marker interfaces, as all interfaces do, define a type. This is really where the core of when they should be used comes from. In defining a type we allow ourselves to use that power to help us at compile time. Let's consider the above example of Serializable
. The main consumer of this interface, ObjectOutputStream.write
, could use this ability of knowing it requires an object of the Serializable
type to define it's write
method as taking a Serializable
object. If this was done we would know at compile time (or more likely coding time because of our IDE's help) when we were trying to pass an object that isn't going to work to this method. Unfortunately the designer of this class didn't take the opportunity to make the interface this way and it instead takes an Object
but it still is instructive of a good potential use for a marker interface. Other times when we should use a marker interface is when we see that marker interface as only applicable to subtypes of a certain parent interface. In this case we simply extend the parent interface and then we know that all classes implementing this interface are also of the parent interface. As stated above, if deinfing a type makes sense for the marker you are creating, marker interfaces are the way to go.
So when do marker annotations make sense? Some of the things can lead us to using one of these instead of interfaces is when we are marking something other than a type. This is obviously impossible with an interface so naturally fits in here. We can also gain value of cohesiveness when working within an annotation heavy framework to follow the norm and use marker annotations rather than marker interfaces. This is nice in that the framework all feels put together and you aren't using interfaces sometimes and annotations at other times.
As often is the case when making decisions between two techniques in development, whether to use a marker interface or marker annotation largely comes down to use case. Both of these methods have valid use cases and by understanding those use cases we can make the best decision when writing our code now.
Top comments (5)
Marker interfaces were the only way to go before Java 5's annotations. Since annotations, there's no valid reason to come up with an interface with no methods.
Interfaces are meant to design a contract that all implementors need to follow.
Serializable
and other marker interfaces are legacy, and should never ever be used as examples of what to do.I definitely agree that interfaces most often are used to define a contract and it does muddie the waters to use them as marker interfaces. I think the author is simply pointing out that marker interfaces do have interesting attributes that annotations don't give you, namely compile time checking vs runtime checking. While I personally have never used an interfaces this way it is an interesting attribute of marker interfaces, and one that can be weighed against the shortcomings of the pattern as well.
Can you please provide a concrete example of this advantage?
Sure. For example if my method takes a
Set
.Set
adds nothing new to theCollection
interface other than some JavaDoc changes in my reading of the two interfaces. If I wanted to force the implementation ofSet
that would mean I don't require anything above aCollection
interface but I could enforce that implementation detail at compile time.As stated above the
ObjectOutputstream.writeObject
method is a missed opportunity for forcing at at compile time compliance in that only objects that implementSerializable
can successfully be processed by this method. Of course these classes were added to Java before annotations so they can't use annotations. However, they act the same way that annotations would act today (checked at runtime). The author is pitching that if the original designer would have made the method takeSerializable
rather thanObject
it would be slightly easier to work with the method and more self documenting.I'll focus on
Serializable
, becauseSet
cannot be replaced by annotation. Worse, its "contract" is enforced by nothing.Regarding
Serializable
, it should be the class that offers thewriteObject()
method. It should also be adefault
method, just asList.sort()
is. For the whole rationale behind default methods, please check this post.