your programing

Java에서 정적 메서드가 추상이 될 수없는 이유

lovepro 2020. 10. 3. 11:23
반응형

Java에서 정적 메서드가 추상이 될 수없는 이유


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

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

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


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


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


abstract메서드에 대한 주석은 메서드가 하위 클래스에서 재정의되어야 함을 나타냅니다.

Java에서 static멤버 (메서드 또는 필드)는 하위 클래스에 의해 재정의 될 수 없습니다 (다른 객체 지향 언어에서는 반드시 해당되는 것은 아닙니다. SmallTalk 참조). static멤버는 숨겨 질 수 있지만 재정의와 근본적으로 다릅니다 .

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

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

ClassA.methodA();

methodA();

SmallTalk에서 클래스 이름은 선택 사항이 아니므로 구문은 다음과 같습니다 (SmallTalk는 "subject"와 "verb"를 구분하기 위해.를 사용하지 않고 대신 statemend 종결 자로 사용함).

ClassA methodA.

클래스 이름이 항상 필요하기 때문에 메서드의 올바른 "버전"은 항상 클래스 계층 구조를 탐색하여 확인할 수 있습니다. 그만한 가치가 있기 때문에 나는 때때로 static상속을 놓치고 처음 시작했을 때 Java에서 정적 상속이 부족하다는 사실에 물렸다. 또한 SmallTalk는 duck 형식이므로 계약 별 프로그램을 지원하지 않습니다. 따라서 abstract클래스 멤버에 대한 수정자가 없습니다 .


나도 같은 질문을했는데 왜

Abstract 클래스가 말 했으므로 구현을 제공하지 않고 하위 클래스가 제공하도록 허용하지 않습니다.

그래서 Subclass는 Superclass의 메서드를 재정의해야합니다.

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

정적 멤버와 메서드는 컴파일 타임 요소이기 때문에 재정의 (런타임 다형성)보다 정적 메서드의 오버로딩 (컴파일 타임 다형성)이 허용됩니다.

그래서 그들은 Abstract 일 수 없습니다.

추상 정적 <--- 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(); 

}

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

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

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


정의에 따라 정적 메서드는를 알 필요가 없습니다 this. 따라서 가상 메서드 (를 통해 사용할 수있는 동적 하위 클래스 정보에 따라 오버로드되는)가 될 수 없습니다 this. 대신 정적 메서드 오버로드는 컴파일 타임에 사용할 수있는 정보만을 기반으로합니다 (즉, 슈퍼 클래스의 정적 메서드를 참조하면 슈퍼 클래스 메서드라고 부르지 만 하위 클래스 메서드는 호출하지 않음).

이것에 따르면 추상 정적 메서드는 정의 된 본문으로 참조를 대체하지 않기 때문에 매우 쓸모가 없습니다.


이미 엄청난 답변이 있음을 알지만 실용적인 해결책은 보이지 않습니다. 물론 이것은 실제 문제이며 Java에서이 구문을 제외 할 이유가 없습니다. 원래 질문에는 이것이 필요할 수있는 컨텍스트가 없기 때문에 컨텍스트와 솔루션을 모두 제공합니다.

동일한 클래스 묶음에 정적 메서드가 있다고 가정합니다. 이러한 메서드는 클래스 별 정적 메서드를 호출합니다.

class C1 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C1
    }
}
class C2 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C2
    }
}

doWork()의 방법 C1C2동일하다. 이러한 calsses가 많이있을 수 있습니다. C3 C4등. static abstract허용 된 경우 다음과 같은 작업을 수행하여 중복 코드를 제거합니다.

abstract class C {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }

    static abstract void doMoreWork(int k);
}

class C1 extends C {
    private static void doMoreWork(int k) {
        // code for class C1
    }
}

class C2 extends C {
    private static void doMoreWork(int k) {
        // code for class C2
    }
}

그러나 이것은 static abstract조합이 허용되지 않기 때문에 컴파일 되지 않습니다. 그러나 다음과 같이 static class허용되는 구성을 사용 하여 피할 수 있습니다 .

abstract class C {
    void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    abstract void doMoreWork(int k);
}
class C1 {
    private static final C c = new  C(){  
        @Override void doMoreWork(int k) {
            System.out.println("code for C1");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}
class C2 {
    private static final C c = new C() {
        @Override void doMoreWork(int k) {
            System.out.println("code for C2");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}

이 솔루션으로 복제되는 유일한 코드는

    public static void doWork() {
        c.doWork();
    }

두 개의 클래스가 있다고 가정 Parent하고 Child. Parent입니다 abstract. 선언은 다음과 같습니다.

abstract class Parent {
    abstract void run();
}

class Child extends Parent {
    void run() {}
}

이는의 모든 인스턴스 가 실행 Parent방법을 지정해야 함을 의미합니다 run().

그러나 지금 Parentabstract.

class Parent {
    static void run() {}
}

이것은 Parent.run()정적 메서드를 실행 한다는 것을 의미합니다 .

abstract메서드 의 정의 는 "선언되었지만 구현되지 않은 메서드"이며, 이는 자체적으로 아무것도 반환하지 않음을 의미합니다.

static메소드 의 정의 는 "호출 된 인스턴스에 관계없이 동일한 매개 변수에 대해 동일한 값을 리턴하는 메소드"입니다.

abstract메소드의 반환 값은 인스턴스 변화에 따라 변경됩니다. static방법은하지 않습니다. static abstract방법은 거의 반환 값이 일정한 방법이지만 아무것도 반환하지 않습니다. 이것은 논리적 모순입니다.

또한 static abstract방법 에 대한 이유가별로 없습니다 .


추상 클래스는 DYNAMIC BINDING을 달성하기 위해 추상화가 수행되는 반면 정적 메서드는 기능에 정적으로 바인딩되기 때문에 정적 메서드를 가질 수 없습니다. 정적 메서드는 인스턴스 변수에 종속되지 않는 동작을 의미하므로 인스턴스 / 객체가 필요하지 않습니다. 정적 메서드는 객체가 아닌 클래스에 속합니다. 그것들은 모든 객체와 공유되는 PERMGEN이라는 메모리 영역에 저장됩니다. 추상 클래스의 메서드는 해당 기능에 동적으로 바인딩됩니다.


클래스의 인스턴스없이 정적 메서드를 호출 할 수 있습니다. 귀하의 예제에서는 foo.bar2 ()를 호출 할 수 있지만 foo.bar ()는 호출 할 수 없습니다. bar의 경우 인스턴스가 필요하기 때문입니다. 다음 코드가 작동합니다.

foo var = new ImplementsFoo();
var.bar();

정적 메서드를 호출하면 항상 동일한 코드로 실행됩니다. 위의 예에서 ImplementsFoo에서 bar2를 재정의하더라도 var.bar2 ()를 호출하면 foo.bar2 ()가 실행됩니다.

bar2에 구현이없는 경우 (추상적 인 의미) 구현없이 메서드를 호출 할 수 있습니다. 그것은 매우 해 롭습니다.


이 질문에 대한 답을 찾았다 고 생각합니다. 인터페이스의 메서드 (부모 클래스의 추상 메서드처럼 작동)가 정적 일 수없는 이유입니다. 여기에 전체 답변이 있습니다 (내가 아님)

Basically static methods can be bound at compile time, since to call them you need to specify a class. This is different than instance methods, for which the class of the reference from which you're calling the method may be unknown at compile time (thus which code block is called can only be determined at runtime).

If you're calling a static method, you already know the class where it's implemented, or any direct subclasses of it. If you define

abstract class Foo {
    abstract static void bar();
}

class Foo2 {
    @Override
    static void bar() {}
}

Then any Foo.bar(); call is obviously illegal, and you will always use Foo2.bar();.

With this in mind, the only purpose of a static abstract method would be to enforce subclasses to implement such a method. You might initially think this is VERY wrong, but if you have a generic type parameter <E extends MySuperClass> it would be nice to guarantee via interface that E can .doSomething(). Keep in mind that due to type erasure generics only exist at compile time.

So, would it be useful? Yes, and maybe that is why Java 8 is allowing static methods in interfaces (though only with a default implementation). Why not abstract static methods with a default implementation in classes? Simply because an abstract method with a default implementation is actually a concrete method.

Why not abstract/interface static methods with no default implementation? Apparently, merely because of the way Java identifies which code block it has to execute (first part of my answer).


Declaring a method as static means we can call that method by its class name and if that class is abstract as well, it makes no sense to call it as it does not contain any body, and hence we cannot declare a method both as static and abstract.


Because abstract class is an OOPS concept and static members are not the part of OOPS....
Now the thing is we can declare static complete methods in interface and we can execute interface by declaring main method inside an interface

interface Demo 
{
  public static void main(String [] args) {
     System.out.println("I am from interface");
  }
}

The idea of having an abstract static method would be that you can't use that particular abstract class directly for that method, but only the first derivative would be allowed to implement that static method (or for generics: the actual class of the generic you use).

That way, you could create for example a sortableObject abstract class or even interface with (auto-)abstract static methods, which defines the parameters of sort options:

public interface SortableObject {
    public [abstract] static String [] getSortableTypes();
    public String getSortableValueByType(String type);
}

Now you can define a sortable object that can be sorted by the main types which are the same for all these objects:

public class MyDataObject implements SortableObject {
    final static String [] SORT_TYPES = {
        "Name","Date of Birth"
    }
    static long newDataIndex = 0L ;

    String fullName ;
    String sortableDate ;
    long dataIndex = -1L ;
    public MyDataObject(String name, int year, int month, int day) {
        if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
        if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
        this.fullName = name ;
        this.sortableDate = MyUtils.createSortableDate(year,month,day);
        this.dataIndex = MyDataObject.newDataIndex++ ;
    }
    public String toString() {
        return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
    }

    // override SortableObject 
    public static String [] getSortableTypes() { return SORT_TYPES ; }
    public String getSortableValueByType(String type) {
        int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
        switch(index) {
             case 0: return this.name ;
             case 1: return this.sortableDate ;
        }
        return toString(); // in the order they were created when compared
    }
}

Now you can create a

public class SortableList<T extends SortableObject> 

that can retrieve the types, build a pop-up menu to select a type to sort on and resort the list by getting the data from that type, as well as hainv an add function that, when a sort type has been selected, can auto-sort new items in. Note that the instance of SortableList can directly access the static method of "T":

String [] MenuItems = T.getSortableTypes();

The problem with having to use an instance is that the SortableList may not have items yet, but already need to provide the preferred sorting.

Cheerio, Olaf.


First, a key point about abstract classes - An abstract class cannot be instantiated (see wiki). So, you can't create any instance of an abstract class.

Now, the way java deals with static methods is by sharing the method with all the instances of that class.

So, If you can't instantiate a class, that class can't have abstract static methods since an abstract method begs to be extended.

Boom.


As per Java doc:

A static method is a method that is associated with the class in which it is defined rather than with any object. Every instance of the class shares its static methods

In Java 8, along with default methods static methods are also allowed in an interface. This makes it easier for us to organize helper methods in our libraries. We can keep static methods specific to an interface in the same interface rather than in a separate class.

A nice example of this is:

list.sort(ordering);

instead of

Collections.sort(list, ordering);

Another example of using static methods is also given in doc itself:

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

Because 'abstract' means the method is meant to be overridden and one can't override 'static' methods.


You can do this with interfaces in Java 8.

This is the official documentation about it:

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


Regular methods can be abstract when they are meant to be overridden by subclasses and provided with functionality. Imagine the class Foo is extended by Bar1, Bar2, Bar3 etc. So, each will have their own version of the abstract class according to their needs.

Now, static methods by definition belong to the class, they have nothing to do with the objects of the class or the objects of its subclasses. They don't even need them to exist, they can be used without instantiating the classes. Hence, they need to be ready-to-go and cannot depend on the subclasses to add functionality to them.


Because abstract is a keyword which is applied over Abstract methods do not specify a body. And If we talk about static keyword it belongs to class area.


because if you are using any static member or static variable in class it will load at class loading time.


Because if a class extends an abstract class then it has to override abstract methods and that is mandatory. And since static methods are class methods resolved at compile time whereas overridden methods are instance methods resolved at runtime and following dynamic polymorphism.

참고URL : https://stackoverflow.com/questions/370962/why-cant-static-methods-be-abstract-in-java

반응형