programing

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

goodcopy 2022. 8. 1. 21:56
반응형

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

이 토픽에서는 대부분의 내용을 설명하고 있습니다.인터페이스에서 스태틱 메서드를 선언할 수 없는 이유는 무엇입니까?

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

위의 코드는 적어도 Eclipse에서는 "Interface method ITest.test()의 부정 수식자; 퍼블릭&abstract만 허용됩니다."라는 오류를 표시합니다.

여기에는 몇 가지 문제가 있습니다.첫 번째는 정의하지 않고 스태틱 방식을 선언하는 문제입니다.이게 바로 와의 차이점입니다.

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

그리고.

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

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

Java는 후자를 허용할 수 있으며, 실제로 Java 8부터는 후자를 허용합니다.

인터페이스에서 정적 메서드를 사용할 수 없는 이유는 Java가 정적 참조를 해결하는 방식에 있습니다.Java는 정적 메서드를 실행하려고 할 때 클래스의 인스턴스를 검색하지 않습니다.이는 정적 메서드는 인스턴스에 의존하지 않기 때문에 클래스 파일에서 바로 실행할 수 있기 때문입니다.인터페이스의 모든 메서드가 추상적이기 때문에 VM은 실행할 수 있도록 정적 메서드의 배후에 있는 코드를 찾기 위해 인터페이스의 특정 구현을 찾아야 합니다.이는 정적 메서드 해결의 작동 방식과 모순되며 언어에 불일치를 가져옵니다.

제가 당신의 질문에 예를 들어 답하겠습니다.정적 메서드가 추가된 수학 수업이 있다고 가정합니다.이 메서드를 다음과 같이 부릅니다.

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을 명시적으로 사용하지 않으면 인터페이스의 메서드는 여전히 기본 공개 추상화입니다.

당신의 질문에 대한 매우 훌륭하고 간결한 답변이 여기 있습니다. (그것은 매우 알기 쉽게 설명하는 방법이라 생각했기 때문에 여기서부터 연결시키고 싶습니다.)

인터페이스의 스태틱메서드는 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...을 사용하다

인터페이스는 유형이 아닌 개체에 적용되는 다형성에 사용됩니다.따라서 (이미 기술한 바와 같이) 스태틱인터페이스 멤버를 갖는 것은 의미가 없습니다.

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 수식어와 추상 수식어의 조합이 잘못되었습니다.

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

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

정적 메서드의 동작을 변경할 하위 클래스의 추상 멤버에게 구현을 제공해야 합니다. 또한 추상이라고 선언된 기본 클래스로, 올바르지 않습니다.

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

Java 8에서는 인터페이스에 스태틱메서드를 설정할 수 있게 되었습니다.

예를 들어 Comparator에는 static natural Order() 메서드가 있습니다.

인터페이스에 실장을 할 수 없는 요건도 완화되었습니다.이제 인터페이스는 "기본" 메서드 구현을 선언할 수 있습니다.이것은 1개의 예외를 제외하고 일반 구현과 같습니다.인터페이스에서 기본 구현과 슈퍼클래스에서 일반 구현을 모두 상속하면 슈퍼클래스의 구현이 항상 우선됩니다.

코드 예제가 도움이 될 수도 있습니다.C#을 사용할 예정이지만, 따라갈 수 있을 것입니다.

IPayable이라고 하는 인터페이스가 있다고 합시다.

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

이 인터페이스를 실장하는 구체적인 클래스는 2개 있습니다.

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

이제 인터페이스가 얼마나 유용한지 알게 되었습니다.

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

IPayable을 계정에서 루프할 때 지불을 정지한 경우, BusinessAcount 또는 CustomerAccount 중 어느 쪽에 지불을 호출해야 하는지 알 수 없습니다.

언급URL : https://stackoverflow.com/questions/21817/why-cant-i-declare-static-methods-in-an-interface

반응형