개발 기록

> [Java] 마커 인터페이스(Marker Interface)에 대하여 본문

JAVA

> [Java] 마커 인터페이스(Marker Interface)에 대하여

1z 2024. 5. 7. 13:48

 

 

인터페이스(interface) 는 객체 지향프로그래밍의 핵심인 추상화(abstraction)와 다형성(polymorphism)을 구현하는 도구이며 인터페이스를 구현한 클래스들은 인터페이스에 정의된 모든 메서드를 반드시 구현해야 한다.

 

근데 내부에 메서드도! 필드도! 아무것도 없는! 말 그대로 빈 껍데기 인터페이스가 있다. 이게 무슨 말일까? 아래의 설명을 봐보자!

1. 개념 

마커 인터페이스는 내부에 메서드나 상수가 없는 인터페이스이며 태깅 인터페이스라고도 한다. 

내부가 비어있기 때문에 존재의 의미를 의심할 수 있지만, 마커 인터페이스는 해당 인터페이스를 구현하는 클래스가 특정한 타입이나 기능을 갖추었음을 나타내는 데 사용한다. 이러한 인터페이스의 주된 목적은 컴파일러나 런타임 시에 클래스에 대한 정보를 제공하거나 클래스의 동작을 변경하는 것이다.

Spring 에서 사용하는 마커 인터페이스 : 빈을 초기화하고 관리할 때 사용

 

정리하자면 마커 인터페이스는

ⓛ 클래스의 동작에 대한 메타데이터를 제공한다.

② 런타임 환경이나 프레임워크에 특정 작업을 수행하도록 신호를 보내는 데 사용한다.

구현 클래스가 특정 규약에 따라 동작해야 함을 나타내는 데 사용한다.

④ 특정 인터페이스를 구현함으로써 해당 인터페이스가 나타내는 기능이 활성화되거나 사용 가능하다는 것을 의미한다.

 

마커인터페이스의 예로는 Serializable, Cloneable, Closeable  등 이 있다.

 

 

(1) Java Maker Interface - Serializable 인터페이스 

: 가장 유명한 Java의 마커 인터페이스 중 하나이다. Serializable 인터페이스는 객체의 직렬화(serialization)를 지원하는데 사용되며 Serializable 인터페이스를 구현한 클래스는 직렬화될 수 있는 기능을 갖게 된다.

 

근데 마커 인터페이스의 유용성은 단순히 implement 만한다고 되는게 아니고, 구현 클래스가 특정 작업을 수행하기 위한 필요한 메서드 시그니처를 제대로 선언하고 구현했을 때! 의미가 있다.

예를 들어. Serializable 인터페이스를 구현하는 클래스에서는 serialVersionUID라는 필드를 선언해야하는데, 직렬화 프로세스가 객체를 직렬화하고 복원하기 위해 내부적으로 사용한다.

// Serializable 마커 인터페이스를 구현한 클래스
public class MyClass implements Serializable {
// 직렬화 시스템에서 객체의 버전 식별자로 사용된다.
// 클래스의 구현에 따라 직렬화 메커니즘이 이 필드를 사용하여 객체의 직렬화 여부를 결정한다.
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    
   ...
}

 

 

자바의 직렬화 메커니즘

1. writeObject() 메서드가 호출되면, JVM은 전달된 객체의 클래스 정보를 획득한다.

2. JVM은 리플렉션(reflection) 기능을 사용하여  객체의 클래스 정보를 기반으로 Serializable 인터페이스 구현 여부를 확인한다.

3. Serializable 인터페이스를 구현하지 않은 경우 java.io.NotSerializableException이 발생하여 직렬화가 실패한다.

 

 


2. 마커 인터페이스 예제  

 

마커 인터페이스 생성

Deleteable 인터페이스는 데이터베이스에서 객체를 제거할 수 있는지에 대한 여부를 나타내는 역할을 한다. 

public interface Deletable {
// 아무 메서드도 포함하지 않는다.
}

 

마커 인터페이스 구현 클래스 생성

public class Entity implements Deletable {
    // implementation details
}

 

Type 확인

Deletable Type 일 경우에만 삭제를 진행한다.

public class test {

    // other dao methods

    public boolean delete(Object object) {
    // instanceof 연산자로 객체의 타입을 확인한다. 
        if (!(object instanceof Deletable)) {
            return false;
        }

        // delete implementation details
        
        return true;
    }
}

 

 

 

3. Marger Interface vs Annotaion 

 

(1) Java Maker Interface - Serializable 인터페이스 

최근에는 애노테이션을 활용하여 마커 인터페이스가 수행하던 역할을 대체하고 있으며 마커 인터페이스보다 더 유연하고 강력한 기능(ex. 메타데이터 부여)을 제공한다.

 

메서드 실행시 reflection을 사용하여 해당 메서드에 부여된 어노테이션 정보를 읽고 출력하는 예제이다.  이렇게 하면 어노테이션을 사용하여 메타데이터를 쉽게 관리하고 활용할 수 있다.

import java.lang.annotation.*;

// 어노테이션 정의
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
    String value() default "default value";
    int number();
}

// 어노테이션 사용 예제
public class MyAnnotatedClass {

    // 어노테이션 적용
    @MyAnnotation(value = "Hello Annotation!", number = 10)
    public void myAnnotatedMethod() {
        System.out.println("This method is annotated!");
    }

    public static void main(String[] args) throws Exception {
        MyAnnotatedClass obj = new MyAnnotatedClass();
        // 어노테이션 정보 읽기
        var method = obj.getClass().getMethod("myAnnotatedMethod");
        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
        
        // 어노테이션 값 출력
        System.out.println("Value: " + annotation.value());
        System.out.println("Number: " + annotation.number());
    }
}

 

 

하지만 어노테이션을 대신 마커 인터페이스를 사용하면 다형성을 활용할 수 있다는 장점도 있다. 아래를 봐보자. 

 

 

 

(2) 마커 인터페이스의 다형성 활용

마커 인터페이스를 구현하는 클래스들을 상속 관계를 통해 다형성을 활용 할 수 있다.

// 마커 인터페이스
public interface MarkerInterface {
}

 

// 마커 인터페이스를 상속한 추상 클래스
abstract class Shape implements MarkerInterface {
    // 아무 메서드도 포함하지 않음
    // 단지 마커 인터페이스를 상속함
    // 이 추상 클래스는 다형성을 위한 기반 클래스로 활용됨
    public abstract double getArea();
}

 

// Rectangle 클래스: Shape 추상 클래스를 상속하고 마커 인터페이스를 구현
class Rectangle extends Shape {
    // implementation details
}

 

public class Example {
    public static void main(String[] args) {
        // Shape 클래스를 다형성을 이용하여 처리

        // 다형성을 위한 List 생성
        List<Shape> shapes = new ArrayList<>();

        // 리스트의 각 객체에 대해 특정 기능 수행 (다형성 활용)
        for (Shape shape : shapes) {
            if (shape instanceof Rectangle) {
            ...
            } else {
             ...
            }
        }
    }
}

 

 

(3) 마커 인터페이스와 어노테이션의 각 특성 

아래의 마커 인터페이스와 어노테이션은 각각의 특성과 사용 목적에 따라 적절히 선택하여 개발 하면 된다.

특성 마커 인터페이스 어노테이션
구현방식 인터페이스를 구현하여 사용 어노테이션을 선언하고, @ 기호를 사용하여 사용
사용예시 Serializable 인터페이스 @Override, @Deprecated, @SuppressWarnings
사용목적 클래스의 특정기능 활성화 또는 제어 코드 문서화, 컴파일 경고 무시, 런타임 처리 
인터페이스 구현 클래스가 인터페이스를 구현하여 특정 기능을 표시 어노테이션을 클래스, 메서드 등에 부착하여 기능 활성화