왜 정적 중첩 인터페이스가 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에서만 사용되도록 의도했을 것입니다 (정적 내부 인터페이스는 이것을 논리적 연결로 강제하지는 않지만)
Foo 클래스를 Foo 인터페이스로 변경하면 위 예제의 "public"키워드도 중복됩니다.
다른 인터페이스 내에 정의 된 인터페이스는 암시 적으로 공개 정적입니다.
1998 년 Philip Wadler는 정적 인터페이스와 비 정적 인터페이스의 차이점을 제안했습니다.
내가 볼 수있는 한, 인터페이스를 비 정적으로 만드는 것의 유일한 차이점은 이제 비 정적 내부 클래스를 포함 할 수 있다는 것입니다. 따라서 변경으로 인해 기존 Java 프로그램이 유효하지 않게됩니다.
예를 들어 그는 표현 문제에 대한 해결책을 제안했는데 , 이는 표현이 "언어로 표현할 수 있는가"라는 표현과 표현이 "귀하의 언어로 표현하려고하는 용어"와의 불일치입니다. .
정적 및 비 정적 중첩 인터페이스의 차이점에 대한 예제는 샘플 코드 에서 확인할 수 있습니다 .
// 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에서 이루어지지 않았습니다. 따라서 다른 모든 대답은 정확합니다. 정적 및 비 정적 중첩 인터페이스에는 차이가 없습니다.
Java에서 정적 인터페이스 / 클래스는 인터페이스 / 클래스를 최상위 클래스처럼 사용할 수 있습니다. 즉, 다른 클래스에서 선언 할 수 있습니다. 그래서 당신은 할 수 있습니다 :
class Bob
{
void FuncA ()
{
Foo.Bar foobar;
}
}
정적이 없으면 위의 컴파일에 실패합니다. 이것의 장점은 인터페이스를 선언하기 위해 새 소스 파일이 필요하지 않다는 것입니다. 또한 Foo.Bar를 작성해야하므로 인터페이스 Bar를 시각적으로 Foo 클래스에 시각적으로 연결하며 Foo 클래스가 Foo.Bar의 인스턴스로 무언가를 수행함을 의미합니다.
정적은 패키지 (프로젝트)의 모든 클래스 부분이 포인터를 사용하지 않고 패키지에 액세스 할 수 있음을 의미합니다. 상황에 따라 유용하거나 방해가 될 수 있습니다.
"정적"메소드의 유용한 예는 Math 클래스입니다. Math의 모든 메소드는 정적입니다. 즉, 방해가되지 않고 새로운 인스턴스를 만들고 변수를 선언하고 더 많은 변수에 저장할 필요가 없습니다. 데이터를 입력하고 결과를 얻을 수 있습니다.
정적이 항상 유용한 것은 아닙니다. 예를 들어 대 / 소문자를 비교하는 경우 여러 가지 다른 방식으로 데이터를 저장할 수 있습니다. 동일한 서명으로 3 개의 정적 메서드를 만들 수 없습니다. 정적이 아닌 3 가지 인스턴스가 필요하며 정적 인 경우 데이터를 입력과 함께 변경하지 않으므로 원인과 비교할 수 있습니다.
정적 방법은 일회성 반환 및 빠른 계산 또는 쉽게 얻을 수있는 데이터에 적합합니다.
참고 URL : https://stackoverflow.com/questions/71625/why-would-a-static-nested-interface-be-used-in-java
'IT story' 카테고리의 다른 글
가장 간단한 SOAP 예 (0) | 2020.04.14 |
---|---|
JSON.parse에서 예외를 포착하는 올바른 방법 (0) | 2020.04.14 |
Sublime over SSH를 사용하는 방법 (0) | 2020.04.14 |
JavaScript를 사용하여 Caps Lock이 켜져 있는지 어떻게 알 수 있습니까? (0) | 2020.04.14 |
클라이언트 측 Javascript의 Base64 인코딩 및 디코딩 (0) | 2020.04.14 |