답변:
위 예제에서 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.util.Map.Entry
(다른 인터페이스에 중첩 된 인터페이스)입니다.
Map.Entry
또는 클래스가 해당 패키지 내에있는 것을 선호합니다 . 수업 시간을 단축하고 요점을 지키기 때문에 이렇게 말합니다. 또한 독자는 패키지의 클래스를보고 클래스와 관련된 다른 엔티티를 볼 수 있습니다. java.collections.map
지도 용 패키지가있을 것입니다 . 이것은 OO와 모듈성에 관한 것입니다. java.util
그것에 너무 많이 있습니다. util
같은 common
냄새 IMO
java.util
확실히 너무 많이 있습니다. 즉, 제안 한대로 세밀한 패키지로 나누는 것이 이상적이라고 생각하지 않습니다.
java.util.MapEntry
자체 패키지 외부에서 호출한다고 가정하십시오 . 첫 번째 반사 :이 클래스와 관련된 인터페이스는 무엇입니까? 수업을 봅니다. javadoc이이 인터페이스에 링크하지 않는 한, 나는 그들의 관계에 대한 실마리가 없다. 또한 사람들은 가져 오기 패키지를 보지 않습니다. 모두 자신의 의견이 있습니다. 아무도 옳지 않다, 아무도 잘못하지 않았다
멤버 인터페이스는 암시 적으로 정적입니다. 예제의 정적 수정자는 코드의 의미를 변경하지 않고 제거 할 수 있습니다. Java 언어 사양 8.5.1 도 참조하십시오 . 정적 멤버 유형 선언
내부 인터페이스에 액세스하려면 정적이어야합니다. 인터페이스는 클래스의 인스턴스와 관련이 없지만 클래스 자체 Foo.Bar
와 연결되므로 다음과 같이 액세스됩니다 .
public class Baz implements Foo.Bar {
...
}
대부분의 경우 이것은 정적 내부 클래스와 다르지 않습니다.
The interface isn't associated with instances of the class, but with the class itself
더 자세한 의미를 설명해 주실 수 는 없습니다.
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;
}
}
Zoo
는 인터페이스를 구현 하지 않으므로AC
인스턴스가 예상 Zoo
되는 생성자에 전달 될 수 없습니다 . 사실 모두를 확장 하고 , 클래스가 구현하는 것을 의미하지는 않습니다 및 마술도 구현합니다 . DoSomethingAlready
AC
AC
A
C
A
C
AC
일반적으로 정적 내부 클래스가 보입니다. 정적 내부 클래스는 비 정적 클래스가 할 수있는 포함 클래스를 참조 할 수 없습니다. 패키지 충돌이 발생하지 않는 한 (이미 Foo와 동일한 패키지에 Bar라는 인터페이스가 있습니다) 필자는 자체 파일로 만들 것이라고 생각합니다. Foo와 Bar 사이의 논리적 연결을 적용하기위한 설계 결정일 수도 있습니다. 아마도 저자는 Bar가 Foo에서만 사용되도록 의도했을 것입니다 (정적 내부 인터페이스는 이것을 논리적 연결로 강제하지는 않지만)
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 가지 인스턴스가 필요하며 정적 인 경우 입력과 함께 데이터가 변경되지 않으므로 원인과 비교할 수 있습니다.
정적 방법은 일회성 반환 및 빠른 계산 또는 쉽게 얻을 수있는 데이터에 적합합니다.