인터페이스에 정적 메소드가 없지만 정적 필드와 내부 클래스가 왜 정적 인 방법이 없습니까? [Pre-Java8] [복제

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

  •  02-07-2019
  •  | 
  •  

문제

이 질문은 이미 여기에 답이 있습니다.

인터페이스 내에서 정적 메소드를 정의 할 수없는 이유에 대해 몇 가지 질문이 있었지만 기본 불일치를 다루지 않는 이유는 무엇입니까? 왜 정적 필드와 정적 내부 유형을 정의 할 수는 있지만 정적 메소드는 아니 었습니까?

정적 내부 유형은 아마도 공정한 비교가 아닐 수도 있습니다. 왜냐하면 그것은 새로운 클래스를 생성하는 구문 설탕이지만 왜 필드는 그렇지 않지만 왜 방법은 없기 때문입니까?

인터페이스 내의 정적 메소드에 대한 인수는 JVM이 사용하는 가상 테이블 해상도 전략을 중단하지만 정적 필드에 동일하게 적용되지 않아야한다는 것입니다.

일관성은 내가 원하는 것이며 Java는 인터페이스 내에서 어떤 형태의 정적을 지원하지 않았거나, 일관성이 있어야하고 허용해야합니다.

도움이 되었습니까?

해결책

an 공식 제안 Java 7의 인터페이스에서 정적 메소드를 허용하도록 만들어졌습니다.이 제안은 아래에서 이루어지고 있습니다. 프로젝트 코인.

내 개인적인 의견은 좋은 생각이라는 것입니다. 구현에는 기술적 인 어려움이 없으며 매우 논리적이고 합리적인 일입니다. 프로젝트 코인에는 내가 희망하는 몇 가지 제안이 있습니다. 절대 Java 언어의 일부가되지만 이것은 많은 API를 정리할 수있는 언어입니다. 예를 들어, Collections 클래스에는 정적 방법이 있습니다 조작을 위해 List 구현; 그것들은 List 상호 작용.


업데이트: 에서 Java Posse Podcast #234, Joe D 'Arcy는 제안을 간단히 언급하면서 그것이 "복잡하다"고 프로젝트 코인에 따라 그것을 만들지 않을 것이라고 말했습니다.


업데이트: Java 7의 프로젝트 코인으로 만들지는 않았지만 Java 8은 지원합니다. 인터페이스의 정적 기능.

다른 팁

나는 이것으로 내 애완 동물 이론과 함께 갈 것입니다.이 경우는이 경우 일관성의 부족이 디자인이나 필요성보다는 편의의 문제라는 것입니다. .

정적 필드는 (a) JDK 1.0에 있었기 때문에 (a) JDK 1.0에서 많은 멍청한 결정이 내려졌으며 (b) 인터페이스의 정적 최종 필드는 당시 Java가 상수에 가장 가까운 것입니다.

순수한 구문 설탕이기 때문에 인터페이스의 정적 내부 클래스가 허용되었습니다. 내부 클래스는 실제로 부모 클래스와 관련이 없습니다.

따라서 정적 방법은 단순히 그렇게 할 이유가 없기 때문에 허용되지 않습니다. 일관성은 현 상태를 변경하기에 충분히 설득력이 없습니다.

물론 이것은 아무것도 깨지 않고 향후 JLS 버전에서 허용 될 수 있습니다.

인터페이스에서 정적 메소드를 선언 할 포인트는 없습니다. 일반 호출 Myinterface.staticMethod ()에 의해 실행할 수 없습니다. (편집 : 마지막 문장이 일부 사람들을 혼란스럽게했기 때문에 myclass.staticMethod () 호출 MyClass에서 정적 메드의 구현을 정확하게 실행합니다. MyClass 인 경우 인터페이스가 존재할 수 없습니다!) 구현 클래스 MyImplementor.staticMethod ()를 지정하여 호출하는 경우. 그런 다음 실제 클래스를 알아야하므로 인터페이스에 포함되어 있는지 여부는 관련이 없습니다.

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

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

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

물론 메소드에서 항상 정적 키워드를 제거 할 수 있습니다. 모든 것이 잘 작동합니다. 인스턴스 방법에서 호출되면 일부 경고를 억제해야 할 수도 있습니다.

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

인터페이스의 목적은 구현을 제공하지 않고 계약을 정의하는 것입니다. 따라서 정적 메소드를 가질 수 없으므로 정적 메소드를 가질 수 없습니다. 정적 메소드를 무시할 수 없으므로 인터페이스에 이미 구현해야하므로 이미 구현해야합니다. 필드에 관해서는 정적입니다 final fields 본질적으로 상수가 허용됩니다 (1.5+에서는 인터페이스에 열거를 가질 수 있음). 상수는 마법의 숫자없이 인터페이스를 정의하는 데 도움이됩니다.

BTW, 명시 적으로 지정할 필요가 없습니다 static final 정적 최종 필드 만 허용되기 때문에 인터페이스의 필드 용 수정 자.

이것은 오래된 실이지만 이것은 모두에게 매우 중요한 질문입니다. 나는 오늘 이것을 알아 차렸으므로 더 깨끗한 방식으로 설명하려고 노력하고 있습니다.

인터페이스의 주요 목적은 구현할 수없는 것을 제공하는 것입니다.

허용되는 정적 방법

그런 다음 해당 메소드를 사용하여 호출 할 수 있습니다 interfaceName.staticMethodName (), 그러나 이것은 구현되지 않은 방법이며 아무것도 포함하지 않습니다. 따라서 정적 방법을 허용하는 것은 쓸모가 없습니다. 그러므로 그들은 이것을 전혀 제공하지 않습니다.

정적 필드가 허용됩니다

필드는 구현할 수 없기 때문에 구현 가능에 따라 필드에서 논리적 작업을 수행 할 수 없으므로 필드에서 작동 할 수 있습니다. 따라서 당신은 분야의 행동을 바꾸지 않기 때문에 그들이 허용되는 이유입니다.

내부 클래스가 허용됩니다

내부 클래스는 컴파일 후 내부 클래스의 다른 클래스 파일이 생성되기 때문에 허용됩니다. Interfaceame $ innerclassname.class , 기본적으로 당신은 다른 엔티티에서 구현을 모두 함께 제공하지만 인터페이스에 있지 않습니다. 따라서 내부 클래스의 구현이 제공됩니다.

이것이 도움이되기를 바랍니다.

실제로 누군가가 정적 방법으로 혜택을받을 수있는 이유가 있습니다. 인터페이스를 구현하는 클래스의 공장 방법으로 사용할 수 있습니다. 예를 들어 OpenJDK에 컬렉션 인터페이스와 컬렉션 클래스가있는 이유입니다. 따라서 언제나처럼 해결 방법이 있습니다. 다른 클래스에 정적 메소드의 "네임 스페이스"역할을하는 개인 생성자를 제공합니다.

Java 5 이전에는 정적 필드에 대한 일반적인 사용이 다음과 같습니다.

interface HtmlConstants {
    static String OPEN = "<";
    static String SLASH_OPEN = "</";
    static String CLOSE = ">";
    static String SLASH_CLOSE = " />";
    static String HTML = "html";
    static String BODY = "body";
    ...
}

public class HtmlBuilder implements HtmlConstants { // implements ?!?
    public String buildHtml() {
       StringBuffer sb = new StringBuffer();
       sb.append(OPEN).append(HTML).append(CLOSE);
       sb.append(OPEN).append(BODY).append(CLOSE);
       ...
       sb.append(SLASH_OPEN).append(BODY).append(CLOSE);
       sb.append(SLASH_OPEN).append(HTML).append(CLOSE);
       return sb.toString();
    }
}

이것은 의미가 있습니다 htmlbuilder 각 상수를 자격이 없어서 사용할 수 있습니다. 열려 있는 대신에 htmlconstants.open

이러한 방식으로 도구를 사용하는 것은 궁극적으로 혼란 스럽습니다.

이제 Java 5를 사용하면 다음과 같습니다 정적 가져 오기 동일한 효과를 달성하기위한 구문 :

private final class HtmlConstants {
    ...
    private HtmlConstants() { /* empty */ }
}

import static HtmlConstants.*;
public class HtmlBuilder { // no longer uses implements
    ...
}

Java Language Designers는 그것을 원하지 않았습니다. 기술적 인 관점에서 볼 때 그들을 허용하는 것이 합리적입니다. 결국 추상 수업도 그들을 가질 수 있습니다. 인터페이스에 정적 메소드가있는 곳에서 "수작업"바이트 코드를 "수작업"할 수 있다고 가정하지만 테스트하지 않았으며 메소드를 호출하거나 인터페이스를 일반적으로 사용하는 데 문제가없는 IMHO 작동해야합니다.

나는 종종 정적 방법이 왜 전혀 궁금해합니까? 그것들은 그들의 용도를 가지고 있지만, 패키지/네임 스페이스 레벨 방법은 아마도 정적 방법의 80을 포함 할 것입니다.

두 가지 주요 이유가 떠오르고 있습니다.

  1. Java의 정적 방법은 서브 클래스로 무시할 수 없으며, 이는 정적 필드보다 방법에 대한 훨씬 더 큰 문제입니다. 실제로, 나는 서브 클래스로 필드를 무시하고 싶지 않았지만 항상 메소드를 무시합니다. 따라서 정적 메소드를 사용하면 클래스가 인터페이스가 자체 구현을 구현하는 데 해당 메소드를 구현하는 것을 방지하여 인터페이스를 사용하는 목적을 크게 물리칩니다.

  2. 인터페이스에는 코드가 없어야합니다. 그것이 추상적 인 수업을위한 것입니다. 인터페이스의 요점은 모든 방법 세트를 가지고있는 모든 관련 대상에 대해 이야기 할 수 있도록하는 것입니다. 실제로 이러한 방법의 구현을 제공하는 것은 인터페이스의 의도의 범위를 벗어납니다.

정적 메소드는 클래스에 묶여 있습니다. Java에서는 인터페이스가 기술적으로 클래스가 아니며 유형이지만 클래스는 아닙니다 (따라서 키워드 구현 및 인터페이스는 객체를 확장하지 않습니다). 인터페이스는 클래스가 아니기 때문에 실제 클래스가 부착되지 않기 때문에 정적 메소드를 가질 수 없습니다.

인터페이스에 해당하는 클래스 객체를 얻으려면 interfacename.class를 호출 할 수 있지만 클래스 클래스는 특히 Java 응용 프로그램의 클래스 및 인터페이스를 나타내는 것으로 나타났습니다. 그러나 인터페이스 자체는 클래스로 취급되지 않으므로 정적 방법을 첨부 할 수 없습니다.

정적 최종 필드 만 인터페이스에서 선언 될 수 있습니다 ( "공개"키워드를 포함하지 않더라도 공개적 인 메소드와 매우 유사합니다. 정적 필드는 키워드의 유무에 관계없이 "최종"입니다).

이것들은 값 일 뿐이며 컴파일 시간에 사용되는 곳마다 문자 그대로 복사되므로 실제로 런타임에 정적 필드를 "호출"하지 않습니다. 정적 방법을 갖는 것은 동일한 의미를 갖지 못할 것입니다. Java가 허용하지 않는 구현없이 인터페이스를 호출하는 것이 포함되기 때문입니다.

그 이유는 인터페이스에 정의 된 모든 방법이 해당 수정자를 명시 적으로 선언하든 아니든 추상적이기 때문입니다. 정적 방법은 고정 된 방법을 재정의 할 수 없기 때문에 추상 정적 방법은 수정 자의 허용 조합이 아닙니다.

인터페이스가 정적 필드를 허용하는 이유에 관해서. "기능"으로 간주되어야하는 느낌이 있습니다. 내가 생각할 수있는 유일한 가능성은 인터페이스의 구현이 관심을 가질 것이라는 상수를 그룹화하는 것입니다.

일관성이 더 나은 접근 방식이었을 것이라는 데 동의합니다. 인터페이스에서 정적 멤버는 허용되지 않아야합니다.

객체를 만들지 않고 정적 메소드에 액세스 할 수 있으며 인터페이스는 프로그래머가 구현 된 클래스가 아닌 인터페이스 메소드를 직접 사용하는 것을 제한하는 객체를 만들 수 없습니다. 그러나 인터페이스에서 정적 메소드를 정의하면 구현없이 직접 액세스 할 수 있습니다. 따라서 인터페이스에서는 정적 메소드가 허용되지 않습니다. 나는 일관성이 우려가되어야한다고 생각하지 않습니다.

Java 1.8 인터페이스 정적 메소드는 인터페이스 메소드로만 표시됩니다. 인터페이스면 클래스에서 MethodSta1 () 메소드를 제거하는 경우 인터페이스 면축 객체에 사용할 수 없습니다. 그러나 다른 정적 메소드와 마찬가지로 클래스 이름을 사용하여 인터페이스 정적 메소드를 사용할 수 있습니다. 예를 들어, 유효한 진술은 다음과 같습니다. exp1.methodsta1 ();

따라서 아래 예제를 살펴본 후 1) Java 인터페이스 정적 메소드는 인터페이스의 일부이며 구현 클래스 객체에 사용할 수 없습니다.

2) Java 인터페이스 정적 메소드는 유틸리티 메소드 (예 : Null Check, Collection Sinding, Log 등)를 제공하는 데 좋습니다.

3) Java 인터페이스 정적 메소드는 구현 클래스 (인터페이스면)를 무시하지 않도록 보안을 제공하는 데 도움이됩니다.

4) 객체 클래스 메소드의 인터페이스 정적 메소드를 정의 할 수 없으며 "이 정적 메소드가 인스턴스 메소드를 객체에서 숨길 수 없기 때문에 컴파일러 오류가 발생합니다. 객체는 모든 클래스의 기본 클래스이며 하나의 클래스 레벨 정적 메소드와 동일한 서명을 가진 다른 인스턴스 메소드를 가질 수 없기 때문에 Java에서는 허용되지 않기 때문입니다.

5) Java 인터페이스 정적 메소드를 사용하여 컬렉션과 같은 유틸리티 클래스를 제거하고 모든 정적 메소드를 해당 인터페이스로 이동하여 쉽게 찾을 수 있습니다.

public class InterfaceExample implements exp1 {

    @Override
    public void method() {
        System.out.println("From method()");
    }

    public static void main(String[] args) {
        new InterfaceExample().method2();
        InterfaceExample.methodSta2();      //  <---------------------------    would not compile
        // methodSta1();                        //  <---------------------------    would not compile
        exp1.methodSta1();
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= InterfaceExample :: from methodSta2() ======");
    }
}


interface exp1 {

    void method();
    //protected void method1();         //          <--      error
    //private void method2();           //          <--      error
    //static void methodSta1();         //          <--      error it require body in java 1.8

    static void methodSta1() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta1() ======");
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta2() ======");
    }

    default void method2() { System.out.println("---  exp1:: from method2() ---");}
    //synchronized default void method3() { System.out.println("---");}             // <-- Illegal modifier for the interface method method3; only public, abstract, default, static 
                                                                                // and strictfp are permitted
    //final default void method3() { System.out.println("---");} //             <--      error
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top