주제는 그 대부분을 말합니다-인터페이스에서 정적 메소드를 선언 할 수 없다는 이유는 무엇입니까?
public interface ITest {
public static String test();
}
위 코드는 적어도 Eclipse에서 다음과 같은 오류를 발생시킵니다. "인터페이스 메소드 ITest.test ()의 잘못된 수정 자; 공개 및 요약 만 허용됩니다."
주제는 그 대부분을 말합니다-인터페이스에서 정적 메소드를 선언 할 수 없다는 이유는 무엇입니까?
public interface ITest {
public static String test();
}
위 코드는 적어도 Eclipse에서 다음과 같은 오류를 발생시킵니다. "인터페이스 메소드 ITest.test ()의 잘못된 수정 자; 공개 및 요약 만 허용됩니다."
답변:
여기에 몇 가지 문제가 있습니다. 첫 번째는 정적 메소드를 정의하지 않고 선언하는 문제입니다. 이것은 차이점입니다
public interface Foo {
public static int bar();
}
과
public interface Foo {
public static int bar() {
...
}
}
첫 번째는 Espo가 언급 한 이유로 불가능 합니다. 어떤 구현 클래스가 올바른 정의인지 모릅니다.
자바 는 후자를 허용 할 수있다. 실제로 Java 8부터 시작합니다!
static
에서 메소드를 정의 할 수 있습니다 interface
. 방법은이어야합니다 public
.
인터페이스에 정적 메소드를 가질 수없는 이유는 Java가 정적 참조를 분석하는 방식에 있습니다. Java는 정적 메소드를 실행하려고 할 때 클래스의 인스턴스를 찾지 않습니다. 정적 메소드는 인스턴스에 종속되지 않으므로 클래스 파일에서 직접 실행될 수 있기 때문입니다. 인터페이스의 모든 메소드가 추상적이라는 점에서 VM은 정적 메소드 뒤의 코드를 찾아서 실행될 수 있도록 인터페이스의 특정 구현을 찾아야합니다. 그러면 정적 메소드 분석이 작동하는 방식과 모순되며 언어에 불일치가 발생합니다.
그 이유는 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 ()를 호출하면 어떻게됩니까?
A
포함 int x(int z);
하고 인터페이스에 B
포함 시키는 것보다 더 나쁜 상황 은 string x(int x);
어떻습니까? x(3)
인터페이스 C 의 의미는 무엇입니까 ?
이제 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);
}
수정 자의 잘못된 조합 : 정적 및 추상
클래스의 멤버가 정적으로 선언 된 경우 객체를 만들지 않고 해당 클래스에 한정된 클래스 이름과 함께 사용할 수 있습니다.
클래스의 멤버가 abstract로 선언 된 경우 클래스를 abstract로 선언해야하며 상속 된 클래스 (Sub-Class)에서 추상 멤버의 구현을 제공해야합니다.
정적 메소드의 동작을 변경하려는 서브 클래스의 클래스 추상 멤버에 구현을 제공해야합니다. 기본 클래스에 국한된 abstract로도 선언되어 있습니다.
로 자바 (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);
}
이제 인터페이스가 얼마나 유용한 지 알 수 있습니다.
인스턴스화 된 객체에만 사용됩니다. 정적 클래스에는 없습니다.
고정 지불을 한 경우 accountsToPay에서 IPayable을 통해 루핑 할 때 BusinessAcount 또는 CustomerAccount에서 pay를 호출해야하는지 여부를 알 수있는 방법이 없습니다.