[java] 왜 정적 메소드가 Java에서 추상적 일 수 없습니까?

문제는 Java에서 추상 정적 메소드를 정의 할 수없는 이유는 무엇입니까? 예를 들어

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}



답변

“추상”은 “기능 구현 없음”을 의미하고 “정적”은 “객체 인스턴스가 없어도 기능이 있음”을 의미하기 때문입니다. 그리고 그것은 논리적 모순입니다.


답변

언어 디자인이 잘못되었습니다. 해당 추상 메소드를 사용하기 위해 인스턴스를 작성하는 것보다 정적 추상 메소드를 직접 호출하는 것이 훨씬 더 효과적입니다. 열거를 확장 할 수없는 해결 방법으로 추상 클래스를 사용할 때 특히 그렇습니다. 이는 또 다른 열악한 디자인 예입니다. 다음 릴리스에서 이러한 한계를 해결하기를 바랍니다.


답변

정적 메서드를 재정의 할 수 없으므로 추상적으로 만드는 것은 의미가 없습니다. 또한 추상 클래스의 정적 메서드는 재정의 클래스가 아닌 해당 클래스에 속하므로 어쨌든 사용할 수 없었습니다.


답변

abstract메소드에 대한 주석은 메소드가 서브 클래스에서 대체되어야 함을 나타냅니다.

자바에서는 static멤버 (메소드 나 필드) A (이것은 다른 객체 지향 언어로, 스몰 토크를 참조하십시오. 반드시 사실이 아니다) 서브 클래스에 의해 오버라이드 (override) 할 수없는 static구성원이 될 수 있습니다 숨겨져 있지만,보다 근본적으로 다르다 오버라이드 (override) .

정적 멤버는 서브 클래스에서 재정의 abstract할 수 없으므로 주석을 적용 할 수 없습니다.

다른 언어는 인스턴스 상속과 마찬가지로 정적 상속도 지원합니다. 구문 관점에서 이러한 언어는 일반적으로 명령문에 클래스 이름을 포함해야합니다. 예를 들어, Java에서 ClassA로 코드를 작성한다고 가정하면 다음과 같은 명령문입니다 (methodA ()가 정적 메소드이고 동일한 서명을 가진 인스턴스 메소드가없는 경우).

ClassA.methodA();

methodA();

SmallTalk에서 클래스 이름은 선택 사항이 아니므로 구문은 다음과 같습니다 (SmallTalk는.를 사용하여 “제목”과 “동사”를 구분하지 않고 대신이를 상태 수정 종료 자로 사용합니다).

ClassA methodA.

클래스 이름은 항상 필요하므로 클래스 계층 구조를 통과하여 메소드의 올바른 “버전”을 항상 결정할 수 있습니다. 그 가치가 있기 때문에 때로는 static상속이 누락 되고 처음 시작할 때 Java에서 정적 상속이 부족하여 물 렸습니다. 또한 SmallTalk는 오리 형식이므로 계약별로 지원하지 않습니다. 따라서 abstract클래스 멤버를위한 수정자가 없습니다 .


답변

나는 또한 같은 질문을했다, 여기에 이유가있다.

Abstract 클래스가 말 했으므로 구현을 제공하지 않고 서브 클래스가 제공 할 수 있습니다

서브 클래스는 Superclass의 메소드를 재정의해야합니다.

규칙 NO 1정적 메서드는 재정의 할 수 없습니다

정적 멤버와 메서드는 컴파일 타임 요소이므로 정적 메서드의 오버로드 (컴파일 타임 다형성)가 재정의 (런타임 다형성)보다 허용되는 이유

그래서 그들은 추상적 일 수 없습니다.

추상 정적 <— 와 같은 것은 없습니다 . Java Universe에서는 허용되지 않습니다.


답변

이것은 끔찍한 언어 디자인이며 실제로 불가능한 이유는 없습니다.

실제로 다음은 JAVA 에서 수행 할 있는 방법에 대한 구현입니다 .

public class Main {

        public static void main(String[] args) {
                // This is done once in your application, usually at startup
                Request.setRequest(new RequestImplementationOther());

                Request.doSomething();
        }

        public static final class RequestImplementationDefault extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something AAAAAA");
                }
        }

        public static final class RequestImplementaionOther extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something BBBBBB");
                }
        }

        // Static methods in here can be overriden
        public static abstract class Request {

                abstract void doSomethingImpl();

                // Static method
                public static void doSomething() {
                        getRequest().doSomethingImpl();
                }

                private static Request request;
                private static Request getRequest() {
                        // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. 
                        if ( request == null ) {
                                return request = new RequestImplementationDefault();
                        }
                        return request;
                }
                public static Request setRequest(Request r){
                        return request = r;
                }

        }
}

================= 아래의 예 =================

getRequest를 찾으십시오. getRequestImpl … setInstance를 호출하여 호출하기 전에 구현을 변경할 수 있습니다.

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Mo. Joseph
 * @date 16 mar 2012
 **/

public abstract class Core {


    // ---------------------------------------------------------------        
    private static Core singleton; 
    private static Core getInstance() {
        if ( singleton == null )
            setInstance( new Core.CoreDefaultImpl() );  // See bottom for CoreDefaultImpl

        return singleton;
    }    

    public static void setInstance(Core core) {
        Core.singleton = core;
    }
    // ---------------------------------------------------------------        



    // Static public method
    public static HttpServletRequest getRequest() {      
        return getInstance().getRequestImpl();
    }


    // A new implementation would override this one and call setInstance above with that implementation instance
    protected abstract HttpServletRequest getRequestImpl();




    // ============================ CLASSES =================================

    // ======================================================================
    // == Two example implementations, to alter getRequest() call behaviour 
    // == getInstance() have to be called in all static methods for this to work
    // == static method getRequest is altered through implementation of getRequestImpl
    // ======================================================================

    /** Static inner class CoreDefaultImpl */
    public static class CoreDefaultImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    }

     /** Static inner class CoreTestImpl : Alternative implementation */
    public static class CoreTestImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return new MockedRequest();
        }
    }       

}

다음과 같이 사용됩니다 :

static {
     Core.setSingleton(new Core.CoreDefaultImpl());

     // Or

     Core.setSingleton(new Core.CoreTestImpl());

     // Later in the application you might use

     Core.getRequest(); 

}


답변

  • 추상 메소드는 서브 클래스에서 대체 될 수 있도록 정의됩니다. 그러나 정적 메서드는 재정의 할 수 없습니다. 따라서 추상 정적 메소드를 갖는 것은 컴파일 타임 오류입니다.

    이제 다음 질문은 정적 메소드를 재정의 할 수없는 이유입니다.

  • 정적 메소드는 인스턴스가 아닌 특정 클래스에 속하기 때문입니다. 정적 메서드를 재정의하려고하면 컴파일이나 런타임 오류가 발생하지 않지만 컴파일러는 슈퍼 클래스의 정적 메서드를 숨길 수 있습니다.