인터페이스에서 정적 메소드를 선언 할 수없는 이유는 무엇입니까?


150

주제는 그 대부분을 말합니다-인터페이스에서 정적 메소드를 선언 할 수 없다는 이유는 무엇입니까?

public interface ITest {
    public static String test();
}

위 코드는 적어도 Eclipse에서 다음과 같은 오류를 발생시킵니다. "인터페이스 메소드 ITest.test ()의 잘못된 수정 자; 공개 및 요약 만 허용됩니다."


2
결함이 있기 때문에 Espo의 답변을 수락하지 마십시오. 인터페이스에는 정적 메소드의 구현을 포함 할 수있는 클래스 파일이 있습니다 (Java 디자이너가이를 허용하는 경우). 정적 메소드의 구현을 해결하는 데 아무런 문제가 없습니다. 다른 정적 클래스와 똑같이 작동합니다.
Mnementh

"erickson"의 답변에 동의합니다. stackoverflow.com/questions/512877/…
Maverick

9
이것은 Java 8 btw에서 사용할 수 있습니다.
m0skit0

1
@Vadorequest GIYF 그러나 어쨌든 여기를 확인하십시오
m0skit0

답변:


85

여기에 몇 가지 문제가 있습니다. 첫 번째는 정적 메소드를 정의하지 않고 선언하는 문제입니다. 이것은 차이점입니다

public interface Foo {
  public static int bar();
}

public interface Foo {
  public static int bar() {
    ...
  }
}

첫 번째는 Espo가 언급 한 이유로 불가능 합니다. 어떤 구현 클래스가 올바른 정의인지 모릅니다.

자바 는 후자를 허용 수있다. 실제로 Java 8부터 시작합니다!


2
그렇습니다-기술적이지 않습니다. 내가 원하는 이유입니다. 인터페이스에서 클래스를 구현하여 쉽게 재사용 할 수있는 다른 "인터페이스"메서드 만 참조하는 인터페이스에는 정적 "구현"메서드가있을 수 있습니다. 그러나 인터페이스에 정적 클래스 를 선언 할 수 있으므로 MyInterface.Impl.doIt (MyInterface i, Object [] args) {...}
peterk

9
Java 8부터는 static에서 메소드를 정의 할 수 있습니다 interface. 방법은이어야합니다 public.
Olivier Grégoire

4
@ OlivierGrégoire ... 그리고 상속받지 못했습니다. 이것이 핵심입니다.
William F. Jameson

1
좋은 대답이지만 ROFLMAO xD는 "상당히 동일합니다."
Timo

44

인터페이스에 정적 메소드를 가질 수없는 이유는 Java가 정적 참조를 분석하는 방식에 있습니다. Java는 정적 메소드를 실행하려고 할 때 클래스의 인스턴스를 찾지 않습니다. 정적 메소드는 인스턴스에 종속되지 않으므로 클래스 파일에서 직접 실행될 수 있기 때문입니다. 인터페이스의 모든 메소드가 추상적이라는 점에서 VM은 정적 메소드 뒤의 코드를 찾아서 실행될 수 있도록 인터페이스의 특정 구현을 찾아야합니다. 그러면 정적 메소드 분석이 작동하는 방식과 모순되며 언어에 불일치가 발생합니다.


3
이 설명은 문제를 설명하지 않습니다. 모든 인터페이스에는 자체 클래스 파일이 있으며 정적 메소드를 포함 할 수 있습니다. 따라서 특정 구현에 대한 조회가 필요하지 않습니다.
Mnementh

Java의 모든 인터페이스 유형이 자체 파일 내에있는 것은 아니며 JLS를 준수하지 않아야합니다. 또한 JLS는 클래스가 항상 파일 시스템과 함께 저장되어야한다고 명시하지 않습니다.
Vlad Gudim

4
@Totophil : 인터페이스는 단일 java 파일에 없어야하지만 컴파일 후에는 고유 한 클래스 파일이 있습니다. 그게 내가 쓴 것입니다.
Mnementh

18

예를 들어 질문에 대답하겠습니다. 정적 메소드 add를 가진 Math 클래스가 있다고 가정하십시오. 이 방법을 다음과 같이 호출합니다.

Math.add(2, 3);

Math가 클래스 대신 인터페이스 인 경우 정의 된 함수를 가질 수 없습니다. 따라서 Math.add (2, 3)과 같은 것을 말하면 의미가 없습니다.


11

그 이유는 java가 다중 상속을 허용하지 않기 때문에 디자인 원칙에 있습니다. 다중 상속 문제는 다음 예제를 통해 설명 할 수 있습니다.

public class A {
   public method x() {...}
}
public class B {
   public method x() {...}
}
public class C extends A, B { ... }

이제 Cx ()를 호출하면 어떻게됩니까? Ax () 또는 Bx ()가 실행됩니까? 상속이 여러 개인 모든 언어는이 문제를 해결해야합니다.

인터페이스는 Java에서 일종의 제한된 다중 상속을 허용합니다. 위의 문제를 피하기 위해 메소드를 사용할 수 없습니다. 인터페이스와 정적 메소드에 대해 동일한 문제를 보면 :

public interface A {
   public static method x() {...}
}
public interface B {
   public static method x() {...}
}
public class C implements A, B { ... }

Cx ()를 호출하면 어떻게됩니까?


downvote에 대한 이유가 있습니까? 설명이 좋을 것입니다.
Mnementh

나는 downvoter가 아니지만 비 정적 메소드에도 유효하지 않습니까?
nawfal

여기 두 가지 가능성이 있습니다. 메소드는 구현되거나 선언 만 가능합니다. 정적 방법을 구현해야한다는 것을 이해했습니다. 그 의미에서 나는 내 대답에 제시된 문제에 직면한다. 그렇게하지 않으면 Espo가 설명 한 문제가 발생합니다. 정적 메소드가 구현되었다고 가정했기 때문에 이해하지 못했습니다. 이런 이유로 정적 추상 메소드를 선언 할 수 없으며 시도해보십시오. 컴파일러가 불평합니다.
Mnementh

좋아, 구현 부분을 잊어 버려라. 문제는 우리가 선언 할 수없는 이유입니다. 그렇습니다. 컴파일러는 불만을 제기 할 것이며 왜 그게 문제입니까? 나는 당신이 대답하지 않았다고 생각합니다.
nawfal

1
인터페이스에 A포함 int x(int z);하고 인터페이스에 B포함 시키는 것보다 더 나쁜 상황 은 string x(int x);어떻습니까? x(3)인터페이스 C 의 의미는 무엇입니까 ?
supercat

7

정적 메소드는 인스턴스 메소드가 아닙니다. 인스턴스 컨텍스트가 없으므로 인터페이스에서 구현하는 것이 의미가 없습니다.


5

이제 Java8을 사용하면 인터페이스에서 정적 메소드도 정의 할 수 있습니다.

interface X {
    static void foo() {
       System.out.println("foo");
    }
}

class Y implements X {
    //...
}

public class Z {
   public static void main(String[] args) {
      X.foo();
      // Y.foo(); // won't compile because foo() is a Static Method of X and not Y
   }
}

참고 : 키워드를 default / static 키워드로 명시 적으로 사용하여 기본 메소드 및 정적 메소드를 지정하지 않으면 인터페이스의 메소드는 기본적으로 여전히 공개 추상입니다.


4

귀하의 질문에 매우 훌륭하고 간결한 답변이 있습니다 . (내가 여기에서 연결하고 싶다는 것을 설명하는 아주 간단한 방법으로 놀랐습니다.)


이것은 질문에 대한 답변이 아니며 기껏해야 의견이어야합니다.
CubeJockey

3

인터페이스의 정적 메소드가 Java 8 에서 지원 될 수있는 것 같습니다. 내 솔루션은 내부 클래스에서 정의하는 것입니다.

interface Foo {
    // ...
    class fn {
        public static void func1(...) {
            // ...
        }
    }
}

주석에도 동일한 기술을 사용할 수 있습니다.

public @interface Foo {
    String value();

    class fn {
        public static String getValue(Object obj) {
            Foo foo = obj.getClass().getAnnotation(Foo.class);
            return foo == null ? null : foo.value();
        }
    }
}

내부 클래스는 항상의 형태로 액세스해야 Interface.fn...하는 대신 Class.fn..., 다음, 당신은 모호한 문제의 제거 얻을 수 있습니다.


2

인터페이스는 유형이 아닌 객체에 적용되는 다형성에 사용됩니다. 따라서 (이미 언급했듯이) 정적 인터페이스 멤버를 갖는 것은 의미가 없습니다.


일부 반사적 맥락에서 거의 의미가있는 것 같습니다
Cruncher

1

Java 8 인터페이스에서 정적 메소드를 사용할 수있는 세상이 바뀌었지만 강제로 구현해야합니다.

public interface StaticMethodInterface {
public static int testStaticMethod() {
    return 0;
}

/**
 * Illegal combination of modifiers for the interface method
 * testStaticMethod; only one of abstract, default, or static permitted
 * 
 * @param i
 * @return
 */
// public static abstract int testStaticMethod(float i);

default int testNonStaticMethod() {
    return 1;
}

/**
 * Without implementation.
 * 
 * @param i
 * @return
 */
int testNonStaticMethod(float i);

}


0

수정 자의 잘못된 조합 : 정적 및 추상

클래스의 멤버가 정적으로 선언 된 경우 객체를 만들지 않고 해당 클래스에 한정된 클래스 이름과 함께 사용할 수 있습니다.

클래스의 멤버가 abstract로 선언 된 경우 클래스를 abstract로 선언해야하며 상속 된 클래스 (Sub-Class)에서 추상 멤버의 구현을 제공해야합니다.

정적 메소드의 동작을 변경하려는 서브 클래스의 클래스 추상 멤버에 구현을 제공해야합니다. 기본 클래스에 국한된 abstract로도 선언되어 있습니다.


이 질문에 어떻게 대답합니까? 수업에 대해 쓰면서 OP가 인터페이스에 대해 물었습니다.
Lucky

0

정적 메소드는 상속 될 수 없기 때문에. 따라서 인터페이스에 배치하지 마십시오. 인터페이스는 기본적으로 모든 가입자가 따라야하는 계약입니다. 인터페이스에 정적 메소드를 배치하면 구독자가 메소드를 구현해야합니다. 정적 메소드를 상속 할 수 없다는 사실과 모순됩니다.


정적 메소드는 항상 상속되지만 재정의 할 수는 없습니다.
Akki

0

자바 (8) , 인터페이스는 이제 정적 메서드를 가질 수 있습니다.

예를 들어 Comparator에는 정적 naturalOrder () 메서드가 있습니다.

인터페이스가 구현을 가질 수 없다는 요구 사항도 완화되었습니다. 인터페이스는 이제 "기본"메소드 구현을 선언 할 수 있는데, 한 가지 예외는 예외입니다. 인터페이스에서 기본 구현과 수퍼 클래스에서 일반 구현을 모두 상속하면 수퍼 클래스 구현이 항상 우선합니다.


세상에! 우리는 10 살짜리 질문에 대답하는 (그리고 나, 주석) 진지한 프로그래머가 있습니다.
Mohamed Anees A

나는 날짜를
몰랐다

ㅋ! 문제 없어요!
Mohamed Anees A

-2

아마도 코드 예제가 도움이 될 것입니다 .C #을 사용하려고하지만 따라 할 수 있어야합니다.

IPayable이라는 인터페이스를 가지고 있다고 가정하자

public interface IPayable
{
    public Pay(double amount);
}

이제이 인터페이스를 구현하는 두 가지 구체적인 클래스가 있습니다.

public class BusinessAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

public class CustomerAccount : IPayable
{
    public void Pay(double amount)
    {
        //Logic
    }
}

이제 우리는 다양한 계정 모음을 가지고 있다고 가정합니다.이를 위해 IPayable 유형의 일반 목록을 사용합니다.

List<IPayable> accountsToPay = new List<IPayable>();
accountsToPay.add(new CustomerAccount());
accountsToPay.add(new BusinessAccount());

이제 모든 계정에 $ 50.00를 지불하려고합니다.

foreach (IPayable account in accountsToPay)
{
    account.Pay(50.00);
}

이제 인터페이스가 얼마나 유용한 지 알 수 있습니다.

인스턴스화 된 객체에만 사용됩니다. 정적 클래스에는 없습니다.

고정 지불을 한 경우 accountsToPay에서 IPayable을 통해 루핑 할 때 BusinessAcount 또는 CustomerAccount에서 pay를 호출해야하는지 여부를 알 수있는 방법이 없습니다.


이 예제에서는 정적 메소드가 의미가 없다고해서 모든 예제에서 의미가없는 것은 아닙니다. 귀하의 예에서 IPayable 인터페이스에 추가 할 지불금 수를 추적하는 정적 메소드 "IncrementPayables"가있는 경우 실제 사용 사례가됩니다. 물론 항상 추상 클래스를 사용할 수는 있지만 그게 해결 한 것은 아닙니다. 예제 자체는 인터페이스의 정적 메소드를 손상시키지 않습니다.
Cruncher
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.