인터페이스 내의 내부 클래스


97

인터페이스 내에서 내부 클래스 를 만들 수 있습니까?
가능하다면 인터페이스 객체를 만들지 않을 것이므로 왜 그런 내부 클래스 를 만들고 싶 습니까?

이러한 내부 클래스가 개발 프로세스에 도움이됩니까?

답변:


51

예, Java 인터페이스 내에 중첩 된 클래스 또는 내부 클래스를 모두 만들 있습니다 (일반적인 믿음과는 반대로 " 정적 내부 클래스 " 와 같은 것은 없습니다 . 이것은 단순히 말이되지 않고 "내부"도없고 "도 없습니다. outter "클래스는 중첩 된 클래스가 정적이므로"정적 내부 "일 수 없습니다.

어쨌든 다음은 잘 컴파일됩니다.

public interface A {
    class B {
    }
}

인터페이스 정의에 일종의 "계약 검사기"를 직접 넣는 데 사용되는 것을 보았습니다 (인터페이스에 중첩 된 클래스에서 정적 메서드를 가질 수 있지만 인터페이스 자체와는 반대로). 내가 올바르게 기억하면 이렇게 보입니다.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

나는 그러한 것의 유용성에 대해 언급하는 것이 아니라 단순히 귀하의 질문에 대답하는 것입니다. 그것은 할 수 있으며 이것은 내가 본 용도 중 하나입니다.

이제 나는 그러한 구조의 유용성에 대해 언급하지 않을 것이며 내가 본 것으로부터 : 나는 그것을 보았지만 그것은 매우 일반적인 구조는 아닙니다.

200KLOC 코드베이스에서 이것이 정확히 제로 시간에 발생합니다 (하지만 우리는 다른 사람들이 완벽하게 정상이라고 생각할 정도로 정확히 제로 시간이 발생하는 나쁜 관행을 고려하는 다른 많은 것들을 가지고 있습니다 ...).


몇 가지 사용 예를 추가 할 수 있습니까? 나는 얼마 전에 비슷한 것을 테스트했지만이 구조를 사용하여 무엇을 얻을 수 있는지 이해하지 못했습니다.
Roman

@Roman : 글쎄요, 나는 어떤 프로젝트에서 이것을 만났던 것을 기억합니다 (상대적으로 깨끗한 프로젝트는 내가 추가 할 것이지만 그들은 내 것이 아닙니다).하지만 그것이 정말로 깨끗한 지 아닌지 모르겠습니다. 나는 내가 본 것과 같은 작은 예제를 추가했지만 다시 한 번 : 이것은 내 코드가 아니었고 그 구조를 사용하고 있지 않기 때문에 유효한 예제를 생각 해낼 수있는 가장 자격이없는 사람이 아니다. :) IIRC 예를 들어, 클래스의 내부는 항상 지명되었다 StateChecker : 전화를 걸고 항상 같을 것이다 A.StateChecker.check의 (a) 또는 그런 일.
SyntaxT3rr0r 2010 년

8
"" 정적 내부 클래스 " 와 같은 것은 없다"고 말하면 " 자바 인터페이스 내에 중첩 된 클래스 또는 내부 클래스를 모두 만들 있습니다 "라는 대답 은 근본적으로 잘못되었습니다. 좁혀진 정의를 사용하면 interfaces 는 내부 클래스를 가질 수 없습니다 . 의 중첩 클래스 의 static수정자를 생략 할 수 interface있지만 여전히 내부 클래스가 아닌 중첩 클래스입니다.
Holger

6
이 대답은 틀 렸습니다. 인터페이스는 정적 중첩 클래스를 가질 수 있지만 내부 클래스는 가질 수 없습니다.
Paul Boddington 2015 년

1
@PaulBoddington 당신이 맞아요. '정적'을 제거하더라도 B클래스는 내부 클래스가 아닌 정적 중첩 클래스입니다. 인터페이스는 특별한 대우를받습니다. "인터페이스의 멤버 클래스는 암시 적으로 정적이므로 내부 클래스로 간주되지 않습니다." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough

109

예, 인터페이스 내부에 클래스를 가질 수 있습니다. 사용의 한 가지 예는 다음과 같습니다.

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

여기서 코드에는 나중에 getKeyEvents ()와 같은 메서드 정의에서 사용되는 이벤트 객체에 대한 정보를 캡슐화하기위한 두 개의 중첩 클래스가 있습니다. 입력 인터페이스 내부에두면 응집력이 향상됩니다.


3
@Levit 방금 구현 된 클래스가 어떻게 생겼는지 궁금하십니까?
overexchange

1
위의 사용법에 대한 구현을보고 싶습니다. 감사합니다.
Prakash K

45

IMHO라는 유효한 용도는 둘러싸는 인터페이스 메서드에서 수신하거나 반환하는 개체를 정의하는 것입니다. Tiply 데이터 보유 구조. 이런 식으로 객체가 해당 인터페이스에만 사용되는 경우 더 일관된 방식으로 작업을 수행 할 수 있습니다.

예를 들어 :

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

하지만 어쨌든 ... 그것은 단지 맛의 문제입니다.


35

Java 7 사양 에서 인용 :

인터페이스에는 멤버 형식 선언 (§8.5)이 포함될 수 있습니다.

인터페이스의 멤버 형식 선언은 암시 적으로 정적이며 공용입니다. 이러한 수정 자 중 하나 또는 둘 다를 중복으로 지정할 수 있습니다.

Java 인터페이스 내에서 비 ​​정적 클래스를 선언하는 것은 불가능합니다.


감사합니다. 이것은 아마도 가장 간결한 대답 일 것입니다.
Joseph

1
이것이 제가 찾고 있던 대답입니다.하지만 OP는 몇 가지 질문을합니다.
Charlie Wallace

11

흥미로운 사용 사례는 https://stackoverflow.com/a/3442218/454667 (단일 클래스 상속 문제를 극복하기 위해)에 설명 된대로 내부 클래스를 통해 인터페이스 메서드에 일종의 기본 구현을 제공하는 것입니다 .


이것이 바로 개인 멤버 클래스가 의미가있는 이유입니다.
Vincent

7

확실히 가능하며, 유용하다고 생각되는 한 가지 경우는 인터페이스가 사용자 지정 예외를 throw해야하는 경우입니다. 관련 인터페이스로 예외를 유지하면 사소한 예외 파일 더미로 소스 트리를 버리는 것보다 종종 깔끔하다고 생각합니다.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

7

예, 인터페이스 내부에 정적 클래스 정의를 가질 수 있지만이 기능의 가장 유용한 측면은 enum 유형 (특수한 종류의 정적 클래스)을 사용할 때입니다. 예를 들어 다음과 같은 것을 가질 수 있습니다.

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}


1

다른 구현 동작과 같은 더 복잡한 구성을 원할 때 다음을 고려하십시오.

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

이것이 귀하의 인터페이스이며 이것이 구현자가 될 것입니다.

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

일부 정적 구현을 ​​제공 할 수 있지만 혼란 스럽지는 않습니다. 모르겠습니다.


0

나는 이러한 유형의 구조에 대한 사용을 발견했습니다.

  1. 이 구성을 사용하여 모든 정적 최종 상수를 정의하고 그룹화 할 수 있습니다.
  2. 클래스에서 구현할 수있는 인터페이스이기 때문입니다.

그룹화 된 모든 상수에 액세스 할 수 있습니다. 이 경우 클래스 이름이 네임 스페이스 역할을합니다.


0

이 인터페이스를 구현하는 개체의 공통 기능에 대한 "Helper"정적 클래스를 만들 수도 있습니다.

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

0

지금 당장 필요 해요. 여러 메서드에서 고유 한 클래스를 반환하는 것이 편리한 인터페이스가 있습니다. 이 클래스는이 인터페이스의 메서드로부터의 응답을위한 컨테이너로만 의미가 있습니다.

따라서이 인터페이스 만이 결과 컨테이너 클래스가 생성되는 유일한 위치 여야하므로이 인터페이스와 만 연결된 정적 중첩 클래스 정의를 갖는 것이 편리합니다.


0

예를 들어 Groovy의 특성 (구현 된 메서드가있는 인터페이스와 유사한). 모든 메소드가 구현되는 내부 클래스를 포함하는 인터페이스로 컴파일됩니다.

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