[java] 왜 정적 중첩 인터페이스가 Java에서 사용됩니까?

코드베이스에서 정적 중첩 인터페이스를 찾았습니다.

class Foo {
    public static interface Bar {
        /* snip */
    }
    /* snip */
}

나는 이것을 전에 본 적이 없다. 원래 개발자가 접근 할 수 없습니다. 따라서 나는 이렇게 물어야한다.

정적 인터페이스의 의미는 무엇입니까? 를 제거하면 static어떻게됩니까? 왜 이런 짓을했을까요?



답변

위 예제에서 static 키워드는 중복 적이며 (중첩 된 인터페이스는 자동으로 “정적”임) 의미에 영향을주지 않고 제거 할 수 있습니다. 나는 그것을 제거하는 것이 좋습니다. 인터페이스 메소드의 “public”과 인터페이스 필드의 “public final”도 마찬가지입니다. 수정자는 중복되며 소스 코드에 혼란을 더합니다.

어느 쪽이든 개발자는 단순히 Foo.Bar라는 인터페이스를 선언합니다. Foo에 액세스 할 수없는 코드가 Foo.Bar에 액세스 할 수 없다는 점을 제외하고는 둘러싸는 클래스와 더 이상 연결되지 않습니다. (소스 코드에서-Foo가 패키지 전용 인 경우에도 바이트 코드 또는 리플렉션이 Foo.Bar에 액세스 할 수 있습니다!)

외부 클래스에서만 사용할 것으로 예상되는 경우 중첩 된 인터페이스를 작성하여 새 최상위 이름을 작성하지 않는 것이 허용되는 스타일입니다. 예를 들면 다음과 같습니다.

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});


답변

질문에 대한 답변이 있지만 중첩 된 인터페이스를 사용해야하는 한 가지 좋은 이유는 함수가 해당 클래스와 직접 관련이있는 것입니다. 이에 대한 좋은 예는 Listener입니다. 당신이 클래스를 가지고 있다면 Foo당신이 그것을에서 이벤트를 수신 할 수있는 다른 클래스를 원, 당신은라는 인터페이스를 선언 할 수 FooListener괜찮습니다,하지만 아마 중첩 된 인터페이스를 선언하는 것이 더 명확하고 그 다른 클래스가 구현하는 것이다 Foo.Listener( 중첩 클래스 Foo.Event는 이것과 함께 나쁘지 않습니다).


답변

멤버 인터페이스는 암시 적으로 정적입니다. 예제의 정적 수정자는 코드의 의미를 변경하지 않고 제거 할 수 있습니다. Java 언어 사양 8.5.1 도 참조하십시오 . 정적 멤버 유형 선언


답변

내부 인터페이스에 액세스하려면 정적이어야합니다. 인터페이스는 클래스의 인스턴스와 관련이 없지만 클래스 자체 Foo.Bar와 연결되므로 다음과 같이 액세스됩니다 .

public class Baz implements Foo.Bar {
   ...
}

대부분의 경우 이것은 정적 내부 클래스와 다르지 않습니다.


답변

Jesse의 대답은 가깝지만 내부 인터페이스가 유용한 이유를 보여주는 더 나은 코드가 있다고 생각합니다. 읽기 전에 아래 코드를 살펴보십시오. 내부 인터페이스가 유용한 이유를 찾을 수 있습니까? 대답은 내부 인터페이스를 사용하여 DoSomethingAlready 클래스를 인스턴스화 할 수 있다는 것 입니다. 사용자 정의 유형을 구성하고 캡슐화를 향상시킵니다 . 클래스를 A와 C를 구현하는 모든 클래스 있다는 것입니다. 콘크리트 클래스 동물원 만이 아닙니다. 물론 이것은 AC가 내부가 아니더라도 달성 할 수 있지만 A와 C뿐만 아니라 더 긴 이름을 연결하고 다른 조합 (예 : A 및 B, C 및 B 등)을 위해이 작업을 수행하는 것을 상상해보십시오. 상황이 어떻게 통제되지 않는지보십시오. 말할 것도없이 소스 트리를 검토하는 사람들은 한 클래스에서만 의미있는 인터페이스에 압도 될 것입니다.

class ConcreteA implements A {
 :
}

class ConcreteB implements B {
 :
}

class ConcreteC implements C {
 :
}

class Zoo implements A, C {
 :
}

class DoSomethingAlready {
  interface AC extends A, C { }

  private final AC ac;

  DoSomethingAlready(AC ac) {
    this.ac = ac;
  }
}


답변

질문에 직접 대답하려면 Map.Entry를보십시오.

지도

또한 이것은 유용 할 수 있습니다

정적 중첩 인터페이스 블로그 항목


답변

일반적으로 정적 내부 클래스가 보입니다. 정적 내부 클래스는 비 정적 클래스가 할 수있는 포함 클래스를 참조 할 수 없습니다. 패키지 충돌이 발생하지 않는 한 (이미 Foo와 동일한 패키지에 Bar라는 인터페이스가 있습니다) 필자는 자체 파일로 만들 것이라고 생각합니다. Foo와 Bar 사이의 논리적 연결을 적용하기위한 설계 결정일 수도 있습니다. 아마도 저자는 Bar가 Foo에서만 사용되도록 의도했을 것입니다 (정적 내부 인터페이스는 이것을 논리적 연결로 강제하지는 않지만)