Marker Interface in Java – Tagging Classes with Empty Interfaces
A marker interface (or tagging interface) is an interface with no methods and no constants. Implementing it does not add behaviour; it simply marks a class as having a certain property. Other code, such as the JVM, a library or your own framework, checks for the marker with instanceof and treats marked objects differently.
This tutorial covers the JDK's marker interfaces (Serializable, Cloneable, RandomAccess), how to create your own, and how marker interfaces compare with marker annotations.
1. What Is a Marker Interface?
public interface Serializable { } // the entire declaration in java.io
class Customer implements Serializable { ... } // "Customer objects may be serialized"
The marker carries meaning through the type system: an object is either an instance of the marker type or not. Code that cares checks obj instanceof Marker or declares parameters of the marker type.
2. Marker Interfaces in the JDK
| Marker | Package | Meaning | Checked by |
|---|---|---|---|
Serializable | java.io | Objects may be converted to a byte stream | ObjectOutputStream throws NotSerializableException otherwise |
Cloneable | java.lang | Object.clone() may make a field-by-field copy | Object.clone() throws CloneNotSupportedException otherwise |
RandomAccess | java.util | The list supports fast indexed access | Algorithms such as Collections.binarySearch choose a strategy |
Remote | java.rmi | Methods may be invoked remotely via RMI | The RMI runtime |
EventListener | java.util | Tags all event listener interfaces | Tools and frameworks |
import java.io.*;
import java.util.*;
public class JdkMarkers {
static class Plain { int x = 1; }
static class Saveable implements Serializable { int x = 1; }
static class Sheep implements Cloneable {
String name = "Dolly";
@Override public Sheep clone() throws CloneNotSupportedException { return (Sheep) super.clone(); }
}
static class Goat {
String name = "Billy";
public Goat copy() throws CloneNotSupportedException { return (Goat) super.clone(); }
}
static void serialize(Object o) {
try (ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream())) {
out.writeObject(o);
System.out.println("Serializable: " + o.getClass().getSimpleName() + " OK");
} catch (IOException e) {
System.out.println("Serializable: " + e);
}
}
public static void main(String[] args) {
serialize(new Saveable());
serialize(new Plain());
try { System.out.println("Cloneable: cloned " + new Sheep().clone().name); }
catch (CloneNotSupportedException e) { System.out.println("Cloneable: " + e); }
try { new Goat().copy(); }
catch (CloneNotSupportedException e) { System.out.println("Cloneable: " + e); }
// RandomAccess tells algorithms that get(i) is fast
System.out.println("ArrayList is RandomAccess: " + (new ArrayList<>() instanceof RandomAccess));
System.out.println("LinkedList is RandomAccess: " + (new LinkedList<>() instanceof RandomAccess));
}
}
Serializable: Saveable OK Serializable: java.io.NotSerializableException: JdkMarkers$Plain Cloneable: cloned Dolly Cloneable: java.lang.CloneNotSupportedException: JdkMarkers$Goat ArrayList is RandomAccess: true LinkedList is RandomAccess: false
The classes are identical except for the marker, yet serialization and cloning succeed only for marked classes. See Serialization and Object Cloning.
3. Creating a Custom Marker Interface
You can define your own marker to tag classes that need special handling, such as events that must be audited:
import java.util.List;
public class CustomMarker {
// Custom marker interface: no methods, just a type tag
interface Auditable { }
record Payment(String id, double amount) implements Auditable { }
record Login(String user) implements Auditable { }
record PageView(String url) { }
static void process(Object event) {
if (event instanceof Auditable) { // check the marker
System.out.println("AUDIT -> " + event);
}
System.out.println("handled " + event.getClass().getSimpleName());
}
// Unlike an annotation, the marker is a TYPE: the compiler can enforce it
static void archive(Auditable record) {
System.out.println("ARCHIVE -> " + record);
}
public static void main(String[] args) {
List<Object> events = List.of(new Payment("P-1", 999.0), new PageView("/java"), new Login("asha"));
events.forEach(CustomMarker::process);
archive(new Login("ravi"));
// archive(new PageView("/x")); // compile error: PageView is not Auditable
}
}
AUDIT -> Payment[id=P-1, amount=999.0] handled Payment handled PageView AUDIT -> Login[user=asha] handled Login ARCHIVE -> Login[user=ravi]
The key strength of a marker interface is visible in archive(Auditable record): the compiler rejects unmarked objects, so mistakes are caught before the program runs.
4. Marker Interfaces vs Marker Annotations
Since Java 5, annotations without elements (marker annotations such as @Override, @FunctionalInterface and @Deprecated) can also tag code:
import java.lang.annotation.*;
import java.util.List;
public class MarkerAnnotation {
// Annotation-based alternative: a marker annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Cacheable { }
@Cacheable static class ProductService { }
static class OrderService { }
public static void main(String[] args) {
for (Class<?> c : List.of(ProductService.class, OrderService.class)) {
boolean cache = c.isAnnotationPresent(Cacheable.class);
System.out.println(c.getSimpleName() + " cacheable? " + cache);
}
}
}
ProductService cacheable? true OrderService cacheable? false
| Aspect | Marker interface | Marker annotation |
|---|---|---|
| Defines a type | Yes: usable for parameters and variables | No |
| Compile-time checking | Yes (method can require the marker type) | Only with annotation processors |
| Inherited by subclasses | Always | Only if @Inherited (and only for classes) |
| Can mark | Classes and interfaces only | Classes, methods, fields, parameters, packages, modules… |
| Can carry data | No | Yes, by adding elements later |
| Checked with | instanceof | Reflection: isAnnotationPresent |
A useful rule (from Effective Java): use a marker interface when you want to define a type that methods can accept; use a marker annotation to mark program elements other than classes, or in frameworks that already rely heavily on annotations (such as Spring and JPA).
5. Criticism and Pitfalls
- Inheritance cannot be undone: if a parent class is
Serializable, every subclass is too, even if it should not be. Cloneableis a poor design: it does not declareclone(), so the marker alone does not make an object cloneable through the interface. Copy constructors or factory methods are usually better.- Meaning is implicit: nothing in the interface explains what it promises; document it clearly.
6. Summary
- A marker interface has no methods and tags a class with a property.
- JDK markers include
Serializable,CloneableandRandomAccess. - Markers are checked with
instanceofor enforced by parameter types at compile time. - Marker annotations are more flexible but do not define a type.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a marker interface in Java?
An interface with no methods or fields whose only purpose is to mark classes that implement it, so other code can treat them specially.
Q2. What are examples of marker interfaces?
Serializable, Cloneable, RandomAccess, Remote and EventListener.
Q3. Why is it called a tagging interface?
Because implementing it only attaches a tag to the class; it adds no methods to implement.
Q4. How does the JVM use Serializable?
ObjectOutputStream checks whether an object is Serializable and throws NotSerializableException if it is not.
Q5. What happens if I call clone() without implementing Cloneable?
Object.clone() throws CloneNotSupportedException.
Q6. What is the RandomAccess interface?
A marker indicating that a list supports fast (constant-time) indexed access, like ArrayList. Algorithms use it to choose between index-based loops and iterators.
Q7. Can I create my own marker interface?
Yes. Declare an empty interface, implement it on the relevant classes, and check it with instanceof or use it as a parameter type.
Q8. What is the difference between a marker interface and a marker annotation?
A marker interface defines a type and enables compile-time checks; a marker annotation can mark more kinds of elements and is checked by reflection or annotation processors.
Q9. Are marker interfaces still used?
Yes, but less often. Annotations replaced many uses, while marker interfaces remain valuable when a type is needed for compile-time safety.
Q10. Is a functional interface a marker interface?
No. A functional interface has exactly one abstract method. @FunctionalInterface is a marker annotation, not a marker interface.
Q11. Is Runnable a marker interface?
No. It declares the run() method.
Q12. Do subclasses inherit a marker interface?
Yes. If a class implements a marker, all its subclasses are instances of the marker type too.
Q13. Can a marker interface be removed in a subclass?
No. Once a superclass implements an interface, subclasses cannot "un-implement" it. For Serializable, a subclass can only throw an exception from writeObject to block serialization.
Q14. Why is Cloneable considered badly designed?
It has no clone() method, so you cannot call clone() through a Cloneable reference, and it changes the behaviour of a protected method in Object in a hidden way.
Q15. Can a marker interface have constants?
A pure marker has none. An interface with constants is technically no longer an empty marker, though it would still add no methods.
Q16. How do I check whether an object has a marker?
Use obj instanceof Marker, or Marker.class.isAssignableFrom(clazz) for a Class object.
Q17. Is Remote a marker interface?
Yes. java.rmi.Remote marks interfaces whose methods can be invoked from another JVM through RMI.
Q18. What is the advantage of a marker interface over a boolean field?
It is checked by the type system, applies to all instances of a class without extra state, and can be enforced by method signatures at compile time.
Q19. Are records Serializable by default?
No. A record must implement Serializable explicitly, like any class. Records then serialize safely through their canonical constructor.
Q20. Do sealed interfaces replace marker interfaces?
They solve a different problem. A sealed interface restricts which classes may implement it. It can be empty like a marker, but its main purpose is controlling the hierarchy.