web-dev-qa-db-fra.com

Pourquoi les méthodes statiques ne peuvent-elles pas être abstraites en Java?

La question est en Java pourquoi je ne peux pas définir une méthode statique abstraite? par exemple

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

Parce que "abstrait" signifie: "N'implémente aucune fonctionnalité" et "statique" signifie: "Il y a une fonctionnalité même si vous n'avez pas d'instance d'objet". Et c'est une contradiction logique.

520
Tomalak

Mauvaise conception de la langue. Il serait beaucoup plus efficace d'appeler directement une méthode abstraite statique que de créer une instance uniquement pour utiliser cette méthode abstraite. Cela est particulièrement vrai lorsqu’on utilise une classe abstraite comme solution de contournement en cas d’impossibilité d’extension, qui est un autre exemple de conception médiocre. J'espère qu'ils résoudront ces limitations dans une prochaine version.

284
lxndr

Vous ne pouvez pas écraser une méthode statique, le rendre abstrait n'aura donc aucun sens. De plus, une méthode statique dans une classe abstraite appartiendrait à cette classe, et non à la classe de substitution, elle ne pourrait donc pas être utilisée.

140
GaryF

L'annotation abstract à une méthode indique que celle-ci DOIT être remplacée dans une sous-classe.

En Java, un membre static (méthode ou champ) ne peut pas être remplacé par des sous-classes (ceci n'est pas nécessairement vrai dans d'autres langages orientés objet, voir Smalltalk.) Un membre static peut être hidden , mais il est fondamentalement différent de écrasé .

Comme les membres statiques ne peuvent pas être remplacés dans une sous-classe, l'annotation abstract ne peut pas leur être appliquée.

En passant, d'autres langages supportent l'héritage statique, tout comme l'héritage d'instance. Du point de vue de la syntaxe, ces langues exigent généralement que le nom de la classe soit inclus dans l'instruction. Par exemple, en Java, en supposant que vous écriviez du code dans ClassA, il s'agit d'instructions équivalentes (si methodA () est une méthode statique et qu'il n'existe aucune méthode d'instance avec la même signature):

ClassA.methodA();

et

methodA();

Dans Smalltalk, le nom de la classe n’est pas facultatif. Par conséquent, la syntaxe est la suivante (notez que Smalltalk n’utilise pas le.. Pour séparer le "sujet" et le "verbe", mais l’utilise plutôt comme terminateur de statemend):

ClassA methodA.

Comme le nom de classe est toujours requis, la "version" correcte de la méthode peut toujours être déterminée en parcourant la hiérarchie des classes. Pour ce que cela vaut, je manque parfois l'héritage static, et j'ai été piqué par le manque d'héritage statique en Java lorsque j'ai commencé à l'utiliser. De plus, Smalltalk est typé «canard» (et ne prend donc pas en charge programme par contrat.) Ainsi, il n'a pas de modificateur abstract pour les membres de la classe.

65
Jared

J'ai aussi posé la même question, voici pourquoi

Depuis la classe abstraite dit, il ne donnera pas la mise en œuvre et permettre à la sous-classe de le donner

donc Subclass doit remplacer les méthodes de Superclass, 

RÈGLE NO 1 - Une méthode statique ne peut pas être remplacée  

Étant donné que les membres et les méthodes statiques sont des éléments de compilation, c'est pourquoi la surcharge (polymorphisme de la compilation) des méthodes statiques est autorisée plutôt que la substitution (polymorphisme d'exécution)

Donc, ils ne peuvent pas être abstraits. 

Il n'y a rien qui ressemble à abstract static <--- Non autorisé dans Java Universe

14
anshulkatta

C'est une conception de langage terrible et vraiment aucune raison pour laquelle cela ne peut pas être possible. 

En fait, voici une implémentation sur la façon dont PEUT être fait dans 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;
                }

        }
}

================= Ancien exemple ci-dessous =================

Recherchez getRequest et getRequestImpl ... setInstance peut être appelé pour modifier l'implémentation avant l'appel. 

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






}
9
momomo
  • Une méthode abstraite est définie uniquement pour pouvoir être remplacée dans une sous-classe. Cependant, les méthodes statiques ne peuvent pas être remplacées. Par conséquent, le fait d'avoir une méthode abstraite et statique est une erreur de compilation.

    Maintenant la question suivante est pourquoi les méthodes statiques ne peuvent pas être remplacées?

  • C'est parce que les méthodes statiques appartiennent à une classe particulière et non à son instance. Si vous essayez de remplacer une méthode statique, vous ne recevrez aucune erreur de compilation ou d'exécution, mais le compilateur cacherait simplement la méthode statique de la superclasse.

5
Rahul Saxena

Je vois qu'il y a déjà un dieu-zillion de réponses mais je ne vois pas de solutions pratiques. Bien sûr, il s’agit d’un problème réel et il n’existe aucune raison valable d’exclure cette syntaxe en Java. Puisque la question initiale manque d'un contexte où cela peut être nécessaire, je fournis à la fois un contexte et une solution:

Supposons que vous ayez une méthode statique dans un groupe de classes identiques. Ces méthodes appellent une méthode statique spécifique à la classe:

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

Les méthodes doWork() dans C1 et C2 sont identiques. Il peut y avoir beaucoup de ces calculs: C3C4 etc. Si static abstract était autorisé, vous élimineriez le code dupliqué en procédant comme suit:

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

mais cela ne compilerait pas car la combinaison static abstract n'est pas autorisée . Cependant, ceci peut être contourné avec la construction static class, qui est autorisée:

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

Avec cette solution, le seul code dupliqué est

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

Une classe abstraite ne peut pas avoir de méthode statique car une abstraction est effectuée pour obtenir une LIAISON DYNAMIQUE alors que les méthodes statiques sont liées de manière statique à leur fonctionnalité. Une méthode statique signifie que le comportement de required.Just the class.Static Les méthodes appartiennent à la classe et non à l'objet . Elles sont stockées dans une zone mémoire appelée PERMGEN à partir de laquelle il est partagé avec chaque objet . Les méthodes de la classe abstraite sont dynamiquement liées à leurs fonctionnalités. .

2
Sunil Kumar Jha

Supposons qu'il existe deux classes, Parent et Child. Parent est abstract. Les déclarations sont les suivantes:

abstract class Parent {
    abstract void run();
}

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

Cela signifie que toute instance de Parent doit spécifier comment run() est exécuté.

Cependant, supposons maintenant que Parent ne soit pas abstract.

class Parent {
    static void run() {}
}

Cela signifie que Parent.run() exécutera la méthode statique.

La définition d'une méthode abstract est "Une méthode déclarée mais non implémentée", ce qui signifie qu'elle ne renvoie rien elle-même.

La définition d'une méthode static est "Une méthode qui renvoie la même valeur pour les mêmes paramètres, quelle que soit l'instance sur laquelle elle est appelée".

La valeur de retour d'une méthode abstract changera à mesure que l'instance change. Une méthode static ne le fera pas. Une méthode static abstract est à peu près une méthode où la valeur de retour est constante, mais ne renvoie rien. C'est une contradiction logique.

En outre, il n'y a vraiment pas beaucoup de raisons pour une méthode static abstract.

2
HyperNeutrino

Une méthode statique, par définition, n'a pas besoin de connaître this. Ainsi, il ne peut pas s'agir d'une méthode virtuelle (surchargée en fonction des informations de sous-classes dynamiques disponibles via this); à la place, une surcharge de méthode statique est uniquement basée sur les informations disponibles au moment de la compilation (cela signifie: une fois que vous vous référez à une méthode statique de superclasse, vous appelez notamment la méthode superclass, mais jamais une méthode de sous-classe).

Selon cela, les méthodes statiques abstraites seraient totalement inutiles, car leur référence ne sera jamais remplacée par un corps défini.

2
AndreyS Scherbakov

Une méthode statique peut être appelée sans instance de la classe. Dans votre exemple, vous pouvez appeler foo.bar2 (), mais pas foo.bar (), car pour bar vous avez besoin d'une instance .

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

Si vous appelez une méthode statique, elle sera toujours exécutée avec le même code. Dans l'exemple ci-dessus, même si vous redéfinissez bar2 dans ImplementsFoo, un appel à var.bar2 () exécuterait foo.bar2 ().

Si bar2 n'a plus d'implémentation (c'est ce que signifie abstrait), vous pouvez appeler une méthode sans implémentation. C'est très nocif.

1
Mnementh

Parce que la classe abstraite est un concept OOPS et que les membres statiques ne font pas partie d'OOPS ....
Nous pouvons maintenant déclarer des méthodes complètes statiques dans une interface et exécuter une interface en déclarant la méthode principale dans une interface.

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

Je pense avoir trouvé la réponse à cette question, en expliquant pourquoi les méthodes d'une interface (qui fonctionnent comme des méthodes abstraites dans une classe parente) ne peuvent pas être statiques. Voici la réponse complète (pas la mienne)

En principe, les méthodes statiques peuvent être liées à la compilation, car pour les appeler, vous devez spécifier une classe. Cela diffère des méthodes d'instance, pour lesquelles la classe de la référence à partir de laquelle vous appelez la méthode peut être inconnue au moment de la compilation (ainsi, le bloc de code appelé ne peut être déterminé qu'au moment de l'exécution).

Si vous appelez une méthode statique, vous connaissez déjà la classe dans laquelle elle est implémentée, ou l'une de ses sous-classes directes. Si vous définissez

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

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

Alors, tout appel à Foo.bar(); est évidemment illégal et vous utiliserez toujours Foo2.bar();.

Dans cet esprit, le seul but d'une méthode abstraite statique serait de forcer les sous-classes à implémenter une telle méthode. Vous pensez peut-être au début que cela est TRÈS faux, mais si vous avez un paramètre de type générique <E extends MySuperClass>, il serait agréable de garantir via l'interface que E peut .doSomething(). N'oubliez pas qu'en raison de l'effacement des types, les génériques n'existent qu'au moment de la compilation.

Alors, serait-ce utile? Oui, et c'est peut-être pour cette raison que Java 8 autorise les méthodes statiques dans les interfaces (bien qu'avec une implémentation par défaut). Pourquoi pas des méthodes statiques abstraites avec une implémentation par défaut dans les classes? Tout simplement parce qu'une méthode abstraite avec une implémentation par défaut est en réalité une méthode concrète.

Pourquoi pas des méthodes abstraites/interfaces statiques sans implémentation par défaut? Apparemment, simplement à cause de la manière dont Java identifie le bloc de code qu'il doit exécuter (première partie de ma réponse).

1
Blueriver

L'idée d'avoir une méthode statique abstraite serait que vous ne pouvez pas utiliser cette classe abstraite particulière directement pour cette méthode, mais seule la première dérivée serait autorisée à implémenter cette méthode statique (ou pour les génériques: utilisation).

De cette façon, vous pouvez créer par exemple une classe abstraite sortableObject ou même une interface Avec des méthodes statiques (auto-) abstraites, qui définissent les paramètres des options de tri:

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

Vous pouvez maintenant définir un objet triable qui peut être trié selon les types principaux identiques pour tous ces objets:

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

Maintenant, vous pouvez créer un

public class SortableList<T extends SortableObject> 

qui peut récupérer les types, créer un menu contextuel pour sélectionner un type sur lequel trier et utiliser la liste en extrayant les données de ce type, ainsi qu'une fonction d'ajout qui, lorsqu'un type de tri est sélectionné, peut -sort de nouveaux éléments dans . Notez que l'instance de SortableList peut accéder directement à la méthode statique de "T":

String [] MenuItems = T.getSortableTypes();

Le problème de devoir utiliser une instance est que SortableList n'a peut-être pas encore d'éléments, mais doit déjà fournir le tri préféré.

Cheerio, Olaf.

0
Olaf Leimann

Premièrement, un point clé concernant les classes abstraites - Une classe abstraite ne peut pas être instanciée (voir wiki ). Vous ne pouvez donc pas créer aucune instance d'une classe abstraite. 

Maintenant, Java traite les méthodes statiques en partageant la méthode avec tous les instances de cette classe. 

Donc, si vous ne pouvez pas instancier une classe, cette classe ne peut pas avoir de méthodes abstraites statiques, car une méthode abstraite demande à être étendue. 

Boom. 

0
bruhhhhh

Parce que abstract est un mot-clé qui s'applique aux méthodes abstraites ne spécifie pas de corps Et si nous parlons de mot clé statique, il appartient à la classe.

0
Ashish Ranjan

Parce que 'abstrait' signifie que la méthode doit être remplacée et qu'il est impossible de remplacer les méthodes 'statiques'.

0
Praveen Kumar

Selon Java doc :

Une méthode statique est une méthode associée à la classe dans laquelle il est défini plutôt qu'avec n'importe quel objet. Chaque instance de la classe partage ses méthodes statiques

En Java 8, avec les méthodes par défaut, les méthodes statiques sont également autorisées dans une interface. Cela nous permet d’organiser plus facilement des méthodes d’aide dans nos bibliothèques. Nous pouvons garder les méthodes statiques spécifiques à une interface dans la même interface plutôt que dans une classe séparée. 

Un bel exemple de ceci est:

list.sort(ordering);

au lieu de

Collections.sort(list, ordering);

Un autre exemple d'utilisation de méthodes statiques est également donné dans doc lui-même:

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
i_am_zero

Les méthodes classiques peuvent être abstraites lorsqu'elles sont censées être remplacées par des sous-classes et dotées de fonctionnalités. Imaginez que la classe Foo soit étendue de Bar1, Bar2, Bar3 etc. Ainsi, chacun aura sa propre version de la classe abstraite en fonction de ses besoins. 

Maintenant, les méthodes statiques appartiennent par définition à la classe, elles n’ont rien à voir avec les objets de la classe ou les objets de ses sous-classes. Ils n'ont même pas besoin d'eux pour exister, ils peuvent être utilisés sans instancier les classes. Par conséquent, ils doivent être prêts à l'emploi et ne peuvent pas dépendre des sous-classes pour leur ajouter des fonctionnalités.

0
Darshan Chaudhary

Vous pouvez le faire avec des interfaces en Java 8.

Voici la documentation officielle à ce sujet:

https://docs.Oracle.com/javase/tutorial/Java/IandI/defaultmethods.html

0
Jim Showalter

car si vous utilisez un membre statique ou une variable statique dans la classe, il se chargera au moment du chargement de la classe.

0
Manu

Déclarer une méthode en tant que static signifie que nous pouvons appeler cette méthode par son nom de classe. Si cette classe est également abstract, cela n’a aucun sens de l’appeler car elle ne contient aucun corps et nous ne pouvons donc pas déclarer une méthode à la fois en tant que static et abstract.

0
akash kumar