Java & Kotlin

[Java]✏️마커 인터페이스에 대하여.

자흐니 2022. 2. 12. 21:22

0. 들어가며🚶

 String 클래스에 대하여 공부하다 String 클래스가 구현한 인터페이스 중 Serializable 이라는 인터페이스가 눈에 띄었습니다.

 

Java API

 Serializable은 직렬화를 위한 인터페이스로 객체를 파일에 저장하거나, 다른 서버로 보내거나 받거나 등의 일을 하기 위해 구현해야 하는 인터페이스라고 소개되어있습니다.

public interface Serializable {

}

 ?? 그런데 인터페이스에 아무 내용이 없죠.. 아무 내용이 없는 인터페이스가 어떤 식으로 위와 같은 기능을 제공할 수 있는지 궁금해져 찾아보니 마커 인터페이스라는 키워드를 얻을 수 있었고 이에 대해 정리해보려고 합니다.


1. 마커 인터페이스(Marker Interface)❗

1) 마커 인터페이스(Marker Interface) 란?

A marker interface is an interface that has no methods or constants inside it.

 

 마커 인터페이스란 위에서 살펴본 바와 같이 인터페이스 내부에 상수도, 메소드도 없는 인터페이스를 말합니다. 아무 내용도 없어서 쓸모가 없어 보이지만 마커 인터페이스는 객체의 타입과 관련된 정보를 제공해줍니다. 따라서 컴파일러와 JVM은 이 마커 인터페이스를 통해 객체에 대한 추가적인 정보를 얻을 수 있게 되죠.

 

 마커 인터페이스의 대표적 예시로는 Cloneable, Serializable 인터페이스가 있습니다. 

 

 위 정보만으로는 마커 인터페이스가 무엇인지에 대한 감이 전혀 오지 않으니 실제 활용 사례를 Serializable 인터페이스를 통해서 알아보도록 하겠습니다.

 

2) 마커 인터페이스의 활용 예시

아래의 코드를 살펴봅시다! 주의 깊게 봐야 하는 곳은 9번 라인22번 라인입니다.

  • 9번 라인의 경우 객체를 파일로 저장하려는 곳입니다.
  • 22번 라인의 경우 Serializable 인터페이스를 구현하지 않은 임의의 오브젝트입니다.
import java.io.*;

public class MarkerInterfaceTest {
    public void serializableTest() throws IOException {
        File f= new File("test.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(f));

        // 이 부분이 객체를 파일로 저장하는 부분!
        objectOutputStream.writeObject(new SomeObject("kjhoon", "kjhoon0330@snu.ac.kr"));
    }

    public static void main(String[] args) {
        MarkerInterfaceTest t = new MarkerInterfaceTest();
        try {
            t.serializableTest();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class SomeObject {
    private String name;
    private String email;

    public SomeObject(String name, String email) {
        this.name = name;
        this.email = email;
    }
}

 위 코드를 실행시킬 시 아래와 같이 NotSerializableException 에러 메시지가 뜨게 되죠.

 직렬화가 불가능하다는 것인데 위 코드의 일부분을 아래와 같이 고치면 에러를 해결할 수 있습니다.

class SomeObject implements Serializable { // Serializable 인터페이스 구현
        // 생략
}

즉, SomeObject 객체가 Serializable 인터페이스를 구현하면 되는 것이죠. 또한 Serializable 인터페이스는 마커 인터페이스이기 때문에 아무 메소드도 구현해줄 필요가 없습니다.

 

 하지만.. 단지 이것만으로 에러가 어떻게 해결된 것인지 이해하기가 어렵습니다.. 이에 대해 좀 더 알아보기 위해 writeObject의 코드 중 일부를 확인해보죠!

ObjectOutputStream의 writeObject 함수 내부

 빨간 상자 안을 살펴보면 obj가 Serializable의 인스턴스인지에 대한 여부를 체크하고 있고, 그렇지 않으면 아래 코드에서 에러를 발생시키는 것을 알 수 있습니다. 즉, Serializable 이라는 마커 인터페이스를 활용하여 코드를 진행시켰음을 알 수 있다. 이러한 방식을 통해 아무 내용도 없는 마커 인터페이스가 객체에 추가적인 정보를 주입시킨다는 것을 알 수 있죠.

 

여기까지 마커 인터페이스가 어떻게 활용되었는지를 살펴보았습니다!


2. 나가며💨

이번 글에서는 언뜻보면 아무 의미없어 보이는 마커 인터페이스에 대해 알아보았습니다. 

 

클래스에 추가적인 정보 마킹을 위해 사용할 수 있는 선택지는 여러 가지가 있었을 것 같습니다. 그 중에서도 인터페이스를 사용한 이유가 뭘까에 대해 고민해보았는데 제 개인적인 결론은 다음과 같습니다. 

 

인터페이스들의 네이밍을 보면  XXXable과 같이 짓는 경우가 많이 있죠. 해당 인터페이스를 구현한 클래스가 XXX할 수 있음을 알려주려는 듯 말입니다. Comparable 인터페이스를 구현한 클래스를 보면서 코드를 읽는 사람이 "해당 클래스는 인스턴스끼리 서로 비교가 가능하구나!" 라고 생각할 수 있게 해주는 것이 그 예시가 될 수 있습니다.

 

이렇듯 인터페이스는 특정 클래스에 추가적인 정보를 표현하기 좋은 것 같습니다. 또한  다중 상속이 가능하고 상속관계에서 자유로운 인터페이스의 특징은 목표인 정보 표현 이외에 사이드 이펙트를 발생시키지 않을 수 있는 좋은 선택지가 될 수 있는 것 같습니다.

반응형