it-swarm-ko.tech

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

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

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

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

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

231
Mo.

위의 예제에서 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() {...}
});
291
Jesse Glick

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

71
ColinD

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

14
Bas Leijdekkers

내부 인터페이스에 액세스하려면 정적이어야합니다. 인터페이스는 클래스의 인스턴스와 관련이 없지만 클래스 자체와 관련이 있으므로 Foo.Bar, 이렇게 :

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

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

9

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;
  }
}
6
user1982892

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

Map.Entry

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

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

3
Henry B

1998 년 Philip Wadler는 정적 인터페이스와 비 정적 인터페이스의 차이점을 제안했습니다.

내가 볼 수있는 한, 인터페이스를 비 정적으로 만드는 것의 유일한 차이점은 이제 비 정적 내부 클래스를 포함 할 수 있다는 것입니다. 따라서 변경으로 인해 기존 Java 프로그램이 무효화되지 않습니다.

예를 들어, 그는 Expression Problem 에 대한 해결책을 제안했습니다. 이는 "언어 표현이 가능한지"라는 표현과 표현을 표현하려는 용어 사이의 불일치입니다. 당신의 언어 ".

정적 및 비 정적 중첩 인터페이스의 차이점에 대한 예는 그의 샘플 코드 에서 볼 수 있습니다.

// This code does NOT compile
class LangF<This extends LangF<This>> {
    interface Visitor<R> {
        public R forNum(int n);
    }

    interface Exp {
        // since Exp is non-static, it can refer to the type bound to This
        public <R> R visit(This.Visitor<R> v);
    }
}

그의 제안은 결코 Java 1.5.0)으로 만들지 않았으므로 다른 모든 대답은 정확합니다. 정적 및 비 정적 중첩 인터페이스에는 차이가 없습니다.

0
Pindatjuh

Foo 클래스를 Foo 인터페이스로 변경하면 위 예제의 "public"키워드도 중복됩니다.

다른 인터페이스 내에 정의 된 인터페이스는 암시 적으로 public static.

0
Danylo Volokh

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

0
basszero