A marker interface in java is an interface with no methods and no fields. Its sole purpose is to mark or tag a class as belonging to a certain category so that the JVM or a framework can identify those classes at runtime and treat them differently—essentially “tagging” the class for special processing.
The most commonly cited examples from the Java standard library are java.io.Serializable, java.lang.Cloneable, and java.util.RandomAccess. None of these interfaces define any methods. They exist entirely so that the JVM or the Java runtime can check – using instanceof or reflection – whether a class has been deliberately opted into a particular behaviour. Implementing Serializable does not give a class serialisation logic; it tells the ObjectOutputStream that this class has been intentionally allowed to be serialised.
How Java Uses Marker Interfaces Internally
| Interface | Package | Purpose | What Changes When Implemented |
|---|---|---|---|
| Serializable | java.io | Marks a class as safe to serialise to a byte stream | ObjectOutputStream will serialise it; throws NotSerializableException if absent |
| Cloneable | java.lang | Marks a class as allowing Object.clone() to perform field-by-field copy | clone() works; throws CloneNotSupportedException if absent |
| RandomAccess | java.util | Marks a List as having O(1) random access (e.g., ArrayList) | Collections algorithms choose between indexed and iterator traversal based on this |
| Remote | java.rmi | Marks an object as remotely accessible via Java RMI | RMI infrastructure handles remote invocation for marked objects |
Code Example: Serializable in Practice
Without the marker interface:
- public class User { private String name; private int age; }
- // Attempting to serialise this throws: java.io.NotSerializableException
With the marker interface:
- public class User implements Serializable {
- private static final long serialVersionUID = 1L;
- private String name;
- private int age;
- }
- // Now ObjectOutputStream.writeObject(user) works correctly
The interface body is empty. No methods. No constants. The act of implementing it is the entire mechanism – it is a declaration of intent that the runtime honours.
How It Works Under the Hood
When the Java runtime or a framework needs to check whether an object has been marked, it uses the instanceof operator or reflection. For example, ObjectOutputStream contains logic roughly equivalent to:
- if (!(obj instanceof Serializable)) {
- throw new NotSerializableException(obj.getClass().getName());
- }
The instanceof check is O(1) – it is a fast type check the JVM is highly optimised for. Marker interfaces effectively extend Java’s type system to carry semantic meaning, allowing runtime dispatch decisions based on class identity rather than interface contracts.
Marker Interface vs. Annotation: The Modern Comparison
| Factor | Marker Interface | Marker Annotation |
|---|---|---|
| Syntax | implements MarkerInterface | @MarkerAnnotation on class |
| Type system integration | Yes – captured in compile-time type | No – annotation metadata, not a type |
| Inheritance | Automatically inherited by subclasses | Not inherited unless @Inherited is added |
| Retention | Always present at runtime | Depends on @Retention policy |
| Works with instanceof | Yes – if (obj instanceof Marker) | No – requires reflection: cls.isAnnotationPresent(Marker.class) |
| Can be applied to non-classes | No – interfaces only | Yes – methods, fields, parameters, packages |
| Modern preference | Legacy – maintained for backward compat | Preferred for new code in most cases |
When to Use a Marker Interface in Modern Java
The honest answer in 2026: rarely for new code, but not never. The main case where a marker interface still beats an annotation is when you need type system integration – specifically when you want to restrict a method parameter to only accept classes that have been explicitly marked.
- Marker interface allows: public void process(Serializable obj) – the compiler enforces that only Serializable objects can be passed
- Marker annotation cannot do this: you cannot write public void process(@Marked Object obj) and have the compiler enforce it
If your design needs that compile-time guarantee – ‘this method must only ever receive a marked class’ – then a marker interface is the right tool. If you just need to attach metadata for runtime inspection, use an annotation.
Real-World Use Cases
- Domain-Driven Design event markers: marking a class as a domain event (implements DomainEvent) gives it type identity that can be used in generic bounds – public <T extends DomainEvent> void publish(T event)
- Security markers: marking classes as safe for serialisation to untrusted sources – a custom SafeToDeserialise interface that ObjectInputStream checks before deserialization
- Framework hooks: Spring and Hibernate use marker interfaces in some contexts (e.g., Spring’s ApplicationListener conceptually, Hibernate’s entity markers in older versions)
- Test doubles: marking test stubs for cleanup – interfaces like TestFixture or MockObject that allow test frameworks to identify and reset them automatically
Final Guidance
Marker interfaces are a pattern from an era before Java annotations existed (pre-Java 5). They remain valid – and actively used in the JDK – but the default choice for new code that needs to mark or tag a class should be an annotation. Annotations are more flexible, work on more targets, do not pollute the type hierarchy, and communicate intent through explicit metadata rather than inheritance.
Use a marker interface when: you specifically need instanceof-based type checking or compile-time parameter restriction. Use an annotation for everything else. Understanding why the distinction exists makes you better at reading legacy Java code and better at designing clean APIs when the rare case for a marker interface actually arises.

