Warum können statische Methoden in Java nicht abstrakt sein?


593

Die Frage ist in Java, warum ich keine abstrakte statische Methode definieren kann. zum Beispiel

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

9
Einige Gründe: Die statische Methode muss einen Body haben, auch wenn sie Teil einer abstrakten Klasse ist, da keine Instanz einer Klasse erstellt werden muss, um auf ihre statische Methode zuzugreifen. Wenn Sie für einen Moment davon ausgehen, dass dies zulässig ist, besteht das Problem darin, dass statische Methodenaufrufe keine RTTI (Run Time Type Information) bereitstellen. Denken Sie daran, dass keine Instanzerstellung erforderlich ist und daher nicht umgeleitet werden kann Es macht überhaupt keinen Sinn, auf ihre spezifischen Overriden-Implementierungen zuzugreifen und damit statische Abstraktionen zuzulassen. Mit anderen Worten, es konnte keinen Polymorphismusvorteil bieten, der somit nicht zulässig war.
Sactiw

6
Wenn Sie etwas haben, um die Frage zu beantworten, posten Sie es als Antwort , nicht als Kommentar
Solomon Ucko

Antworten:


568

Denn "abstrakt" bedeutet: "Implementiert keine Funktionalität" und "statisch" bedeutet: "Es gibt Funktionalität, auch wenn Sie keine Objektinstanz haben". Und das ist ein logischer Widerspruch.


353
Eine präzisere Antwort wäre "schlechtes Sprachdesign". Statisch sollte bedeuten, dass es zur Klasse gehört, da es so intuitiv verwendet wird, wie genau diese Frage zeigt. Siehe "Klassenmethode" in Python.
Alexander Ljungberg

12
@Tomalak Ich entschuldige mich, ich war nicht klar. Natürlich gehört eine statische Methode 'zur Klasse'. Dennoch ist es nur in dem Sinne, dass es im gleichen Namespace lebt. Eine statische Methode ist keine Methode des Klassenobjekts selbst: Sie arbeitet nicht mit 'this' als Klassenobjekt und nimmt nicht ordnungsgemäß an der Vererbungskette teil. Wenn es wirklich eine Klassenmethode abstract staticwäre, wäre das vollkommen sinnvoll. Es wäre eine Methode des Klassenobjekts selbst, die Unterklassenobjekte implementieren müssen. Natürlich ist die Art und Weise, wie Ihre Antwort steht, richtig, obwohl ich mich mit der Sprache befasst habe.
Alexander Ljungberg

695
Es ist kein logischer Widerspruch, es ist ein Sprachmangel, mehrere andere Sprachen unterstützen diesen Begriff. "abstrakt" bedeutet "in Unterklassen implementiert", "statisch" bedeutet "in der Klasse ausgeführt und nicht in Klasseninstanzen". Es gibt keinen logischen Widerspruch.
Eric Grange

10
@Eric: Und dennoch gilt das, was Sie sagen, nicht für abstract static: Eine Funktion X, die "in der Unterklasse implementiert" ist, kann nicht gleichzeitig "in der Klasse ausgeführt" werden - nur in der Unterklasse . Wo es dann nicht mehr abstrakt ist.
Tomalak

72
@ Tomakak: Deine Logik ist kreisförmig. staticbedeutet nicht "nicht leer" - das ist nur eine Folge von Java, das nicht zulässt, dass statische Methoden abstrakt sind. Es bedeutet "aufrufbar für die Klasse". (Es sollte " nur für die Klasse aufrufbar" bedeuten, aber das ist ein anderes Problem.) Wenn Java abstract staticMethoden unterstützt , würde ich erwarten, dass die Methode 1) von Unterklassen implementiert werden muss und 2) eine Klassenmethode der Unterklasse ist. Einige Methoden sind als Instanzmethoden einfach nicht sinnvoll. Leider können Sie dies in Java beim Erstellen einer abstrakten Basisklasse (oder einer Schnittstelle) nicht angeben.
Michael Carman

326

Schlechtes Sprachdesign. Es wäre viel effektiver, eine statische abstrakte Methode direkt aufzurufen, als eine Instanz nur für die Verwendung dieser abstrakten Methode zu erstellen. Dies gilt insbesondere dann, wenn eine abstrakte Klasse als Problemumgehung für die Enum-Unfähigkeit zum Erweitern verwendet wird. Dies ist ein weiteres schlechtes Designbeispiel. Ich hoffe, sie lösen diese Einschränkungen in einer nächsten Version.


25
Java ist voller seltsamer Einschränkungen. Abschlüsse, die nur auf endgültige Variablen zugreifen, sind andere. Und die verbleibende Liste ist fast endlos. Es ist die Aufgabe eines Java-Programmierers, sie und ihre Problemumgehungen zu kennen. Um Spaß zu haben, müssen wir in unserer Freizeit etwas Besseres als Java verwenden. Aber ich würde mich nicht darum kümmern. Das ist der Keim, um Fortschritte zu erzielen.
Ceving

22
Ich glaube, dass das, was Sie als "schlechtes Sprachdesign" bezeichnen, eher ein "schützendes Sprachdesign" ist, mit dem die Verstöße gegen das OO-Prinzip, die Programmierer aufgrund unnötiger Sprachfunktionen begehen, begrenzt werden sollen.
Ethanfar

22
Ist das Konzept der "abstrakten Statik" eine Verletzung der OO-Prinzipien?
Trevor

7
@threed, überhaupt nicht, aber natürlich gibt es Leute, die sagen, dass das bloße Konzept von sich staticselbst bereits eine Verletzung ist ....
Pacerier

4
Die Notwendigkeit von Statik ist ein klarer Beweis dafür, dass "OO-Prinzipien" nicht so umfassend sind, wie normalerweise behauptet.
Ben

147

Sie können eine statische Methode nicht überschreiben, daher wäre es bedeutungslos, sie abstrakt zu machen. Darüber hinaus würde eine statische Methode in einer abstrakten Klasse zu dieser Klasse gehören und nicht zur übergeordneten Klasse, sodass sie ohnehin nicht verwendet werden kann.


18
Ja, es ist wirklich eine Schande, dass statische Methoden in Java nicht überschrieben werden können.
Michel

12
@ Michael: Was wäre der Punkt? Wenn Sie ein instanzbasiertes Verhalten wünschen, verwenden Sie Instanzmethoden.
Ran Biron

8
Diese Antwort ist falsch. Statische Methoden in abstrakten Klassen funktionieren einwandfrei und werden häufig verwendet. Es ist nur so, dass eine statische Methode der Klasse selbst möglicherweise nicht abstrakt ist. @Michel Es macht keinen Sinn, eine statische Methode zu überschreiben. Wie würde die Laufzeit ohne eine Instanz wissen, welche Methode aufgerufen werden soll?
Erickson

63
@erickson - Auch ohne Instanz ist die Klassenhierarchie intakt - die Vererbung statischer Methoden kann genauso funktionieren wie die Vererbung von Instanzmethoden. Smalltalk macht es und es ist sehr nützlich.
Jared

8
@matiasg das ist überhaupt nichts Neues. Abstrakte Klassen durften immer statische, nicht abstrakte Methoden haben.
Matt Ball

70

Die abstractAnmerkung zu einer Methode gibt an, dass die Methode in einer Unterklasse überschrieben werden muss.

In Java kann ein staticMitglied (Methode oder Feld) nicht durch Unterklassen überschrieben werden (dies gilt nicht unbedingt für andere objektorientierte Sprachen, siehe SmallTalk). Ein staticMitglied kann ausgeblendet sein , dies unterscheidet sich jedoch grundlegend von dem überschriebenen .

Da statische Elemente in einer Unterklasse nicht überschrieben werden können, kann die abstractAnmerkung nicht auf sie angewendet werden.

Abgesehen davon unterstützen andere Sprachen die statische Vererbung, genau wie die Instanzvererbung. Aus syntaktischer Sicht erfordern diese Sprachen normalerweise, dass der Klassenname in der Anweisung enthalten ist. In Java sind dies beispielsweise unter der Annahme, dass Sie Code in ClassA schreiben, äquivalente Anweisungen (wenn methodA () eine statische Methode ist und es keine Instanzmethode mit derselben Signatur gibt):

ClassA.methodA();

und

methodA();

In SmallTalk ist der Klassenname nicht optional, daher lautet die Syntax (beachten Sie, dass SmallTalk das. Nicht verwendet, um das "Subjekt" und das "Verb" zu trennen, sondern es stattdessen als Abschlusszeichen für statemend verwendet):

ClassA methodA.

Da der Klassenname immer erforderlich ist, kann die richtige "Version" der Methode immer durch Durchlaufen der Klassenhierarchie ermittelt werden. Für das, was es wert ist, vermisse ich gelegentlich die staticVererbung und wurde von dem Mangel an statischer Vererbung in Java gebissen, als ich damit anfing. Darüber hinaus ist SmallTalk vom Typ Ente (und unterstützt daher kein vertragliches Programm). Daher gibt es keinen abstractModifikator für Klassenmitglieder.


1
"Ein statisches Mitglied kann nicht von Unterklassen überschrieben werden" ist falsch. Zumindest in Java6 ist dies möglich. Ich bin mir nicht sicher, wann es der Fall ist.
Steven De Groote

15
@Steven De Groote Ein statisches Mitglied kann in der Tat nicht von Unterklassen überschrieben werden. Wenn eine Unterklasse eine statische Methode mit derselben Signatur wie eine statische Methode in der Oberklasse hat, wird sie nicht überschrieben, sondern ausgeblendet. http://docs.oracle.com/javase/tutorial/java/IandI/override.html Der Unterschied besteht darin, dass Polymorphismus nur für überschriebene, nicht aber für versteckte Methoden funktioniert.
John29

2
@ John29 Danke für die Klarstellung, aber abgesehen von dem Namensunterschied scheint es in der Verwendung ähnlich zu sein.
Steven De Groote

2
@Steven De Groote Ja, es wird ähnlich verwendet, aber das Verhalten ist anders. Das ist der Grund, warum es keine statischen abstrakten Methoden gibt - was bringt es, wenn statische abstrakte Methoden keinen Polymorphismus unterstützen?
John29

3
@Steven De Groote: Der Unterschied wird deutlich, wenn Sie diese Methode in der Oberklasse selbst aufrufen. Angenommen, Super.foo ruft Super.bar auf. Wenn eine Unterklasse Subclass.bar implementiert und dann foo aufruft, ruft foo weiterhin Super.bar auf, nicht Subclass.bar. Was Sie also wirklich haben, sind zwei völlig unterschiedliche und nicht verwandte Methoden, die beide als "Balken" bezeichnet werden. Dies ist in keinem nützlichen Sinne außer Kraft zu setzen.
Doradus

14

Ich habe auch die gleiche Frage gestellt, hier ist warum

Da die Abstract-Klasse sagt, wird sie keine Implementierung geben und es der Unterklasse erlauben, sie zu geben

Die Unterklasse muss also die Methoden der Oberklasse überschreiben.

REGEL NR. 1 - Eine statische Methode kann nicht überschrieben werden

Da statische Elemente und Methoden Elemente zur Kompilierungszeit sind, ist das Überladen (Polymorphismus der Kompilierungszeit) statischer Methoden eher zulässig als das Überschreiben (Laufzeitpolymorphismus).

Sie können also nicht abstrakt sein.

Es gibt nichts wie abstrakte statische <--- In Java Universe nicht erlaubt


5
-1, Es ist nicht wahr, dass "Java nicht zulässt, dass statische Methoden überschrieben werden, da statische Elemente und Methoden Elemente der Kompilierungszeit sind". Statische Typprüfung ist auf jeden Fall möglich , abstract staticsiehe stackoverflow.com/questions/370962/... . Der wahre Grund, warum Java das Überschreiben statischer Methoden nicht zulässt, liegt darin, dass Java das Überschreiben statischer Methoden nicht zulässt.
Pacerier

Überladung hat nichts mit Polymorphismus zu tun. Überladen und Überschreiben haben nichts gemeinsam, außer dem Präfix "over", ähnlich wie Java und JavaScript "Java" enthalten. Der Name einer Methode ist nicht die Identität, sondern die Signatur. so foo(String)ist es nicht dasselbe wie foo(Integer)- das ist alles was es ist.
Captain Man

@CaptainMan Overloading wird wörtlich als "parametrischer Polymorphismus" bezeichnet, da je nach Art des Parameters eine andere Methode aufgerufen wird, nämlich Polymorphismus.
Davor

12

Dies ist ein schreckliches Sprachdesign und wirklich kein Grund, warum es nicht möglich sein kann.

In der Tat, hier ist eine Implementierung, wie es CAN in getan werden , 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;
                }

        }
}

================= Altes Beispiel unten =================

Suchen Sie nach getRequest, und getRequestImpl ... setInstance kann aufgerufen werden, um die Implementierung zu ändern, bevor der Aufruf erfolgt.

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

}

Wird wie folgt verwendet:

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

     // Or

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

     // Later in the application you might use

     Core.getRequest(); 

}

6
Ich habe nicht verstanden, wo Sie ein Beispiel für eine abstract staticMethode angegeben haben, wie sie in der Frage gestellt wurde, und Sie haben in Fettdruck geschrieben, KANN IN JAVA GEMACHT WERDEN . Das ist völlig falsch.
Blip

1
Es erlaubt Ihnen per se nicht, es als abstrakte statische zu definieren, aber Sie können ein ähnliches Ergebnis erzielen, wobei Sie die Implementierung der statischen Methode mithilfe dieses Musters / Hacks ändern können. Es ist kaum falsch. Dies ist möglich, jedoch mit unterschiedlicher Semantik.
mmm

Dies ist ein Beispiel für das Erweitern einer abstrakten Klasse und das anschließende Einfügen der statischen Methoden in das untergeordnete Element. Dies ist in keiner Weise ein Beispiel für CAN CAN IN JAVA.
Scuba Steve

2
@ScubaSteve Erstens sind Sie in Ihrer Schlussfolgerung falsch. Zweitens wird das gleiche Ergebnis erzielt. Dies bedeutet, dass der statische Zugriff auf eine Klasse durch eine andere Implementierung geändert werden kann. Es ist keine Antwort darauf, dass ich das statische Schlüsselwort abstrahierbar gemacht habe, aber mit diesem Muster können Sie statische Methoden verwenden und trotzdem deren Implementierung ändern. Es hat zwar den negativen Effekt, nur global zu sein, aber für eine Test- / Produkt- / Entwicklungsumgebung ist es der Trick für uns.
mmm

5
  • Eine abstrakte Methode ist nur so definiert, dass sie in einer Unterklasse überschrieben werden kann. Statische Methoden können jedoch nicht überschrieben werden. Daher ist es ein Fehler bei der Kompilierung, eine abstrakte, statische Methode zu haben.

    Nun ist die nächste Frage, warum statische Methoden nicht überschrieben werden können?

  • Dies liegt daran, dass statische Methoden zu einer bestimmten Klasse und nicht zu ihrer Instanz gehören. Wenn Sie versuchen, eine statische Methode zu überschreiben, wird kein Kompilierungs- oder Laufzeitfehler angezeigt, aber der Compiler würde nur die statische Methode der Oberklasse ausblenden.


4

Eine statische Methode muss per Definition nicht wissen this. Daher kann es sich nicht um eine virtuelle Methode handeln (die gemäß den über verfügbaren dynamischen Unterklasseninformationen überladen ist this). Stattdessen basiert eine statische Methodenüberladung ausschließlich auf Informationen, die zum Zeitpunkt der Kompilierung verfügbar sind (dies bedeutet: Wenn Sie eine statische Methode der Oberklasse referenzieren, rufen Sie nämlich die Oberklassenmethode auf, jedoch niemals eine Unterklassenmethode).

Demnach wären abstrakte statische Methoden völlig nutzlos, da die Referenz niemals durch einen definierten Körper ersetzt wird.


4

Ich sehe, dass es bereits unzählige Antworten gibt, aber ich sehe keine praktischen Lösungen. Dies ist natürlich ein echtes Problem und es gibt keinen guten Grund, diese Syntax in Java auszuschließen. Da der ursprünglichen Frage ein Kontext fehlt, in dem dies erforderlich sein könnte, biete ich sowohl einen Kontext als auch eine Lösung an:

Angenommen, Sie haben eine statische Methode in einer Reihe von Klassen, die identisch sind. Diese Methoden rufen eine statische Methode auf, die klassenspezifisch ist:

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()Methoden in C1und C2sind identisch. Möglicherweise gibt es viele dieser Probleme: C3 C4usw. Wenn dies static abstractzulässig wäre, würden Sie den doppelten Code entfernen , indem Sie Folgendes tun:

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

Dies würde jedoch nicht kompiliert, da eine static abstractKombination nicht zulässig ist. Dies kann jedoch mit einem static classKonstrukt umgangen werden , das erlaubt ist:

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

Mit dieser Lösung wird nur Code dupliziert

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

1
Da in Ihrer endgültigen Lösung die abstrakte Klasse C keine statischen Methoden hat, lassen Sie C1 und C2 sie einfach erweitern und die Methode doMoreWork () überschreiben und alle anderen Klassen ihre Instanz erstellen und die erforderlichen Methoden aufrufen. Grundsätzlich machen Sie dasselbe, dh erweitern Sie Klasse C mit einer anonymen Klasse und dann in C1 und C2 mit ihrer statischen Instanz, um den Zugriff innerhalb einer statischen Methode zu ermöglichen, dies ist jedoch überhaupt nicht erforderlich.
Sactiw

Ich verstehe den Kontext, den Sie hier angegeben haben, nicht. In Ihrer endgültigen Lösung können Sie anrufen C1.doWork()oder C2.doWork()Sie können jedoch nicht anrufen C.doWork(). Nehmen wir auch in dem von Ihnen bereitgestellten Beispiel an, was nicht funktioniert. Angenommen, wenn dies zulässig war, wie findet die Klasse dann Cdie Implementierung von doMoreWork()? Schließlich würde ich Ihren Kontextcode als schlechtes Design bezeichnen. Warum? einfach, weil Sie eine separate Funktion für den Code erstellt haben, die eindeutig ist, anstatt eine Funktion für den gemeinsamen Code zu erstellen und dann eine statische Funktion in der Klasse zu implementieren C. Das ist einfacher !!!
Blip

2

Angenommen, es gibt zwei Klassen Parentund Child. Parentist abstract. Die Erklärungen lauten wie folgt:

abstract class Parent {
    abstract void run();
}

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

Dies bedeutet, dass jede Instanz von Parentangeben muss, wie sie run()ausgeführt wird.

Nehmen wir jetzt jedoch an, dass dies Parentnicht der Fall ist abstract.

class Parent {
    static void run() {}
}

Dies bedeutet, Parent.run()dass die statische Methode ausgeführt wird.

Die Definition einer abstractMethode lautet "Eine Methode, die deklariert, aber nicht implementiert ist", was bedeutet, dass sie selbst nichts zurückgibt.

Die Definition einer staticMethode lautet "Eine Methode, die unabhängig von der Instanz, auf der sie aufgerufen wird, denselben Wert für dieselben Parameter zurückgibt".

abstractDer Rückgabewert einer Methode ändert sich, wenn sich die Instanz ändert. Eine staticMethode wird nicht. Eine static abstractMethode ist so ziemlich eine Methode, bei der der Rückgabewert konstant ist, aber nichts zurückgibt. Dies ist ein logischer Widerspruch.

Es gibt auch wirklich keinen Grund für eine static abstractMethode.


2

Eine abstrakte Klasse kann keine statische Methode haben, da eine Abstraktion durchgeführt wird, um eine DYNAMISCHE BINDUNG zu erreichen, während statische Methoden statisch an ihre Funktionalität gebunden sind. Eine statische Methode bedeutet, dass das Verhalten nicht von einer Instanzvariablen abhängig ist, sodass keine Instanz / kein Objekt erforderlich ist. Nur die Klasse. Statische Methoden gehören zur Klasse und nicht zum Objekt. Sie werden in einem als PERMGEN bekannten Speicherbereich gespeichert, von wo aus sie mit jedem Objekt gemeinsam genutzt werden. Methoden in abstrakten Klassen werden dynamisch an ihre Funktionalität gebunden.


1
Abstrakte Klassen können sicherlich statische Methoden haben. Aber keine statischen abstrakten Methoden.
JacksOnF1re

2

Deklarieren eine Methode als staticMittel , die wir diese Methode von seinen Klassennamen aufrufen können und wenn diese Klasse ist abstractauch, macht es keinen Sinn , es zu nennen , da es keinen Körper enthält, und daher können wir keine Methode deklarieren sowohl als staticund abstract.


2

Da abstrakte Methoden zur Klasse gehören und von der implementierenden Klasse nicht überschrieben werden können. Auch wenn es eine statische Methode mit derselben Signatur gibt, wird die Methode ausgeblendet und nicht überschrieben. Daher ist es unerheblich, die abstrakte Methode als statisch zu deklarieren, da sie niemals den Körper erhält. Daher Fehler beim Kompilieren.


1

Eine statische Methode kann ohne eine Instanz der Klasse aufgerufen werden. In Ihrem Beispiel können Sie foo.bar2 () aufrufen, nicht jedoch foo.bar (), da Sie für bar eine Instanz benötigen. Der folgende Code würde funktionieren:

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

Wenn Sie eine statische Methode aufrufen, wird immer derselbe Code ausgeführt. Selbst wenn Sie im obigen Beispiel bar2 in ImplementsFoo neu definieren, würde ein Aufruf von var.bar2 () foo.bar2 () ausführen.

Wenn bar2 jetzt keine Implementierung hat (was abstrakt bedeutet), können Sie eine Methode ohne Implementierung aufrufen. Das ist sehr schädlich.


1
Eine abstrakte statische Methode könnte ohne Instanz aufgerufen werden, erfordert jedoch die Erstellung einer Implementierung in der untergeordneten Klasse. Es ist nicht gerade Polymorphismus, aber die einzige Möglichkeit, dies zu umgehen, besteht darin, dass das konkrete Kind eine Schnittstelle implementiert, die die "abstrakte statische" Methode "erfordert". Chaotisch, aber praktikabel.
Fijiaaron

3
Eigentlich habe ich mich geirrt. Sie können auch keine statischen Methoden in einer Schnittstelle haben. Sprachfehler.
Fijiaaron

1

Ich glaube, ich habe die Antwort auf diese Frage in der Form gefunden, warum die Methoden einer Schnittstelle (die wie abstrakte Methoden in einer übergeordneten Klasse funktionieren) nicht statisch sein können. Hier ist die vollständige Antwort (nicht meine)

Grundsätzlich können statische Methoden zur Kompilierungszeit gebunden werden, da Sie zum Aufrufen eine Klasse angeben müssen. Dies unterscheidet sich von Instanzmethoden, für die die Klasse der Referenz, von der aus Sie die Methode aufrufen, zur Kompilierungszeit möglicherweise unbekannt ist (daher kann der aufgerufene Codeblock nur zur Laufzeit bestimmt werden).

Wenn Sie eine statische Methode aufrufen, kennen Sie bereits die Klasse, in der sie implementiert ist, oder direkte Unterklassen davon. Wenn Sie definieren

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

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

Dann ist jeder Foo.bar();Anruf offensichtlich illegal und wird immer verwendet Foo2.bar();.

Vor diesem Hintergrund besteht der einzige Zweck einer statischen abstrakten Methode darin, Unterklassen zur Implementierung einer solchen Methode zu erzwingen. Sie könnten zunächst denken, dass dies SEHR falsch ist, aber wenn Sie einen generischen Typparameter <E extends MySuperClass>haben, wäre es schön, dies über eine Schnittstelle zu garantieren, die dies Ekann .doSomething(). Beachten Sie, dass Generika aufgrund von Typlöschungen nur zur Kompilierungszeit vorhanden sind.

Wäre es also nützlich? Ja, und vielleicht erlaubt Java 8 deshalb statische Methoden in Schnittstellen (allerdings nur mit einer Standardimplementierung). Warum nicht abstrakte statische Methoden mit einer Standardimplementierung in Klassen? Einfach, weil eine abstrakte Methode mit einer Standardimplementierung tatsächlich eine konkrete Methode ist.

Warum nicht abstrakte / Schnittstellen-statische Methoden ohne Standardimplementierung? Anscheinend nur aufgrund der Art und Weise, wie Java identifiziert, welchen Codeblock es ausführen muss (erster Teil meiner Antwort).


1

Da die abstrakte Klasse ein OOPS-Konzept ist und statische Elemente nicht Teil von OOPS sind ...
Jetzt können wir statische vollständige Methoden in der Schnittstelle deklarieren und die Schnittstelle ausführen, indem wir die Hauptmethode innerhalb einer Schnittstelle deklarieren

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

0

Die Idee einer abstrakten statischen Methode wäre, dass Sie diese bestimmte abstrakte Klasse nicht direkt für diese Methode verwenden können, sondern nur die erste Ableitung diese statische Methode implementieren darf (oder für Generika: die tatsächliche Klasse des generischen Sie verwenden).

Auf diese Weise können Sie beispielsweise eine abstrakte Klasse sortableObject oder sogar eine Schnittstelle mit (automatisch) abstrakten statischen Methoden erstellen, die die Parameter der Sortieroptionen definiert:

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

Jetzt können Sie ein sortierbares Objekt definieren, das nach den Haupttypen sortiert werden kann, die für alle diese Objekte gleich sind:

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

Jetzt können Sie eine erstellen

public class SortableList<T extends SortableObject> 

Das kann die Typen abrufen, ein Popup-Menü erstellen, um einen Typ zum Sortieren auszuwählen und die Liste neu abzurufen, indem die Daten von diesem Typ abgerufen werden, sowie eine Add-Funktion haben, die, wenn ein Sortiertyp ausgewählt wurde, automatisch ausgeführt werden kann -sortieren Sie neue Elemente in. Beachten Sie, dass die Instanz von SortableList direkt auf die statische Methode von "T" zugreifen kann:

String [] MenuItems = T.getSortableTypes();

Das Problem bei der Verwendung einer Instanz besteht darin, dass die SortableList möglicherweise noch keine Elemente enthält, aber bereits die bevorzugte Sortierung bereitstellen muss.

Cheerio, Olaf.


0

Erstens ein wichtiger Punkt zu abstrakten Klassen - Eine abstrakte Klasse kann nicht instanziiert werden (siehe Wiki ). Sie können also keine Instanz einer abstrakten Klasse erstellen .

Die Art und Weise, wie Java mit statischen Methoden umgeht, besteht darin, die Methode für alle Instanzen dieser Klasse freizugeben.

Wenn Sie eine Klasse nicht instanziieren können, kann diese Klasse keine abstrakten statischen Methoden haben, da eine abstrakte Methode erweitert werden muss.

Boom.


Jede Methode in einer abstrakten Klasse muss ohnehin erweitert werden, damit sie ausgeführt werden kann. Dies ist also keine Entschuldigung. Sie können die abstrakte Klasse erweitern (gleichzeitig die abstrakte Methode implementieren). Das funktioniert also nicht als Erklärung.
Pere

0

Gemäß Java- Dokument :

Eine statische Methode ist eine Methode, die der Klasse zugeordnet ist, in der sie definiert ist, und nicht einem Objekt. Jede Instanz der Klasse teilt ihre statischen Methoden

In Java 8 sind neben Standardmethoden auch statische Methoden in einer Schnittstelle zulässig. Dies erleichtert uns die Organisation von Hilfsmethoden in unseren Bibliotheken. Wir können statische Methoden, die für eine Schnittstelle spezifisch sind, in derselben Schnittstelle und nicht in einer separaten Klasse aufbewahren.

Ein schönes Beispiel dafür ist:

list.sort(ordering);

anstatt

Collections.sort(list, ordering);

Ein weiteres Beispiel für die Verwendung statischer Methoden finden Sie auch in doc selbst:

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

0

Weil 'abstrakt' bedeutet, dass die Methode überschrieben werden soll und man 'statische' Methoden nicht überschreiben kann.


Diese Antwort fügt nichts hinzu, was die vorherigen Antworten noch nicht angesprochen haben.
MarsAtomic

@ MarsAtomic Ich denke, es ist angemessener als die am besten gewählte Antwort. Es ist auch kurz und bündig.
Praveen Kumar

Dann können Sie frühere Antworten bearbeiten, um sie zu verbessern, wenn Sie über genügend Wiederholungen verfügen. Alles, was Sie tun, ist, dem Signal Rauschen hinzuzufügen, indem Sie doppelte Antworten erstellen. Bitte befolgen Sie die festgelegten Regeln und Gepflogenheiten von Stack Overflow, anstatt Ihre eigenen zu erstellen und zu erwarten, dass alle anderen folgen.
MarsAtomic

Ich bin anderer Meinung, bitte vergleichen Sie meine Antwort mit anderen, insbesondere mit der am besten bewerteten Antwort.
Praveen Kumar

"Warum kann ich das nicht tun?" Antwort: "weil du nicht kannst".
JacksOnF1re

0

Reguläre Methoden können abstrakt sein, wenn sie von Unterklassen überschrieben und mit Funktionen versehen werden sollen. Stellen Sie sich vor, die Klasse Foowird um Bar1, Bar2, Bar3usw. erweitert . Jede hat also ihre eigene Version der abstrakten Klasse, je nach ihren Bedürfnissen.

Jetzt gehören statische Methoden per Definition zur Klasse, sie haben nichts mit den Objekten der Klasse oder den Objekten ihrer Unterklassen zu tun. Sie brauchen sie nicht einmal zu existieren, sie können verwendet werden, ohne die Klassen zu instanziieren. Daher müssen sie einsatzbereit sein und können sich nicht auf die Unterklassen verlassen, um ihnen Funktionen hinzuzufügen.


0

Da abstract ein Schlüsselwort ist, das auf Abstract-Methoden angewendet wird, geben Sie keinen Body an. Und wenn wir über statisches Schlüsselwort sprechen, gehört es zum Klassenbereich.


Bitte seien Sie etwas ausführlicher über Ihre Antwort.
Blip

0

Wenn Sie ein statisches Element oder eine statische Variable in der Klasse verwenden, wird diese beim Laden der Klasse geladen.


3
und warum sollte das ein Problem sein?
Eis

-1

Sie können dies mit Schnittstellen in Java 8 tun.

Dies ist die offizielle Dokumentation dazu:

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


2
Wie? Ich habe nach Lösungen gesucht und keine gefunden.
Thouliha

Wut? Du kannst nicht. Alle statischen Schnittstellenmethoden müssen mit der Schnittstellenklasse aufgerufen werden.
mmm

8
Diese Antwort ist falsch und für Leute, die neu in Java sind, falsch. Dies zeigt jedes Beispiel einer abstrakten statischen Methode, da sie nicht implementiert und in anderen Antworten angegeben werden kann
Blip

-1

Denn wenn eine Klasse eine abstrakte Klasse erweitert, muss sie abstrakte Methoden überschreiben, und das ist obligatorisch. Und da statische Methoden Klassenmethoden sind, die zur Kompilierungszeit aufgelöst werden, während überschriebene Methoden Instanzmethoden sind, die zur Laufzeit und nach dynamischem Polymorphismus aufgelöst werden.


Bitte kapitalisieren und interpunktieren Sie dieses Durcheinander.
Marquis von Lorne
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.