A marker interface is an empty interface used purely to tag a type — implements Serializable declares "this class agrees to be serialized" without adding any methods. Annotations (Java 5+) replaced most markers because they carry metadata in a more granular, parameterized, and reflection-friendly form. Markers haven't fully died — they survive where the JVM or libraries need fast, generic-aware type checks.
The classic markers in the JDK
public interface Serializable { /* no methods */ }
public interface Cloneable { /* no methods */ }
public interface RandomAccess { /* no methods */ }
Serializable— your class opts into Java's binary serialization protocol. The serializer checkso instanceof Serializableand throwsNotSerializableExceptionotherwise.Cloneable— opts your class intoObject.clone(). If absent,clone()throwsCloneNotSupportedException.RandomAccess— signals that aListsupports constant-time positional access (ArrayListdoes,LinkedListdoesn't). Algorithms use it to choose between index-based and iterator-based traversal.
How a library uses one
public static <T> int indexOf(List<T> list, T target) {
if (list instanceof RandomAccess) {
for (int i = 0; i < list.size(); i++) // index loop
if (Objects.equals(list.get(i), target)) return i;
} else {
int i = 0;
for (T x : list) { // iterator loop
if (Objects.equals(x, target)) return i;
i++;
}
}
return -1;
}
The marker is a runtime capability check. No methods, no implementation — just a type-system flag.
Why annotations took over
Annotations express the same idea with more power:
@Entity
@Table(name = "users") // parameterized metadata
public class User {
@Id @GeneratedValue Long id;
@Column(nullable = false) String name; // field-level metadata
}
Marker interfaces can't:
- Carry parameters (
@Table(name = "users")). - Annotate fields, methods, parameters, or local variables — only types.
- Be retained selectively (source / class / runtime).
- Be applied without polluting the type hierarchy — once
Foo implements Marker, every subclassis-a Markerwhether or not it should be.
@Override, @Deprecated, @FunctionalInterface, @Test, @Inject — all do work that pre-Java-5 would have needed a marker.
When markers still win
instanceofis faster and clearer thangetClass().isAnnotationPresent(...). For very hot paths the JVM can specialize on the type check.- Generics use markers in bounds:
<T extends Comparable<T>>is structurally what a marker bound looks like. Annotations can't appear in type bounds. - Auto-inheritance. Mark a base class and every subclass inherits the marker for free. Annotations require
@Inheritedand even then only flow throughextends, notimplements. - Legacy and serialization.
Serializable,Cloneable,RandomAccess, andEventListenerare too deeply wired into the platform to replace.
A modern Java take
Bloch (Effective Java item 41) gives the rule: use a marker interface when you need to type-check generically (a method parameter typed as the marker) or when you'd otherwise have to use reflection at every check. Use annotations for purely declarative metadata, especially when parameters or non-type targets are involved.