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

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

  •  21-08-2019
  •  | 
  •  

문제

편집하다: Java 8부터는 이제 인터페이스에서 정적 메소드가 허용됩니다.

예는 다음과 같습니다.

public interface IXMLizable<T>
{
  static T newInstanceFromXML(Element e);
  Element toXMLElement();
}

물론 이것은 작동하지 않습니다.그런데 왜 안되죠?

가능한 문제 중 하나는 전화할 때 어떤 일이 발생하는지입니다.

IXMLizable.newInstanceFromXML(e);

이 경우에는 빈 메서드(예:{}).모든 하위 클래스는 정적 메서드를 구현해야 하므로 정적 메서드를 호출해도 괜찮습니다.그렇다면 왜 이것이 가능하지 않습니까?

편집하다: '자바는 원래 그런 거니까'보다 더 심오한 답을 찾고 있는 것 같아요.

정적 메서드를 덮어쓸 수 없는 특별한 기술적 이유가 있나요?즉, Java 설계자가 인스턴스 메소드를 재정의 가능하게 만들고 정적 메소드는 불가능하게 만들기로 결정한 이유는 무엇입니까?

편집하다: 내 디자인의 문제점은 코딩 규칙을 시행하기 위해 인터페이스를 사용하려고 한다는 것입니다.

즉, 인터페이스의 목표는 두 가지입니다.

  1. 나는 이를 구현하는 클래스를 XML 요소(다형성을 사용하여 잘 작동함)로 변환할 수 있는 IXMLizing 인터페이스를 원합니다.

  2. IXMLized 인터페이스를 구현하는 클래스의 새 인스턴스를 만들려는 경우 newInstanceFromXML(Element e) 정적 생성자가 있다는 것을 항상 알 수 있습니다.

인터페이스에 주석을 추가하는 것 외에 이를 보장할 수 있는 다른 방법이 있습니까?

도움이 되었습니까?

해결책

Java 8은 정적 인터페이스 방법을 허용합니다

Java 8, 인터페이스 ~할 수 있다 정적 방법이 있습니다. 또한 구체적인 인스턴스 방법을 가질 수 있지만 인스턴스 필드는 아닙니다.

여기에는 실제로 두 가지 질문이 있습니다.

  1. 옛날에 왜 인터페이스가 정적 메소드를 포함 할 수 없었습니까?
  2. 정적 메소드를 무시할 수없는 이유는 무엇입니까?

인터페이스의 정적 메소드

인터페이스가 이전 버전에서 정적 메소드를 가질 수 없었던 강력한 기술적 이유는 없었습니다. 이것은 포스터로 잘 요약했습니다 중복 질문의. 정적 인터페이스 방법은 처음에 고려되었습니다 작은 언어 변화, 그리고 거기에있었습니다 공식 제안 Java 7에 추가하려면 나중에 예기치 않은 합병증으로 인해 떨어졌습니다.

마지막으로 Java 8은 기본 구현을 통해 정적 인터페이스 방법과 재정의 가능한 인스턴스 방법을 도입했습니다. 그래도 인스턴스 필드를 가질 수는 없습니다. 이 기능은 Lambda Expression Support의 일부이며, 이들에 대해 더 많이 읽을 수 있습니다. JSR 335의 파트 H.

정적 메소드를 우선합니다

두 번째 질문에 대한 답은 조금 더 복잡합니다.

정적 방법은 컴파일 시간에 해결할 수 있습니다. 동적 디스패치는 컴파일러가 객체의 콘크리트 유형을 결정할 수 없으므로 호출 할 메소드를 해결할 수없는 방법에 대해 의미가 있습니다. 그러나 정적 방법을 호출하려면 클래스가 필요하며 그 수업은 알려져 있기 때문에 정적으로- 컴파일 시간 중 —Dynamic Dispatch는 불필요합니다.

여기서 무슨 일이 일어나고 있는지 이해하려면 인스턴스 방법의 작동 방식에 대한 약간의 배경 지식이 있습니다. 실제 구현이 상당히 다르다고 확신하지만, 메서드 파견 개념을 설명하겠습니다.이 개념은 행동을 정확하게 관찰했습니다.

각 클래스에는 메소드 서명 (이름 및 매개 변수 유형)을 맵핑하여 메소드를 구현하기 위해 실제 코드 덩어리에 맵핑하는 해시 테이블이있는 척하십시오. 가상 머신이 인스턴스에서 메소드를 호출하려고 시도하면 클래스의 객체를 쿼리하고 클래스 테이블에서 요청 된 서명을 찾습니다. 방법 본문이 발견되면 호출됩니다. 그렇지 않으면, 수업의 부모 클래스가 얻어지고 조회가 반복됩니다. 이것은 메소드가 발견 될 때까지 진행되거나 더 이상 부모 수업이 없을 때까지 진행됩니다. NoSuchMethodError.

슈퍼 클래스와 서브 클래스에 동일한 메소드 서명에 대한 테이블에 항목이 있으면 서브 클래스의 버전이 먼저 발생하고 슈퍼 클래스의 버전이 사용되지 않습니다. 이는 "재정의"입니다.

이제 객체 인스턴스를 건너 뛰고 서브 클래스로 시작한다고 가정 해 봅시다. 해상도는 위와 같이 진행될 수있어 일종의 "비정기 가능한"정적 방법을 제공 할 수 있습니다. 그러나 컴파일러가 클래스에 대해 지정되지 않은 유형의 객체를 쿼리하기 위해 런타임까지 기다리지 않고 컴파일러가 알려진 클래스에서 시작하기 때문에 해상도는 모두 컴파일 타임에 발생할 수 있습니다. 정적 메소드를 "재정의"하는 데는 아무런 의미가 없습니다. 원하는 버전이 포함 된 클래스를 항상 지정할 수 있기 때문입니다.


생성자 "인터페이스"

다음은 최근 질문에 대한 편집을 해결하기위한 조금 더 중요한 자료입니다.

각 구현에 대한 생성자와 같은 방법을 효과적으로 요구하는 것 같습니다. IXMLizable. 1 분 동안 인터페이스로 이것을 시행하는 것을 잊고이 요구 사항을 충족하는 수업이있는 척하십시오. 어떻게 사용 하시겠습니까?

class Foo implements IXMLizable<Foo> {
  public static Foo newInstanceFromXML(Element e) { ... }
}

Foo obj = Foo.newInstanceFromXML(e);

콘크리트 유형의 이름을 명시 적으로 이름을 지정해야하므로 Foo 새 객체를 "구성"할 때 컴파일러는 실제로 필요한 공장 방법이 있는지 확인할 수 있습니다. 그렇지 않다면 무엇입니까? 내가 구현할 수 있다면 IXMLizable "생성자"가 부족하고 인스턴스를 생성하여 코드로 전달합니다. ~이다 an IXMLizable 필요한 모든 인터페이스와 함께.

건설은 구현의 일부이며 인터페이스가 아닙니다. 인터페이스에서 성공적으로 작동하는 모든 코드는 생성자를 신경 쓰지 않습니다. 생성자에 관심이있는 모든 코드는 어쨌든 콘크리트 유형을 알아야하며 인터페이스를 무시할 수 있습니다.

다른 팁

이것은 이미 묻고 대답했습니다. 여기

내 대답을 복제하려면 :

인터페이스에서 정적 메소드를 선언 할 포인트는 없습니다. 일반 호출 Myinterface.staticMethod ()에 의해 실행할 수 없습니다. 구현 클래스 MyImplementor.staticMethod ()을 지정하여 호출하는 경우 실제 클래스를 알아야하므로 인터페이스에 포함되어 있는지 여부는 관련이 없습니다.

더 중요한 것은 정적 방법이 무시되지 않으며, 시도하는 경우 :

MyInterface var = new MyImplementingClass();
var.staticMethod();

정적 규칙에 따르면 선언 된 유형의 VAR에 정의 된 방법은 실행되어야한다고 말합니다. 이것은 인터페이스이므로 불가능합니다.

"result = myinterface.staticMethod ()"를 실행할 수없는 이유는 myinterface에 정의 된 메소드의 버전을 실행해야하기 때문입니다. 그러나 MyInterface에는 인터페이스이기 때문에 정의 된 버전은 없습니다. 정의상 코드가 없습니다.

당신은 이것이 "Java가 그렇게하기 때문에"에 해당한다고 말할 수 있지만, 실제로 결정은 다른 디자인 결정의 논리적 결과이며 매우 좋은 이유를 위해 이루어졌습니다.

일반적으로 이것은 공장 패턴을 사용하여 수행됩니다

public interface IXMLizableFactory<T extends IXMLizable> {
  public T newInstanceFromXML(Element e);
}

public interface IXMLizable {
  public Element toXMLElement();
}

출현으로 Java 8 이제 글을 쓸 수 있습니다 기본 그리고 공전 인터페이스의 메소드.docs.oracle/staticmethod

예를 들어:

public interface Arithmetic {

    public int add(int a, int b);

    public static int multiply(int a, int b) {
        return a * b;
    }
}
public class ArithmaticImplementation implements Arithmetic {

    @Override
    public int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int result = Arithmetic.multiply(2, 3);
        System.out.println(result);
    }
}

결과 : 6

팁 : 정적 인터페이스 메소드를 호출하는 것은 모든 클래스에서 구현할 필요가 없습니다. 슈퍼 클래스의 정적 메소드에 대한 동일한 규칙이 인터페이스의 정적 메소드에 적용되기 때문에 반드시 발생합니다.

정적 메소드는 서브 클래스에서 무시할 수 없으므로 추상적이 될 수 없기 때문입니다. 그리고 인터페이스의 모든 방법은 사실상, 요약.

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

실제로 Java 8에서는 가능합니다.

자바에 따르면 문서:

정적 메소드는 객체가 아닌 클래스와 관련된 클래스와 관련된 메소드입니다.클래스의 모든 인스턴스는 정적 방법을 공유합니다

Java 8에서는 인터페이스가 다음을 가질 수 있습니다. 기본 방법 그리고 정적 메소드.이를 통해 라이브러리에서 도우미 메서드를 더 쉽게 구성할 수 있습니다.별도의 클래스가 아닌 동일한 인터페이스의 인터페이스에 특정한 정적 메서드를 유지할 수 있습니다.

기본 방법의 예:

list.sort(ordering);

대신에

Collections.sort(list, ordering);

정적 메서드의 예( 문서 그 자체):

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

인터페이스는 클래스가 아닌 객체 인스턴스와 본질적으로 연결된 다형성과 관련이 있습니다. 따라서 인터페이스의 맥락에서 정적은 의미가 없습니다.

첫째, 모든 언어 결정은 언어 제작자가 내린 결정입니다. 소프트웨어 엔지니어링 또는 언어 정의 또는 컴파일러 / 통역사 작성의 세계에는 정적 메소드가 인터페이스의 일부가 될 수 없다고 말하는 것이 없습니다. 나는 그들을 위해 몇 가지 언어와 서면 컴파일러를 만들었습니다. 그것은 모두 앉아서 의미있는 의미를 정의하는 것입니다. 컴파일러가 런타임에 대한 방법의 해상도를 연기해야하더라도 인터페이스에서 정적 메소드의 의미론은 현저하게 명확하다고 주장합니다.

둘째, 정적 메소드를 사용한다는 것은 정적 방법을 포함하는 인터페이스 패턴을 가질 수있는 유효한 이유가 있음을 의미합니다. 나는 당신에게 말할 수 없지만 정기적으로 정적 메소드를 사용합니다.

가장 정답은 인터페이스의 정적 방법에 대해 언어가 정의 될 때 인식 된 요구가 없다는 것입니다. Java는 수년에 걸쳐 많은 성장을 해왔으며 이것은 분명히 약간의 관심을 얻은 항목입니다. Java 7을 찾은 것은 언어 변화를 초래할 수있는 관심 수준으로 상승했음을 나타냅니다. 하나는 더 이상 객체를 인스턴스화 할 필요가 없을 때 행복 할 것입니다. 그래서 비 정적 getter 메소드를 호출하여 서브 클래스 인스턴스에서 정적 변수에 액세스 할 수 있습니다 ...

정적 메소드는 인스턴스 방법과 같은 가상이 아니므로 Java 디자이너가 인터페이스에서 원치 않는다고 결정했다고 생각합니다.

그러나 인터페이스 내부에 정적 메소드가 포함 된 클래스를 넣을 수 있습니다. 당신은 그것을 시도 할 수 있습니다!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}
  • "정적 방법을 무시할 수없는 특별한 이유가 있습니까?"

정의를 채워서 그 질문을 다시 생각하겠습니다.

  • "컴파일 타임에 해결 된 메소드를 런타임에 해결할 수없는 특별한 이유가 있습니까?"

또는 인스턴스없이 메소드를 호출하려면 수업을 아는 경우, 내가 가지고 있지 않은 인스턴스를 기반으로 어떻게 해결할 수 있습니까?

댓글 EDIT: As of Java 8, static methods are now allowed in interfaces.

정적 방법은 Java 8이 인터페이스에서 허용되므로 정적 방법이지만 예제는 여전히 작동하지 않습니다. 정적 메소드 만 정의 할 수는 없습니다. 구현해야합니다. 그렇지 않으면 컴파일 오류를 얻을 수 있습니다.

글쎄, 제네릭이 없으면 모든 정적 메소드 호출이 컴파일 시간에 해결되므로 정적 인터페이스는 쓸모가 없습니다. 따라서 그들에게는 실제로 사용되지 않습니다.

제네릭을 사용하면 기본 구현의 유무에 관계없이 사용됩니다. 분명히 재정의가 필요합니다. 그러나 내 추측은 그러한 사용법이 (다른 답변이 장애물로 지적한 것처럼) 매우 OO가 아니었기 때문에 유용하게 구현하는 데 필요한 노력의 가치가있는 것으로 간주되지 않았다.

몇 가지 답변이 우선적 인 정적 방법의 개념과 관련된 문제에 대해 논의했습니다. 그러나 때때로 당신은 그것이 당신이 사용하고 싶은 것처럼 보이는 패턴을 발견하게됩니다.

예를 들어, 값 객체가있는 개체 관계 레이어로 작업하지만 값 객체를 조작하기위한 명령도 있습니다. 여러 가지 이유로 각 값 객체 클래스는 프레임 워크가 명령 인스턴스를 찾을 수 있도록 몇 가지 정적 메소드를 정의해야합니다. 예를 들어, 당신이하는 사람을 만들려면 :

cmd = createCmd(Person.getCreateCmdId());
Person p = cmd.execute();

그리고 신분증으로 사람을로드하려면 당신이 할 것입니다

cmd = createCmd(Person.getGetCmdId());
cmd.set(ID, id);
Person p = cmd.execute();

이것은 상당히 편리하지만 문제가 있습니다. 특히 정적 방법의 존재는 인터페이스에서 시행 될 수 없습니다. 인터페이스의 우선적 인 정적 메소드는 어떻게 든 작동 할 수 있다면 정확히 필요한 것입니다.

EJBS는 홈 인터페이스를 통해이 문제를 해결합니다. 각 물체는 집을 찾는 방법을 알고 있으며 집에는 "정적"방법이 포함되어 있습니다. 이런 식으로 "정적"메소드는 필요에 따라 재정의 할 수 있으며, 콩 인스턴스에 적용되지 않는 메소드와 정상 ( "원격"이라고 함) 인터페이스를 혼란스럽게하지 않습니다. 일반 인터페이스로 "gethome ()"메소드를 지정하십시오. 홈 오브젝트 인스턴스 (싱글 톤 일 수 있음)의 인스턴스를 반환하고 발신자는 모든 사람 객체에 영향을 미치는 작업을 수행 할 수 있습니다.

Why can't I define a static method in a Java interface?

인터페이스의 모든 메소드는 명시 적으로 추상적이므로 정적 메소드가 추상적 일 수 없기 때문에 정적으로 정의 할 수 없습니다.

인터페이스는 정적으로 정리할 수 없습니다 ISomething.member. 인터페이스는 항상 인터페이스의 서브 클래스 인스턴스를 나타내는 변수를 통해 항상 차단됩니다. 따라서 인터페이스 참조는 서브 클래스의 인스턴스없이 어떤 서브 클래스를 참조하는지 알 수 없습니다.

따라서 인터페이스에서 정적 메소드에 가장 가까운 근사치는 "this"를 무시하는 비 정적 메소드 일 것입니다. 즉, 인스턴스의 비 정적 멤버에 액세스하지 않습니다. 낮은 수준의 추상화에서, 모든 비 정적 방법 (VTABLE에서 조회 후)은 실제로 "이것"을 암시 적 공식 매개 변수로 취하는 클래스 범위를 가진 함수 일뿐입니다. 보다 Scala의 싱글 톤 객체 및 Java와의 상호 운용성 그 개념의 증거로. 따라서 모든 정적 메소드는 "이"매개 변수를 사용하지 않는 클래스 범위가있는 함수입니다. 따라서 일반적으로 정적 방법을 정적으로 호출 할 수 있지만 앞에서 언급 한 바와 같이 인터페이스에는 구현이 없습니다 (IS 초록).

따라서 인터페이스에서 정적 메소드에 가장 근접한 근사치를 얻는 것은 비 정적 메소드를 사용한 다음 비 정적 인스턴스 멤버에 액세스하지 않는 것입니다. (컴파일 타임)를 정적으로 연결하는 방법이 없기 때문에 다른 방법으로는 성능 이점이 없습니다. ISomething.member(). 인터페이스에서 정적 메소드에서 볼 수있는 유일한 이점은 그것이 "이것"을 입력하지 않고 (즉, 비 정적 인스턴스 멤버에 대한 액세스를 허용하지 않을 것이라는 것입니다. 이것은 "this"에 액세스하지 않는 함수가 불충분하고 포함 된 클래스와 관련하여 읽기조차하지 않음을 암시 적으로 선언 할 것이다. 그러나 인터페이스에서 "정적"선언 ISomething 또한 접근을 시도한 사람들을 혼동 할 것입니다. ISomething.member() 컴파일러 오류가 발생합니다. 컴파일러 오류가 충분히 설명 된 경우, 우리가 여기서하고있는 것처럼 (그리고 3을 반복했던 것처럼, 그들이 원하는 것을 달성하기 위해 비 정적 방법을 사용하는 것에 대해 사람들을 교육하는 것이 더 낫다고 생각합니다. 이 사이트의 Q & A 시간)이므로 많은 사람들에게 직관적이지 않은 문제입니다. 나는 올바른 이해를 얻기 위해 잠시 동안 그것에 대해 생각해야했다.

인터페이스에서 변이 가능한 정적 필드를 얻는 방법은 인터페이스에서 비 정적 getter 및 setter 메소드를 사용하여 서브 클래스에서 해당 정적 필드에 액세스하는 것입니다. Sidenote, 분명히 불변의 정적은 Java 인터페이스로 선언 될 수 있습니다. static final.

인터페이스는 클래스가 제공 할 것들의 목록을 제공하지 않고 정적 항목의 실제 구현이 아니라 정적 항목입니다.

정적을 원한다면 추상 클래스를 사용하고 상속 받으십시오. 그렇지 않으면 정적을 제거하십시오.

도움이되기를 바랍니다!

정적 메소드는 클래스 인스턴스가 아닌 클래스에 속하며 인터페이스가 클래스가 아니기 때문에 인터페이스에서 정적 메소드를 정의 할 수 없습니다. 여기에서 자세히 알아보십시오.

그러나 원한다면이 작업을 수행 할 수 있습니다.

public class A {
  public static void methodX() {
  }
}

public class B extends A {
  public static void methodX() {
  }
}

이 경우 당신이 가진 것은 Methodx ()라는 2 개의 고유 한 정적 메소드를 가진 두 개의 클래스입니다.

당신이 할 수 있다고 가정 해 봅시다. 이 예를 고려하십시오 :

interface Iface {
  public static void thisIsTheMethod();
}

class A implements Iface {

  public static void thisIsTheMethod(){
    system.out.print("I'm class A");
  }

}

class B extends Class A {

  public static void thisIsTheMethod(){
    System.out.print("I'm class B");
  } 
}

SomeClass {

  void doStuff(Iface face) {
    IFace.thisIsTheMethod();
    // now what would/could/should happen here.
  }

}

구현할 수있는 것은 정적 인터페이스입니다 (인터페이스의 정적 메소드 대신). 주어진 정적 인터페이스를 구현하는 모든 클래스는 해당 정적 메소드를 구현해야합니다. 사용하는 클래스 클래스에서 정적 인터페이스 Si를 얻을 수 있습니다.

SI si = clazz.getStatic(SI.class); // null if clazz doesn't implement SI
// alternatively if the class is known at compile time
SI si = Someclass.static.SI; // either compiler errror or not null

그런 다음 전화 할 수 있습니다 si.method(params). 이것은 컴파일 타임 알 수없는 클래스에서 Si 정적 메소드 구현을 얻거나 확인할 수 있기 때문에 (예 : 공장 설계 패턴에) 유용합니다! 동적 디스패치가 필요하며 클래스의 정적 메소드 (최종이 아닌 경우)를 확장하여 (정적 인터페이스를 통해 호출 할 때)를 대체 할 수 있습니다. 분명히 이러한 방법은 클래스의 정적 변수에만 액세스 할 수 있습니다.

Java 8 이이 문제를 해결한다는 것을 알고 있지만, 인터페이스에서 정적 메소드를 지정할 수있는 것이 도움이 될 수있는 현재 작업중 인 시나리오 (Java 7을 사용하는 데 잠긴)를 차지할 것이라고 생각했습니다.

여러 가지 이유로 값을 평가하는 도우미 방법과 함께 "ID"및 "DisplayName"필드를 정의한 몇 가지 열거 정의가 있습니다. 인터페이스를 구현하면 Getter 메소드가 제자리에 있지만 정적 헬퍼 방법이 아닌지 확인할 수 있습니다. 열거적이기 때문에 실제로 도우미 방법을 상속 된 추상 클래스 또는 같은 것으로 오프로드하는 깨끗한 방법은 없으므로 방법은 열거 자체에 정의되어야합니다. 또한 열거적이기 때문에 실제로 그것을 인스턴스 객체로 전달하여 인터페이스 유형으로 취급 할 수는 없지만 인터페이스를 통해 정적 헬퍼 방법의 존재를 요구할 수 있다는 것은 내가 좋아하는 것입니다. Java 8에서 지원됩니다.

여기 내 요점을 보여주는 코드가 있습니다.

인터페이스 정의 :

public interface IGenericEnum <T extends Enum<T>> {
    String getId();
    String getDisplayName();
    //If I was using Java 8 static helper methods would go here
}

하나의 열거 정의의 예 :

public enum ExecutionModeType implements IGenericEnum<ExecutionModeType> {
    STANDARD ("Standard", "Standard Mode"),
    DEBUG ("Debug", "Debug Mode");

    String id;
    String displayName;

    //Getter methods
    public String getId() {
        return id;
    }

    public String getDisplayName() {
        return displayName;
    }

    //Constructor
    private ExecutionModeType(String id, String displayName) {
        this.id = id;
        this.displayName = displayName;
    }

    //Helper methods - not enforced by Interface
    public static boolean isValidId(String id) {
        return GenericEnumUtility.isValidId(ExecutionModeType.class, id);
    }

    public static String printIdOptions(String delimiter){
        return GenericEnumUtility.printIdOptions(ExecutionModeType.class, delimiter);
    }

    public static String[] getIdArray(){
        return GenericEnumUtility.getIdArray(ExecutionModeType.class);
    }

    public static ExecutionModeType getById(String id) throws NoSuchObjectException {
        return GenericEnumUtility.getById(ExecutionModeType.class, id);
    }
}

일반 열거 유틸리티 정의 :

public class GenericEnumUtility {
    public static <T extends Enum<T> & IGenericEnum<T>> boolean isValidId(Class<T> enumType, String id) {       
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(enumOption.getId().equals(id)) {
                return true;
            }
        }

        return false;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String printIdOptions(Class<T> enumType, String delimiter){
        String ret = "";
        delimiter = delimiter == null ? " " : delimiter;

        int i = 0;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(i == 0) {
                ret = enumOption.getId();
            } else {
                ret += delimiter + enumOption.getId();
            }           
            i++;
        }

        return ret;
    }

    public static <T extends Enum<T> & IGenericEnum<T>> String[] getIdArray(Class<T> enumType){
        List<String> idValues = new ArrayList<String>();

        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            idValues.add(enumOption.getId());
        }

        return idValues.toArray(new String[idValues.size()]);
    }

    @SuppressWarnings("unchecked")
    public static <T extends Enum<T> & IGenericEnum<T>> T getById(Class<T> enumType, String id) throws NoSuchObjectException {
        id = id == null ? "" : id;
        for(IGenericEnum<T> enumOption : enumType.getEnumConstants()) {
            if(id.equals(enumOption.getId())) {
                return (T)enumOption;
            }
        }

        throw new NoSuchObjectException(String.format("ERROR: \"%s\" is not a valid ID. Valid IDs are: %s.", id, printIdOptions(enumType, " , ")));
    }
}

정적 방법이 인터페이스에서 허용되었다고 가정 해 봅시다. * 모든 구현 클래스가 해당 방법을 선언하도록 강요 할 것입니다. * 인터페이스는 일반적으로 객체를 통해 사용되므로 객체에 대한 유일한 효과적인 방법은 비 정적 방법입니다. * 특정 인터페이스를 알고있는 클래스는 정적 메소드를 호출 할 수 있습니다. 따라서 구현 클래스의 정적 방법이 아래로 호출되지만 Invoker 클래스는 어느 것을 알지 못합니다. 그것을 아는 방법? 그것을 추측하는 것은 인스턴스화가 없습니다!

객체로 작업 할 때 인터페이스가 사용되는 것으로 생각되었습니다. 이런 식으로, 객체는 특정 클래스에서 인스턴스화 되므로이 마지막 문제가 해결됩니다. 호출 클래스는 인스턴스화가 제 3 클래스에 의해 수행 될 수 있기 때문에 어떤 클래스인지 알 필요가 없습니다. 따라서 호출 클래스는 인터페이스 만 알고 있습니다.

이를 정적 메소드로 확장하려면 이전에 구현 클래스를 특별히 할 수있는 가능성이 있어야하며 호출 클래스에 대한 참조를 전달해야합니다. 이것은 인터페이스의 정적 메소드를 통해 클래스를 사용할 수 있습니다. 그러나이 참조와 객체의 다른 점은 무엇입니까? 우리는 단지 수업이 무엇인지를 나타내는 대상이 필요합니다. 이제 객체는 이전 클래스를 나타내며 이전 정적 방법을 포함한 새로운 인터페이스를 구현할 수 있습니다.

메타 클라스는이 목적을 위해 사용됩니다. Java의 클래스 클래스를 시도 할 수 있습니다. 그러나 문제는 Java가 이것에 대해 충분히 유연하지 않다는 것입니다. 인터페이스의 클래스 객체에서 메소드를 선언 할 수 없습니다.

이것은 메타 문제입니다 - 엉덩이를해야 할 때

..이러쿵 저러쿵

어쨌든 쉬운 해결 방법이 있습니다. 동일한 논리로 메소드를 정적으로 만들 수 있습니다. 그러나 먼저 메소드를 호출하려면 객체를 만들어야합니다.

이것을 해결하려면 : 오류 : 누락 된 메소드 본체, 또는 추상 정적 무효 메인 (String [] args);

interface I
{
    int x=20;
    void getValue();
    static void main(String[] args){};//Put curly braces 
}
class InterDemo implements I
{
    public void getValue()
    {
    System.out.println(x);
    }
    public static void main(String[] args)
    {
    InterDemo i=new InterDemo();
    i.getValue();   
    }

}

출력 : 20

이제 인터페이스에서 정적 메소드를 사용할 수 있습니다

Java는 필요하지 않기 때문에 정적 인터페이스 방법이 없다고 생각합니다. 당신은 그렇게 생각할 수도 있지만 ... 어떻게 사용하겠습니까? 당신이 그들처럼 부르고 싶다면

MyImplClass.myMethod()

그런 다음 인터페이스에서 선언 할 필요가 없습니다. 당신이 그들처럼 부르고 싶다면

myInstance.myMethod()

그러면 정적이어서는 안됩니다. 실제로 첫 번째 방법을 사용하려는 경우, 각 구현이 그러한 정적 메소드를 갖도록 시행하려면 실제로 인터페이스와 호출 코드를 구현하는 인스턴스 간의 계약이 아닌 코딩 컨벤션입니다.

인터페이스를 사용하면 인터페이스와 호출 코드를 구현하는 클래스 인스턴스간에 계약을 정의 할 수 있습니다. 그리고 Java는이 계약이 위반되지 않았는지 확인하는 데 도움이되므로이 계약에 의존 하고이 계약을 구현하는 클래스를 걱정하지 않아도 "계약에 서명 한 사람"만으로도 충분합니다. 정적 인터페이스의 경우 코드가 인터페이스합니다

MyImplClass.myMethod()

각 인터페이스 구현 에이 방법이 있다는 사실에 의존하지 않으므로 확인을 위해 Java가 필요하지 않습니다.

인터페이스에서 정적 메소드의 필요성은 기본적으로 객체의 인스턴스를 만들 필요가없는 경우에 사용됩니다. 인터페이스의 전체 아이디어는 개념에서 분기하는 정적 메소드의 도입으로 OOP 개념을 가져 오는 것입니다.

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