Java의 마커 인터페이스?


134

Java의 Marker 인터페이스는 빈 인터페이스 이며이 인터페이스를 구현하는 클래스의 객체가 직렬화, 복제 등과 같은 특별한 방식으로 처리되어야한다는 것을 컴파일러 또는 JVM에 신호하는 데 사용됩니다.

그러나 최근에는 실제로 컴파일러 또는 JVM과 관련이 없다는 것을 알게되었습니다. 예를 들어, 경우에 Serializable계면에있어서 writeObject(Object)ObjectOutputStream같은 것을 수행 instanceOf Serializable클래스 구현하는지 여부를 검출 Serializable및 드로우 NotSerializableException따라서. 모든 것이 코드에서 처리되며 이것은 디자인 패턴 인 것처럼 보이므로 자체 마커 인터페이스를 정의 할 수 있다고 생각합니다.

이제 내 의심 :

  1. 위에서 언급 한 마커 인터페이스의 정의가 1 점에서 잘못 되었습니까? 그러면 마커 인터페이스를 어떻게 정의 할 수 있습니까?

  2. 그리고 instanceOf연산자 를 사용하는 대신 writeObject(Serializable)런타임이 아닌 컴파일 타임 유형 검사가되도록 메소드를 사용할 수없는 이유는 무엇 입니까?

  3. 주석이 마커 인터페이스보다 나은 점은 무엇입니까?


8
Serializable주석은 말도 안되고 @NonNull인터페이스는 말도 안됩니다. 나는 말할 것입니다 : 주석은 마커 + 메타 데이터입니다. BTW : Anofations의 Forefunner는 Javadoc에서 태어난 XDoclet으로 Annotations에 의해 사망했습니다.
그림

답변:


117
  1. 위에서 언급 한 마커 인터페이스의 정의가 첫 번째 점에서 잘못 되었습니까? -부분적으로는 (1) 마커 인터페이스가 비어 있어야하며 (2) 구현은 구현 클래스의 특별한 처리를 의미합니다. 잘못된 부분은 JVM 또는 컴파일러가 해당 클래스의 객체를 다르게 처리한다는 것을 암시한다는 것입니다. 이러한 객체를 복제 가능, 직렬화 가능 등으로 처리하는 Java 클래스 라이브러리의 코드인지 확인하는 것이 옳습니다. 컴파일러 또는 JVM과 관련이 없습니다.
  2. instanceOf 연산자를 사용하는 대신 writeObject(Serializable)컴파일 타임 유형 검사가 수행되도록 메서드를 사용할 수없는 이유는 무엇입니까 ? 이렇게하면 "일반 Object"이 필요할 때 마커 인터페이스의 이름으로 코드가 오염되는 것을 피할 수 있습니다 . 예를 들어, 직렬화 가능하고 객체 멤버가있는 클래스를 만드는 경우 Serializable컴파일 타임에 객체 를 캐스팅하거나 만들어야합니다 . 인터페이스에 기능이 없기 때문에 불편합니다.
  3. 주석이 마커 인터페이스보다 나은 점은 무엇입니까? -별도의 유형을 만들지 않고도 클래스에 대한 메타 데이터를 소비자에게 전달하는 것과 동일한 목적을 달성 할 수 있습니다. 주석도 더욱 강력하여 프로그래머가보다 복잡한 정보를 "소비하는"클래스에 전달할 수 있습니다.

14
내가 항상 이해했던 방식은 Annotations가 일종의 'Marker Interfaces 2.0'이라는 것입니다. Java 1.1부터 Serializable이 존재하며, 주석은 1.5에 추가되었습니다.
blagae

writeObject비공개 이기 때문에 , 예를 들어 클래스가 수퍼 클래스 구현을 호출 할 필요가 없음을 의미합니다.
ratchet freak

15
명심해야 할 것은 표준 라이브러리가 원래 설계된 후 몇 년 후에 주석이 언어에 추가되었다는 것입니다. 주석이 처음부터 언어로되어 있었다면 Serializable이 인터페이스 였을 것입니다. 아마도 주석 일 것입니다.
Theodore Norvell

글쎄, Cloneable변경 된 인스턴스의 라이브러리인지 JVM 처리인지는 확실하지 않습니다.
Holger

"[...] 별도의 유형을 작성하지 않고." -나는 이것이 정확하게 그것들을 분리시키는 것이라고 말하고 싶습니다 : 마커 인터페이스 유형을 소개하지만 주석 (종류)은 그렇지 않습니다 .
aioobe

22

적용 할 수 없습니다 SerializablewriteObject직렬화 가능하지 않은 클래스의 아이들이 직렬화 될 수 있기 때문에, 그러나 그들의 인스턴스는 부모 클래스에 upcasted 다시 할 수있다. 결과적으로 직렬화 가능 Object하지 않은 무언가에 대한 참조를 보유 한다고해서 참조 된 인스턴스를 실제로 직렬화 할 수는 없습니다. 예를 들어

   Object x = "abc";
   if (x instanceof Serializable) {
   }

부모 클래스 ( Object)는 직렬화 할 수 없으며 매개 변수가없는 생성자를 사용하여 초기화됩니다. 참조하는 값은 x, String직렬화하고 조건문이 실행됩니다.


6

Java의 마커 인터페이스는 필드 나 메소드가없는 인터페이스입니다. 간단히 말해서 Java의 빈 인터페이스를 마커 인터페이스라고합니다. (marker) 인터페이스의 예는이다 Serializable, CloneableRemote인터페이스한다. 이들은 정보를 컴파일러 또는 JVM에 표시하는 데 사용됩니다. 따라서 JVM이 클래스가 Serializable인 것을 발견하면 특별한 작업을 수행 할 수 있습니다. 마찬가지로 JVM에서 일부 클래스가 구현중인 것으로 확인되면 Cloneable복제를 지원하기 위해 일부 작업을 수행 할 수 있습니다. RMI와 Remote인터페이스도 마찬가지입니다 . 간단히 말해서 마커 인터페이스는 컴파일러 또는 JVM에 대한 신호 또는 명령을 나타냅니다.

위의 내용 은 블로그 게시물 의 복사본으로 시작 되었지만 문법에 맞게 약간 수정되었습니다.


6
그것은 복사 괜찮아요하지만 너무 소스를 언급 해주십시오 : javarevisited.blogspot.com/2012/01/...를 . 또한 맞춤법 오류를 붙여 넣지 않으면 복사하는 것이 좋습니다. :)
Saurabh Patil

6

의심의 여지없이 1과 2를 해결하기 위해 간단한 데모를 만들었습니다.

우리는 움직일 수에 의해 구현 될 것이다 인터페이스를 낳게 될 것이다 MobilePhone.java클래스 하나 개 더 클래스 LandlinePhone.java않습니다 하지 움직일 수있는 인터페이스를 구현을

마커 인터페이스 :

package com;

public interface Movable {

}

LandLinePhone.javaMobilePhone.java

 package com;

 class LandLinePhone {
    // more code here
 }
 class MobilePhone implements Movable {
    // more code here
 }

우리의 사용자 정의 예외 클래스 : package com;

public class NotMovableException extends Exception {

private static final long serialVersionUID = 1L;

    @Override
    public String getMessage() {
        return "this object is not movable";
    }
    // more code here
    }

우리의 테스트 클래스 : TestMArkerInterface.java

package com;

public class TestMarkerInterface {

public static void main(String[] args) throws NotMovableException {
    MobilePhone mobilePhone = new MobilePhone();
    LandLinePhone landLinePhone = new LandLinePhone();

    TestMarkerInterface.goTravel(mobilePhone);
    TestMarkerInterface.goTravel(landLinePhone);
}

public static void goTravel(Object o) throws NotMovableException {
    if (!(o instanceof Movable)) {
        System.out.println("you cannot use :" + o.getClass().getName() + "   while travelling");
        throw new NotMovableException();
    }

    System.out.println("you can use :" + o.getClass().getName() + "   while travelling");
}}

이제 메인 클래스를 실행할 때 :

you can use :com.MobilePhone while travelling
you cannot use :com.LandLinePhone while travelling
Exception in thread "main" com.NotMovableException: this object is not movable
    at com.TestMarkerInterface.goTravel(TestMarkerInterface.java:22)
    at com.TestMarkerInterface.main(TestMarkerInterface.java:14)

따라서 마커 인터페이스 Movable를 구현하는 클래스 는 테스트를 통과하지 않으면 오류 메시지가 표시됩니다.

이것은 Serializable , Cloneable 등에서 instanceOf운영자 확인이 수행 되는 방식입니다.


5

a / 이름에서 알 수있는 마커 인터페이스 는 클래스가 무언가를 선언 한다는 사실을 아는 것만 알려 줍니다. Serializable인터페이스 의 JDK 클래스 이거나 사용자 정의 클래스를 작성하는 클래스 일 수 있습니다.

b / 만약 그것이 마커 인터페이스라면, 그것은 어떤 메소드의 존재를 암시해서는 안됩니다-인터페이스에 묵시적인 메소드를 포함시키는 것이 좋습니다. 당신이 알고있는 경우에 당신이 원하는 그러나 당신은 그것을 설계하는 결정할 수 있습니다 당신이 그것을 필요

c / 빈 인터페이스와 값이나 매개 변수를 사용하지 않는 주석에는 차이가 거의 없습니다. 그러나 차이점이 있습니다. 주석은 런타임에 액세스 할 수있는 키 / 값 목록을 선언 할 수 있습니다.


3

ㅏ. 나는 항상 그것들을 디자인 패턴으로 보았고 몇 가지 상황에서 그 패턴을 사용한 JVM 스페셜은 없습니다.

씨. 나는 주석을 사용하여 무언가를 표시하는 것이 마커 인터페이스를 사용하는 것보다 더 나은 해결책이라는 것을 믿습니다. 단순히 인터페이스가 타입 / 클래스의 공통 인터페이스를 정의하는 것을 목표로하기 때문입니다. 그들은 계급 계층의 일부입니다.

주석은 코드에 메타 정보를 제공하기위한 것이며 마커는 메타 정보라고 생각합니다. 따라서 그것들은 정확히 그 유스 케이스를위한 것입니다.


3
  1. JVM 및 컴파일러와 (필수적으로) 아무 관련이 없으며 주어진 마커 인터페이스에 관심이 있고 테스트하는 코드와 관련이 있습니다.

  2. 그것은 디자인 결정이며 정당한 이유가 있습니다. Audrius Meškauskas의 답변을 참조하십시오.

  3. 이 특정 주제와 관련하여, 나는 그것이 더 나빠질 문제라고 생각하지 않습니다. 마커 인터페이스는 제대로 된 일을하고 있습니다.


"Audrius Meškauskas의 답변"에 대한 링크를 추가 할 수 있습니까? 이 페이지에 해당 이름의 내용이 없습니다.
Sarah Messer 2016 년

2

마커 인터페이스의 주요 목적은 유형 자체에 자체 동작이없는 특수 유형을 작성하는 것입니다.

public interface MarkerEntity {

}

public boolean save(Object object) throws InvalidEntityFoundException {
   if(!(object instanceof MarkerEntity)) {
       throw new InvalidEntityFoundException("Invalid Entity Found, can't be  saved);
   } 
   return db.save(object);
}

여기서 save 메소드는 다른 유형의 InvalidEntityFoundException이 발생하도록 MarkerEntity 인터페이스를 구현하는 클래스의 오브젝트 만 저장되도록합니다. MarkerEntity 마커 인터페이스는 클래스를 구현하는 클래스에 특별한 동작을 추가하는 유형을 정의합니다.

주석은 이제 특수 처리를 위해 클래스를 표시하는 데에도 사용할 수 있지만 마커 주석은 마커 인터페이스가 아닌 이름 지정 패턴을 대체합니다.

그러나 마커 주석은 마커 인터페이스를 완전히 대체 할 수 없습니다. 마커 인터페이스는 마커 주석이 아닌 유형을 정의하는 데 사용됩니다 (위에서 이미 설명한대로).

마커 인터페이스 주석의 소스


1
프로그래머가 명시 적으로 데이터베이스에 저장할 수 있다고 명시해야하는 단순한 "안전성"후크로 실제로 사용되었음을 보여 +1.
Ludvig W :

1

나는 Serializable과 Cloneable이 마커 인터페이스의 나쁜 예라고 먼저 주장한다. 물론 메소드와의 인터페이스 이지만와 같은 메소드 를 의미 합니다 writeObject(ObjectOutputStream). (컴파일러를 writeObject(ObjectOutputStream)재정의하지 않으면 모든 메소드 clone()가 이미 clone()메소드를 작성하지만 모든 오브젝트에 이미 메소드가 작성되지만 컴파일러는 다시 사용자를 위해 실제 메소드를 작성 하지만주의 사항이 있습니다. 둘 다 실제로는 그렇지 않은 이상한 경우입니다. 좋은 디자인 예)

마커 인터페이스는 일반적으로 다음 두 가지 목적 중 하나에 사용됩니다.

1) 너무 긴 유형을 피하는 지름길로 많은 제네릭에서 발생할 수 있습니다. 예를 들어,이 메소드 서명이 있다고 가정하십시오.

public void doSomething(Foobar<String, Map<String, SomethingElse<Integer, Long>>>) { ... }

입력하기가 지저분하고 성가 시며, 더 중요한 것은 이해하기 어렵습니다. 대신 이것을 고려하십시오 :

public interface Widget extends Foobar<String, Map<String, SomethingElse<Integer, Long>>> { }

그런 다음 방법은 다음과 같습니다.

public void doSomething(Widget widget) { ... }

더 명확 할뿐만 아니라 이제 위젯 인터페이스를 Javadoc 할 수 있으며 위젯 코드에서 모든 항목을 쉽게 검색 할 수 있습니다.

2) 마커 인터페이스는 Java의 교차 유형이없는 방법으로도 사용할 수 있습니다. 마커 인터페이스를 사용하면 메소드 서명과 같이 두 가지 유형이 필요합니다. 위에서 설명한 것처럼 응용 프로그램에 인터페이스 위젯이 있다고 가정 해보십시오. 위젯을 필요로하는 메소드가있는 경우 위젯을 반복 할 수 있습니다 (생각되었지만 여기에서 나와 함께 작업하십시오). 두 가지 인터페이스를 모두 확장하는 마커 인터페이스를 만드는 것이 유일한 해결책입니다.

public interface IterableWidget extends Iterable<String>, Widget { }

그리고 당신의 코드에서 :

public void doSomething(IterableWidget widget) {
    for (String s : widget) { ... }
}

1
컴파일러는 않습니다 되지 클래스가 구현하는 경우 어떤 방법을 만들 Serializable거나 Cloneable. 클래스 파일을 검사하여 확인할 수 있습니다. 또한 "단축 인터페이스"를 만드는 것은 마커 인터페이스가 아닙니다 . 그리고 추가 인터페이스를 수행하기 위해 추가 구현 클래스를 작성해야하므로 실제 나쁜 코딩 방법 입니다. 그건 그렇고, Java 10 년 동안 교차 유형을 가지고 있습니다. Generics에 대해 배우십시오…
Holger

복제 가능하면 옳습니다. Object.clone ()의 기능을 변경합니다. 여전히 끔찍합니다. Josh Bloch 링크를 참조하십시오. 바로 가기 인터페이스는 메소드로 보낼 수있는 것을 임의로 제한하기 때문에 반드시 좋은 디자인 패턴은 아닙니다. 동시에 약간 더 제한적인 코드를 더 명확하게 작성하는 것이 일반적으로 합리적인 절충이라고 생각합니다. 교차점 유형은 제네릭에만 적용되며 설명 할 수 없으므로 많은 경우에 쓸모가 없습니다. 직렬화 가능하고 다른 무엇이든 인스턴스 변수를 사용해보십시오.
MikeyB

0

인터페이스에 메소드가 포함되어 있지 않고 해당 오브젝트를 구현할 수있는 인터페이스를 구현하여 이러한 유형의 인터페이스를 마커 인터페이스라고합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.