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


498

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

예를 들면 다음과 같습니다.

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

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

가능한 문제 중 하나는 전화를 걸 때 발생하는 일입니다.

IXMLizable.newInstanceFromXML(e);

이 경우 빈 메소드 (예 : {})를 호출해야한다고 생각합니다. 모든 서브 클래스는 정적 메소드를 구현해야하므로 정적 메소드를 호출 할 때 모두 괜찮습니다. 왜 이것이 불가능합니까?

편집 : 나는 "자바의 방식이기 때문에"보다 더 깊은 답변을 찾고 있다고 생각합니다.

정적 메서드를 덮어 쓸 수없는 특별한 기술적 이유가 있습니까? 즉, Java 설계자가 왜 인스턴스 메소드를 대체 가능하지만 정적 메소드는 사용하지 않기로 결정 했습니까?

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

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

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

  2. 누군가가 IXMLizable 인터페이스를 구현하는 클래스의 새 인스턴스를 만들고 싶다면 항상 newInstanceFromXML (Element e) 정적 생성자가 있음을 알게 될 것입니다.

인터페이스에 주석을 넣는 것 외에 다른 방법이 있습니까?


4
btw 인터페이스에서 public으로 메소드 (및 필드) 정의를 어지럽 힐 필요는 없습니다.
Tom Hawtin-tackline

흠, stackoverflow.com/questions/21817/… 의 사본 인 것 같습니다 . 전에는 본 적이 없었습니다.
마이클 마이어스

1
정적 인터페이스 메소드를 어떻게 사용하고 싶은지 코드를 제공해 주시겠습니까?
Pavel Feldman

43
이것은 자바 8 가능할 것이다 : docs.oracle.com/javase/tutorial/java/IandI/...
dakshang

1
@dakshang 네, 그러나 OP가 원하는 것을하지 않습니다.
user253751

답변:


518

Java 8은 정적 인터페이스 메소드를 허용합니다

Java 8을 사용하면 인터페이스 정적 메소드가있을 있습니다. 또한 구체적인 인스턴스 메소드를 가질 수 있지만 인스턴스 필드는 가질 수 없습니다.

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

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

인터페이스의 정적 메소드

인터페이스가 이전 버전에서 정적 메소드를 가질 수 없었던 강력한 기술적 이유는 없었습니다. 이것은 중복 질문 의 포스터의해 훌륭하게 요약됩니다 . 정적 인터페이스 메소드는 처음으로 간주되었다 작은 언어 변화 하고 있었다 공식 제안 자바 7에 추가 할 수는 있지만, 나중에 된 예기치 못한 합병증으로 인해 하락했다.

마지막으로 Java 8에는 정적 인터페이스 메소드와 기본 구현을 통한 대체 가능한 인스턴스 메소드가 도입되었습니다. 그래도 인스턴스 필드를 가질 수 없습니다. 이러한 기능은 람다 식 지원의 일부이며 JSR 335의 H 부분 에서 자세한 내용을 읽을 수 있습니다 .

정적 메서드 재정의

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

정적 메소드는 컴파일 타임에 해석 할 수 있습니다. 동적 디스패치는 컴파일러가 객체의 구체적인 유형을 결정할 수 없으므로 호출 할 메서드를 확인할 수없는 인스턴스 메서드에 적합합니다. 그러나 정적 메소드를 호출하려면 클래스가 필요하며 해당 클래스는 정적으로 알려져 있기 때문에 컴파일 타임에 동적 디스패치가 필요하지 않습니다.

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

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

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

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


생성자 "인터페이스"

다음은 질문에 대한 최근 수정 사항을 다루기위한 자료입니다.

의 각 구현에 대해 생성자와 같은 메소드를 효과적으로 위임하려는 것처럼 들립니다 IXMLizable. 1 분 동안 인터페이스로이를 시행하는 것을 잊고이 요구 사항을 충족하는 클래스가 있다고 가정하십시오. 어떻게 사용 하시겠습니까?

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

Foo obj = Foo.newInstanceFromXML(e);

Foo새 객체를 "구성"할 때 구체적 유형의 이름을 명시 적으로 지정해야하기 때문에 컴파일러는 실제로 필요한 팩토리 메소드가 있는지 확인할 수 있습니다. 그렇지 않은 경우 어떻게해야합니까? 내가 구현할 수 있다면 IXMLizable은 "생성자"부족 것을, 나는 인스턴스를 생성하고 코드에 전달, 그것은 이다IXMLizable 필요한 모든 인터페이스를.

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



12
# 1의 이유가 다중 상속 일 수 있습니까? 여러 인터페이스에서 상속 할 수 있으므로 두 인터페이스에 동일한 정적 메소드 서명이 포함 된 후 클래스가이를 모두 구현하고 해당 메소드를 호출하면 Java 언어 작성자가 여러 클래스 상속을 허용하지 않기 때문에 피하려는 방식이 복잡해질 수 있습니다. 첫 번째 장소. 메소드 정의를 전혀 허용하지 않는 인터페이스에 대해서도 동일한 주장을 할 수 있습니다.
shrini1000

1
@ shrini1000-아니요, 정적 메소드는 컴파일 타임에 해결됩니다. 모호성은 상수로 처리하는 것과 같은 방식으로 처리 할 수 ​​있습니다 . 컴파일러 오류가 있습니다. 그러나 프로젝트 코인의 제안은 일부 예상치 못한 어려움으로 인해 거부되었습니다. 그들이 무엇인지 확실하지 않지만, 나는이 라인을 따라 있다고 생각하지 않습니다.
erickson

1
@ tgm1024 예, "Constructor 'interfaces'"섹션은 컴파일 타임에 알려진 유형을 통해 다형성 동작을 호출하려고 시도하는 것이 왜 타당하지 않은지 설명합니다. 당신은 어떻게 호출 할 RESET()지정된 클래스에? 당신은 쓸 것 SomeClass.RESET()입니다. 따라서 해당 API를 설명하기위한 인터페이스가 필요하지 않습니다. 정적. 컴파일 타임에 구체적인 유형을 모르는 경우 인터페이스가 사용됩니다. 정적 메서드의 경우에는 해당되지 않습니다.
erickson

2
"시공은 인터페이스가 아닌 구현의 일부입니다. 인터페이스와 함께 작동하는 코드는 생성자를 신경 쓰지 않습니다." -그것은 사실이 아닙니다. 다른 언어 (예 : Swift)에서는 정적으로 T알지 않고도 새로운 인스턴스를 만들 수 있습니다 T. 인터페이스에서 특정 생성자 (또는 정적 메소드)가 런타임에 존재할 것이라고 약속하기 때문입니다. Java에서 생성을 지정할 수 없다는 사실이 의미가있는 것은 아닙니다.
라파엘

48

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

내 답변을 복제하려면 :

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

더 중요한 것은 정적 메소드가 재정의되지 않으며 수행하려는 경우 :

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

static 규칙은 선언 된 var 유형에 정의 된 메소드를 실행해야한다고 말합니다. 이것은 인터페이스이므로 불가능합니다.

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

"Java가 그렇게하기 때문에"이 정도라고 말할 수 있지만 실제로 결정은 다른 디자인 결정의 논리적 결과이기도합니다.


14
<T extends MyInterface>를 일반 유형 매개 변수로 사용하는 경우 T가 .doSomething () 할 수있는 인터페이스를 통해 보장하는 것이 좋습니다.
크리스 베티

4
인수를 이해하는 동안 @Chris_Betti (제네릭이 아닌 유형의 경우에도)에 동의합니다. 코드 구조가 일부 클래스 가 특정 정적 API를 구현 하도록하는 것이 좋습니다 . 아마도 다른 개념을 사용하는 것이 가능할 수도 있습니다.
Juh_

@Juh_, ..... 또는 꼭 필요한 경우 새 키워드. 나는 static어쨌든 언어에 있어서는 어리석은 용어 라고 생각 하며, 너무 멀리 확장되었다. 따라서 자체적으로 이미 스케치하는 것입니다. stackoverflow.com/questions/512877/… 위의 예를 참조하십시오 {shrug}.

3
"인터페이스에서 정적 메서드를 선언 할 필요는 없습니다." 인스턴스화하지 않고 정보를 제공 할 수있는 클래스 모음이 있지만이 정적 클래스 수준 정보를 재정의 할 수있는 정적 인터페이스 (예 : 재정의 가능한 정적 메소드가있는 인터페이스)가 필요한 경우 유효한 사용입니다 . 속성, 리플렉션 등을 해킹하지 않고도 클래스 속성에 대한 메타 정보를 캡처 할 수있는 reflection ++을 생각해보십시오.
Jason

1
"인터페이스에서 정적 메소드를 선언 할 필요는 없습니다." 이것은 사실이 아닙니다. 시스템에 기본 클래스 리졸버가 있다고 가정하십시오. ContainerInjectionInterce :: create (Container $ container) 메소드를 구현 한 것을 감지하면 예를 들어이 함수를 사용하여 오브젝트를 작성합니다.
user3790897

37

일반적으로 이것은 팩토리 패턴을 사용하여 수행됩니다.

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

public interface IXMLizable {
  public Element toXMLElement();
}

7
+1 팩토리 패턴은 문제에 대한 해결책처럼 들립니다. (질문은 아니지만)
pvgoddijn

누군가 <T extends IXMLizable>을 여기에 넣는 의미가 무엇인지 말해 줄 수 있습니까? 나는 Java를 처음 사용합니다.
Nuwan Harshakumara Piyarathna

1
@NuwanHarshakumaraPiyarathna T는 IXMLizable을 확장하는 클래스 여야합니다. 이것이 의미하는 바에 대한 이해를 돕기 위해 Java 제네릭을 살펴보십시오
adrian

37

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

팁 : 정적 인터페이스 메서드 호출은 클래스에 의해 구현 될 필요가 없습니다. 수퍼 클래스의 정적 메소드에 대해 동일한 규칙이 인터페이스의 정적 메소드에 적용되기 때문입니다.


이것은이 질문의 완벽한 예입니다.

21

정적 메소드는 서브 클래스에서 재정의 될 수 없으므로 추상적 일 수 없습니다. 인터페이스의 모든 메소드는 사실상 추상적입니다.


2
항상 각 유형이 정적 인터페이스 메소드를 구현하도록 강제 할 수 있습니다. 타입 클래스?
MichaelGG

16
스스로 밖으로 나가서 정적 메서드를 재정의 할 수 없는지 질문에 답하십시오 . 정적 메서드를 재정의 할 수 있다면 어떤 모양입니까? 그들과 함께 무엇을 할 수 있습니까? 이 대답은 기본적으로 "할 수 없기 때문에 할 수 없습니다"입니다.
erickson

10

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

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

Java doc에 따라 :

정적 메소드는 객체가 아니라 정의 된 클래스와 연관된 메소드입니다. 클래스의 모든 인스턴스는 정적 메소드를 공유합니다

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

6

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


명확하고 간결한 논리. 잘 넣어
Oke Uwechue

6

첫째, 모든 언어 결정은 언어 작성자가 내린 결정입니다. 소프트웨어 엔지니어링이나 언어 정의 또는 컴파일러 / 통역사 작성 분야에서는 정적 메소드가 인터페이스의 일부가 될 수 없다고 말하는 것은 없습니다. 필자는 몇 가지 언어를 만들고이를 위해 컴파일러를 작성했습니다. 모두 의미있는 의미를 정의하고 정의하는 것입니다. 컴파일러가 런타임에 메소드의 해상도를 연기해야하더라도 인터페이스에서 정적 메소드의 의미가 매우 명확하다고 주장합니다.

둘째, 정적 메소드를 사용한다는 것은 정적 메소드를 포함하는 인터페이스 패턴을 사용해야하는 타당한 이유가 있다는 것입니다. 저는 여러분에게 말할 수 없지만 정기적으로 정적 메소드를 사용합니다.

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


5

정적 메소드는 인스턴스 메소드와 비슷하지 않으므로 Java 디자이너가 인터페이스에서 원하지 않는 것으로 결정했다고 가정합니다.

그러나 정적 메서드를 포함하는 클래스를 인터페이스 안에 넣을 수 있습니다. 당신은 그것을 시도 할 수 있습니다!

public interface Test {
    static class Inner {
        public static Object get() {
            return 0;
        }
    }
}

5
  • "정적 메서드를 재정의 할 수없는 특별한 이유가 있습니다."

정의를 작성하여 귀하의 질문에 대해 다시 말씀 드리겠습니다.

  • "컴파일 타임에 분석 된 메소드가 런타임에 분석 될 수없는 특별한 이유가 있습니다."

또는 더 완벽하게 말하면 인스턴스없이 메소드를 호출하고 클래스를 알고 싶다면 내가없는 인스턴스를 기반으로 어떻게 해결할 수 있습니까?


3

몇 가지 답변은 재정의 가능한 정적 메소드 개념의 문제점에 대해 논의했습니다. 그러나 때로는 사용하려는 패턴 인 것처럼 보일 수도 있습니다.

예를 들어, 값 개체는 있지만 값 개체를 조작하는 명령이있는 개체 관계형 레이어로 작업합니다. 여러 가지 이유로 각 값 개체 클래스는 프레임 워크가 명령 인스턴스를 찾도록하는 정적 메소드를 정의해야합니다. 예를 들어 개인을 만들려면 다음을 수행하십시오.

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

그리고 ID로 사람을로드하기 위해

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

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

EJB는 홈 인터페이스를 통해이 문제를 해결합니다. 각 객체는 홈을 찾는 방법을 알고 있으며 홈에는 "정적"메소드가 포함되어 있습니다. 이런 식으로 "정적"메소드를 필요에 따라 재정의 할 수 있으며, Bean 인스턴스에 적용되지 않는 메소드로 일반 ( "원격"이라고 함) 인터페이스를 복잡하게 만들지 않습니다. 일반 인터페이스가 "getHome ()"메소드를 지정하도록하십시오. Home 객체의 인스턴스를 반환하십시오 (싱글 톤 일 수 있음) 호출자는 모든 Person 객체에 영향을 미치는 작업을 수행 할 수 있습니다.


3

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

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


2

제네릭이 없으면 정적 인터페이스는 컴파일 타임에 모든 정적 메서드 호출이 해결되므로 쓸모가 없습니다. 따라서 실제로 사용하지 않습니다.

제네릭을 사용하면 기본 구현 유무에 관계없이 사용할 수 있습니다. 분명히 재정의 등이 필요할 것입니다. 그러나 내 생각에 그러한 사용법은 OO가 아니기 때문에 (다른 대답은 엄밀하게 지적되었으므로) 유용하게 구현하는 데 필요한 노력은 가치가 없었습니다.


1
제네릭은 이것과 어떤 관계가 있습니까? 인터페이스의 정적 메소드는 여전히 실행 불가능합니다.
DJClayworth

먼저 구현 결정이 될 것입니다. 그러나 그는 인터페이스에서 정적 메소드를 호출하고 싶지 않다고 생각합니다 (그냥 클래스를 사용할 수 있음). 그러나 대신 유형 클래스와 같은 것이거나 유형 매개 변수가 아닌 것을 원합니다. 사실 그의 최신 편집은 이것을 훨씬 더 명확하게 보여줍니다.
MichaelGG

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

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


1

예를 들어 인터페이스는 정적으로 역 참조 될 수 없습니다 ISomething.member. 인터페이스는 항상 인터페이스의 서브 클래스 인스턴스를 참조하는 변수를 통해 역 참조됩니다. 따라서 인터페이스 참조는 서브 클래스의 인스턴스없이 어떤 서브 클래스를 참조하는지 알 수 없습니다.

따라서 인터페이스에서 정적 메소드에 가장 가까운 근사값은 "this"를 무시하는 즉, 정적이 아닌 인스턴스 멤버에 액세스하지 않는 비 정적 메소드입니다. 저수준 추상화에서 모든 비 정적 메소드 (vtable에서 조회 후)는 실제로 "this"를 암시적인 형식 매개 변수로 사용하는 클래스 범위의 함수일뿐입니다. 스칼라의 싱글 톤 객체와 자바와의 상호 운용성 보기 그 개념의 증거 . 따라서 모든 정적 메소드는 "this"매개 변수를 사용하지 않는 클래스 범위의 함수입니다. 따라서 일반적으로 정적 메서드를 정적으로 호출 할 수 있지만 앞에서 설명한 것처럼 인터페이스에는 구현이 없습니다 (추상).

따라서 인터페이스에서 정적 메서드에 가장 가까운 근사값을 얻으려면 비 정적 메서드를 사용한 다음 비 정적 인스턴스 멤버에 액세스하지 마십시오. 컴파일 타임에 a를 정적으로 링크 할 수있는 방법이 없기 때문에 다른 방법으로는 성능상의 이점이 없습니다 ISomething.member(). 인터페이스에서 정적 메소드에 대한 유일한 이점은 암시 적 "this"를 입력하지 않으므로 정적이 아닌 인스턴스 멤버에 대한 액세스를 허용하지 않는다는 것입니다. 이것은 "this"에 액세스하지 않는 함수가 변경되지 않으며 포함하는 클래스와 관련하여 읽기 전용이 아니라고 암시 적으로 선언합니다. 그러나 인터페이스에서 "정적"으로 선언 ISomething하면 액세스하려는 사람들과 혼동됩니다.ISomething.member()컴파일러 오류가 발생합니다. 컴파일러 오류가 충분히 설명이 되었다면, 사람들이 비 정적 방법을 사용하여 원하는 것을 달성하는 방법에 대해 교육하는 것보다 낫습니다. 이 사이트의 Q & A 시간)에 따라 많은 사람들에게 직관적이지 않은 문제입니다. 나는 올바른 이해를 얻기 위해 잠시 그것에 대해 생각해야했습니다.

인터페이스에서 변경 가능한 정적 필드를 얻는 방법은 인터페이스에서 비 정적 getter 및 setter 메소드를 사용하여 서브 클래스의 정적 필드에 액세스하는 것입니다. 참고로 불변의 스태틱은 Java 인터페이스에서로 선언 할 수 있습니다 static final.


0

인터페이스는 단지 클래스가 제공 할 것들의 목록을 제공하지만, 그것들의 실제 구현은 정적 항목입니다.

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

희망이 도움이됩니다!


2
이론적으로는 정적 동작, 즉 "이 인터페이스의 구현에는이 서명과 함께 정적 메소드 foo ()가 있습니다"를 포함하도록 인터페이스를 정의하고 구현을 특정 클래스로 남겨 둘 수 있습니다. 이 동작이 유용한 상황이 발생했습니다.
Rob

0

정적 메소드는 클래스의 인스턴스가 아닌 클래스에 속하고 인터페이스는 클래스가 아니므로 인터페이스에서 정적 메소드를 정의 할 수 없습니다. 자세한 내용은 여기를 참조하십시오.

그러나 원하는 경우 다음을 수행 할 수 있습니다.

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

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

이 경우 methodX ()라는 2 개의 고유 한 정적 메소드가있는 두 개의 클래스가 있습니다.


0

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

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.
  }

}

1
"I 클래스입니다"를 인쇄합니다. 그러나 입력 A.thisIsTheMethod()하면 "I 'm class B"로 인쇄됩니다.
cdmckay

그러나 인터페이스에서 메소드를 호출하는 oyr 어떻게 (또는 컴파일러) 어떤 메소드를 호출해야하는지 어떻게 알 수 있습니까? (
12

죄송합니다. 다음과 같이 말합니다. 그러나 입력 B.thisIsTheMethod()하면 "I 'm class B"로 표시됩니다.
cdmckay

나는 IFace.thisIsTHeMethod를 의도적으로 말했기 때문에 문제가 있습니다. 은 (는 그것에 선언에도 불구하고) 정의되지 않은 동작없이 인터페이스를 호출 할 수 없을 것이다
pvgoddijn

0

구현할 수있는 것은 인터페이스의 정적 메소드 대신 정적 인터페이스입니다. 주어진 정적 인터페이스를 구현하는 모든 클래스는 해당 정적 메소드를 구현해야합니다. 모든 클래스 clazz에서 정적 인터페이스 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 정적 메소드 구현을 얻거나 확인할 수 있기 때문에 이것은 (예를 들어 팩토리 디자인 패턴에) 유용합니다! 동적 디스패치가 필요하며 클래스를 확장하여 (정적 인터페이스를 통해 호출 할 때) 클래스의 정적 메서드 (최종이 아닌 경우)를 재정의 할 수 있습니다. 분명히 이러한 메소드는 해당 클래스의 정적 변수에만 액세스 할 수 있습니다.


0

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

0

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

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

이것을 정적 메소드로 확장하려면 구현 클래스를 미리 지정 한 다음 호출 클래스에 대한 참조를 전달해야합니다. 인터페이스의 정적 메소드를 통해 클래스를 사용할 수 있습니다. 그러나이 참조와 객체의 차이점은 무엇입니까? 클래스가 무엇인지 나타내는 객체 만 있으면됩니다. 이제 객체는 이전 클래스를 나타내며 이전 정적 메소드를 포함하여 새 인터페이스를 구현할 수 있습니다. 이제 정적이 아닙니다.

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

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

..이러쿵 저러쿵

어쨌든 쉬운 해결 방법이 있습니다-동일한 논리로 메소드를 비 정적으로 만듭니다. 그러나 먼저 메소드를 호출 할 오브젝트를 작성해야합니다.


0

이 문제를 해결하려면 : error : 메소드 본문이 누락되었거나 abstract static void main (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

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


1
그러나 그것은 쓸모가 없습니다. 인터페이스에서 정적 메소드를 정의해도 해당 인터페이스를 구현하는 클래스에서 추가 정의가 적용되지 않습니다. 인터페이스 I에서 정적 메소드를 모두 제거하면 코드가 문제없이 컴파일되고 실행됩니다. 즉, InterDemo 클래스에서 I 인터페이스의 기본 메소드를 대체 하지 않고 동일한 서명으로 새 메소드를 작성하기 만합니다.
Fran Marzoa

-2

자바에는 정적 인터페이스 메소드가 필요 없다고 생각합니다. 당신은 당신이 생각할 수도 있지만 ... 어떻게 사용하겠습니까? 당신이 그들을 부르고 싶다면

MyImplClass.myMethod()

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

myInstance.myMethod()

정적이어서는 안됩니다. 실제로 첫 번째 방법을 사용하려고하지만 각 구현에 이러한 정적 메소드를 적용하도록 강요하려는 경우 실제로 인터페이스를 구현하는 인스턴스와 호출 코드 간의 계약이 아닌 코딩 규칙입니다.

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

MyImplClass.myMethod()

각 인터페이스 구현에이 메소드가 있다는 사실에 의존하지 않으므로이를 확실하게하는 데 Java가 필요하지 않습니다.


-5

인터페이스에서 정적 메소드의 필요성은 무엇입니까? 정적 메소드는 객체의 인스턴스를 만들 필요가 없을 때 기본적으로 사용됩니다. 인터페이스의 전체 아이디어는 개념에서 벗어나는 정적 메소드를 도입하여 OOP 개념을 도입하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.