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

StackOverflow https://stackoverflow.com/questions/21817

문제

이 주제는 대부분의 내용을 담고 있습니다. 인터페이스에서 정적 메서드를 선언할 수 없는 이유는 무엇입니까?

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

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

도움이 되었습니까?

해결책

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

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

그리고

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

첫 번째는 다음과 같은 이유로 불가능합니다. 에스포 언급:어떤 구현 클래스가 올바른 정의인지 알 수 없습니다.

자바 ~할 수 있었다 후자를 허용하십시오.실제로 Java 8부터 가능합니다!

다른 팁

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

귀하의 질문에 예를 들어 답변해 드리겠습니다.정적 메서드 add가 포함된 Math 클래스가 있다고 가정해 보겠습니다.이 메서드를 다음과 같이 호출합니다.

Math.add(2, 3);

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

그 이유는 Java가 다중 상속을 허용하지 않는다는 설계 원칙에 있습니다.다중 상속의 문제는 다음 예제로 설명할 수 있습니다.

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

이제 C.x()를 호출하면 어떻게 될까요?A.x() 또는 B.x()가 실행됩니까?다중 상속이 있는 모든 언어는 이 문제를 해결해야 합니다.

인터페이스는 Java에서 일종의 제한된 다중 상속을 허용합니다.위의 문제를 피하기 위해 메소드를 갖는 것이 허용되지 않습니다.인터페이스와 정적 메서드에서 동일한 문제를 살펴보면 다음과 같습니다.

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

여기서도 같은 문제가 발생합니다. C.x()를 호출하면 어떻게 되나요?

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

이제 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 키워드를 명시적으로 사용하여 Default 메소드 및 Static 메소드로 만들지 않으면 기본적으로 여전히 공개 추상입니다.

귀하의 질문에 대한 매우 훌륭하고 간결한 답변이 있습니다 여기.(설명이 너무 간단해서 여기에서 연결하고 싶습니다.)

인터페이스의 정적 메소드가 다음에서 지원될 수 있는 것 같습니다. 자바 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..., 그러면 모호한 문제를 제거할 수 있습니다.

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

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);

}

수정자의 잘못된 조합:정적이고 추상적인

클래스의 멤버가 static으로 선언되면 객체를 생성하지 않고도 해당 클래스에 국한된 클래스 이름으로 사용할 수 있습니다.

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

정적 메서드의 동작을 변경하려는 하위 클래스에 있는 클래스의 추상 멤버에 대한 구현을 제공해야 합니다. 또한 기본 클래스에 국한된 추상으로 선언되어 올바르지 않습니다.

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

와 함께 자바 8, 인터페이스는 이제 정적 메소드를 가질 수 있습니다.

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

인터페이스가 구현을 가질 수 없다는 요구 사항도 완화되었습니다.이제 인터페이스는 한 가지 예외를 제외하고 일반 구현과 유사한 "기본" 메서드 구현을 선언할 수 있습니다.인터페이스의 기본 구현과 슈퍼클래스의 일반 구현을 모두 상속하는 경우 슈퍼클래스의 구현이 항상 우선순위를 갖습니다.

아마도 코드 예제가 도움이 될 것입니다. 저는 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);
}

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

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

지불을 정적으로 만든 경우 accountToPay에서 IPayable을 반복할 때 BusinessAcount 또는 CustomerAccount에서 지불을 호출해야 하는지 알아낼 방법이 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top