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


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.