web-dev-qa-db-fra.com

Pourquoi Java ne permet-il pas de remplacer des méthodes statiques?

Pourquoi n'est-il pas possible de remplacer des méthodes statiques?

Si possible, veuillez utiliser un exemple.

502
sgokhales

La substitution dépend de la présence d'une instance d'une classe. L'intérêt du polymorphisme est que vous pouvez sous-classer une classe et que les objets implémentant ces sous-classes auront des comportements différents pour les mêmes méthodes définies dans la superclasse (et remplacées dans les sous-classes). Une méthode statique n'est associée à aucune instance d'une classe et le concept n'est donc pas applicable.

La conception de Java a été influencée par deux facteurs. L'une concernait les performances: il y avait eu beaucoup de critiques à propos de Smalltalk pour sa lenteur (le ramassage des ordures et les appels polymorphes en faisaient partie) et les créateurs de Java étaient déterminés à éviter cela. Une autre était la décision que le public cible de Java était les développeurs C++. Le bon fonctionnement des méthodes statiques a permis aux programmeurs C++ de se familiariser avec l'environnement et était également très rapide, car il n'était pas nécessaire d'attendre le moment de l'exécution pour déterminer la méthode à appeler.

473
Nathan Hughes

Personnellement, je pense que c'est une faille dans la conception de Java. Oui, oui, je comprends que des méthodes non statiques sont attachées à une instance, alors que des méthodes statiques sont attachées à une classe, etc. etc. Néanmoins, considérons le code suivant:

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

Ce code ne fonctionnera pas comme prévu. À savoir que les employés spéciaux obtiennent un bonus de 2%, tout comme les employés réguliers. Mais si vous supprimez les "statiques", SpecialEmployee obtiendra un bonus de 3%.

(Certes, cet exemple est un mauvais style de codage dans la mesure où, dans la vie réelle, vous voudriez probablement que le multiplicateur de bonus se trouve dans une base de données quelque part plutôt que codé en dur. Mais c'est simplement parce que je ne voulais pas brouiller l'exemple de code non pertinent au point.)

Il me semble tout à fait plausible que vous souhaitiez peut-être rendre getBonusMultiplier statique. Vous voulez peut-être pouvoir afficher le multiplicateur de bonus pour toutes les catégories d'employés, sans avoir besoin d'avoir une instance d'employé dans chaque catégorie. Quel serait l'intérêt de rechercher de tels exemples? Que se passe-t-il si nous créons une nouvelle catégorie d’employés et qu’aucun employé n’a encore été affecté? C'est assez logiquement une fonction statique.

Mais ça ne marche pas.

Et oui, oui, je peux penser à un certain nombre de façons de réécrire le code ci-dessus pour le faire fonctionner. Mon argument n'est pas que cela crée un problème insoluble, mais que cela crée un piège pour le programmeur imprudent, car le langage ne se comporte pas comme je pense, une personne raisonnable pourrait s'y attendre.

Peut-être que si j'essayais d'écrire un compilateur pour un langage OOP, je comprendrais rapidement pourquoi il était difficile, voire impossible, de l'implémenter de telle sorte que les fonctions statiques puissent être remplacées.

Ou peut-être y a-t-il une bonne raison pour que Java se comporte de cette façon. Quelqu'un peut-il signaler un avantage à ce comportement, une catégorie de problèmes que cela facilite? Je veux dire, ne me dirigez pas seulement vers la spécification de langage Java et dites "voyez, ceci est documenté comment cela se comporte". Je le sais. Mais y a-t-il une bonne raison pour laquelle il DEVRAIT se comporter de cette façon? (En plus de l'évidence "faire en sorte que tout fonctionne bien était trop difficile" ...)

Mise à jour

@VicKirk: Si vous voulez dire que c'est "mauvais design" parce que cela ne correspond pas à la façon dont Java gère la statique, ma réponse est "Eh bien, bien sûr, bien sûr." Comme je l'ai dit dans mon post original, cela ne fonctionne pas. Mais si vous voulez dire que la conception est mauvaise en ce sens qu’il y aurait quelque chose de fondamentalement faux dans un langage qui fonctionnerait, c’est-à-dire où la statique pourrait être dépassée, tout comme les fonctions virtuelles, ce qui introduirait une ambiguïté ou il serait impossible de Pour mettre en œuvre efficacement, je réponds "Pourquoi? Qu'est-ce qui ne va pas dans le concept?"

Je pense que l'exemple que je donne est une chose très naturelle à vouloir faire. J'ai une classe qui a une fonction qui ne dépend d'aucune donnée d'instance et que je pourrais très raisonnablement vouloir appeler indépendamment d'une instance, ainsi que de l'appel depuis une méthode d'instance. Pourquoi cela ne fonctionnerait-il pas? J'ai rencontré cette situation plusieurs fois au cours des années. En pratique, je le contourne en rendant la fonction virtuelle, puis en créant une méthode statique dont le seul but dans la vie est d’être une méthode statique qui transmet l’appel à la méthode virtuelle avec une instance fictive. Cela semble être un moyen très détourné d'y arriver.

175
Jay

La réponse courte est: c'est tout à fait possible, mais Java ne le fait pas.

Voici un code qui illustre la situation actuelle de en Java:

Fichier Base.Java:

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

Fichier Child.Java:

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

Si vous exécutez ceci (je l'ai fait sur un Mac, à partir d'Eclipse, en utilisant Java 1.6), vous obtenez:

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

Ici, seuls les cas susceptibles d’être une surprise (et sur lesquels porte la question) semblent être les premiers cas:

"Le type d'exécution n'est pas utilisé pour déterminer les méthodes statiques appelées, même lorsqu'elles sont appelées avec une instance d'objet (obj.staticMethod())."

et le dernier cas:

"Lors de l'appel d'une méthode statique depuis une méthode objet d'une classe, la méthode statique choisie est celle accessible depuis la classe elle-même et pas depuis la classe définir le type d'exécution de l'objet. "

Appeler avec une instance d'objet

L'appel statique est résolu au moment de la compilation, alors qu'un appel de méthode non statique est résolu au moment de l'exécution. Notez que, bien que les méthodes statiques soient héritées (du parent), elles ne sont pas remplacées (par enfant). Cela pourrait être une surprise si vous vous attendiez au contraire.

Appeler depuis une méthode d'objet

Les appels de méthode Object sont résolus à l'aide du type d'exécution, mais la classe statique () ) Les appels de méthode sont résolus en utilisant le type à la compilation (déclaré).

Changer les règles

Pour modifier ces règles, de sorte que le dernier appel de l'exemple appelé Child.printValue(), les appels statiques doivent être dotés d'un type au moment de l'exécution, au lieu que le compilateur résolve l'appel à la compilation avec la classe déclarée de l'objet ( ou contexte). Les appels statiques pourraient ensuite utiliser la hiérarchie de types (dynamique) pour résoudre l'appel, comme le font aujourd'hui les appels de méthodes objet.

Ce serait facilement faisable (si nous avions changé Java: -O), et ce n’est pas du tout déraisonnable, cependant, il a quelques considérations intéressantes.

La principale considération est que nous devons décider quelle méthode statique devrait faire cela.

Pour le moment, Java a cette "particularité" dans le langage dans lequel les appels à obj.staticMethod() sont remplacés par des appels à ObjectClass.staticMethod() (normalement avec un avertissement). [ Remarque: ObjectClass est le type de compilation obj.] Ce sont de bons candidats pour remplacer de cette manière, en prenant le type d’exécution de obj.

Si nous le faisions, les corps de méthodes seraient plus difficiles à lire: les appels statiques dans une classe parente pourraient potentiellement être dynamiquement "redirigés". Pour éviter cela, nous devrions appeler la méthode statique avec un nom de classe - ce qui rend les appels plus clairement résolus avec la hiérarchie des types à la compilation (comme maintenant).

Les autres manières d'appeler une méthode statique sont plus délicates: this.staticMethod() devrait signifier la même chose que obj.staticMethod(), en prenant le type d'exécution this. Cependant, cela pourrait causer des problèmes avec les programmes existants, qui appellent des méthodes statiques (apparemment locales) sans décoration (ce qui équivaut sans doute à this.method()).

Alors, qu'en est-il des appels sans fioritures staticMethod()? Je suggère qu'ils fassent la même chose qu'aujourd'hui et utilisent le contexte de classe local pour décider quoi faire. Sinon, une grande confusion s'ensuivrait. Bien sûr, cela signifie que method() voudrait dire this.method() si method était une méthode non statique et ThisClass.method() si method était une méthode statique. Ceci est une autre source de confusion.

Autres considérations

Si nous changions ce comportement (et donnions à des appels statiques potentiellement potentiellement non locaux dynamiquement), nous voudrions probablement réexaminer la signification de final, private et protected en tant que qualificateurs sur les méthodes static. Nous devrions alors tous nous habituer au fait que les méthodes private static et public final ne sont pas écrasées et peuvent donc être résolues en toute sécurité au moment de la compilation, et sont "sûres" de se lire en tant que références locales.

38
Steve Powell

En fait nous avions tort.
Bien que Java ne vous autorise pas à remplacer les méthodes statiques par défaut, si vous examinez attentivement la documentation des classes Class et Method en Java, vous pouvez toujours trouver un moyen d’émuler les méthodes statiques. en contournant le problème:

import Java.lang.reflect.InvocationTargetException;
import Java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

Résultat obtenu:

0.02
0.02
0.02
0.03

ce que nous essayions de réaliser :)

Même si nous déclarons la troisième variable Carl comme étant RegularEmployee et lui affectons une instance de SpecialEmployee, nous aurons toujours l'appel de la méthode RegularEmployee dans le premier cas et l'appel de la méthode SpecialEmployee dans le deuxième cas.

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

il suffit de regarder la console de sortie:

0.02
0.03

;)

23
Patlatus

Les méthodes statiques sont traitées comme globales par la machine virtuelle, il n'y a pas du tout de lien avec une instance d'objet.

Cela pourrait théoriquement être possible si vous pouviez appeler des méthodes statiques à partir d'objets de classe (comme dans des langages comme Smalltalk), mais ce n'est pas le cas en Java.

EDIT

Vous pouvez surcharger méthode statique, ce n'est pas grave. Mais vous ne pouvez pas remplacer une méthode statique, car class n'est pas un objet de première classe. Vous pouvez utiliser la réflexion pour obtenir la classe d'un objet au moment de l'exécution, mais l'objet que vous obtenez ne correspond pas à la hiérarchie de la classe.

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

Vous pouvez réfléchir aux cours, mais cela s’arrête là. Vous n'appelez pas une méthode statique en utilisant clazz1.staticMethod(), mais en utilisant MyClass.staticMethod(). Une méthode statique n'est pas liée à un objet et il n'y a donc aucune notion de this ni super dans une méthode statique. Une méthode statique est une fonction globale. par conséquent, il n'y a pas non plus de notion de polymorphisme et, par conséquent, le dépassement de méthode n'a aucun sens.

Mais cela pourrait être possible si MyClass était un objet au moment de l'exécution sur lequel vous appelez une méthode, comme dans Smalltalk (ou peut-être JRuby comme le suggère un commentaire, mais je ne connais rien à JRuby).

Oh oui ... encore une chose. Vous pouvez appeler une méthode statique via un objet obj1.staticMethod(), mais ce sucre réellement syntaxique pour MyClass.staticMethod() devrait être évité. Cela déclenche généralement un avertissement dans l'IDE moderne. Je ne sais pas pourquoi ils ont jamais permis ce raccourci.

17
ewernli

Le remplacement de méthode est rendu possible par dispatching dynamique , ce qui signifie que le type déclaré d'un objet ne détermine pas son comportement, mais plutôt son type d'exécution:

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal Kermit = new Frog();
Kermit.speak(); // outputs "ribbit!"

Même si les deux lassie et Kermit sont déclarés en tant qu'objets de type Animal, leur comportement (méthode .speak()) varie car la répartition dynamique ne fera que bind l'appel de méthode .speak() à une implémentation au moment de l'exécution - pas au moment de la compilation.

Maintenant, voici où le mot-clé static commence à avoir un sens: le mot "statique" est un antonyme de "dynamique". Donc, la raison pourquoi vous ne pouvez pas remplacer les méthodes statiques, c'est parce qu'il n'y a pas de dispatching dynamique sur les membres static - car static signifie littéralement "pas dynamique". S'ils sont envoyés dynamiquement (et pourrait donc être annulé), le mot clé static n'aurait plus aucun sens.

13
Richard JP Le Guen

Oui. Pratiquement Java permet de remplacer une méthode statique, et théoriquement, si vous remplacez une méthode statique dans Java, elle se compilera et fonctionnera de manière fluide, mais perdra le Polymorphisme, propriété de base de Java. Vous lirez partout qu'il n'est pas possible de vous essayer à la compilation et à l'exécution. vous aurez votre réponse. par exemple. Si vous avez Class Animal et une méthode statique, manger () et vous surcharger de cette méthode statique dans sa sous-classe permet de l'appeler Chien. Ensuite, lorsque vous affectez un objet Dog à une référence Animal et appelez eat () conformément à Java, l'attribut eat () de Dog () devrait être appelé, mais en mode Redéfini, la valeur de eat () sera annulée.

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

Selon le principe de polymorphisme de Java, le résultat devrait être Dog Eating.
Mais le résultat était différent car, pour prendre en charge Polymorphism Java, les méthodes de liaison tardive signifient que les méthodes sont appelées uniquement au moment de l'exécution, mais pas dans le cas des méthodes statiques. Dans les méthodes statiques, le compilateur appelle les méthodes au moment de la compilation plutôt qu'au moment de l'exécution. Nous obtenons donc des méthodes en fonction de la référence et non en fonction de l'objet. Une référence contenant ce qui vous permet de dire 't.

9
Shubham Soni

Eh bien ... la réponse est NON si vous pensez de la manière dont une méthode surchargée doit se comporter en Java. Cependant, vous n'obtenez aucune erreur de compilation si vous essayez de remplacer une méthode statique. Cela signifie que si vous essayez de remplacer, Java ne vous empêche pas de le faire; mais vous n'obtiendrez certainement pas le même effet que pour les méthodes non statiques. Remplacer dans Java signifie simplement que la méthode particulière serait appelée en fonction du type d'exécution de l'objet et non de son type à la compilation (ce qui est le cas des méthodes statiques remplacées). D'accord ... des suppositions pour la raison pourquoi se comportent-ils étrangement? Comme ce sont des méthodes de classe, leur accès est toujours résolu au moment de la compilation uniquement à l'aide des informations de type de compilation. Accéder à eux en utilisant des références d’objet n’est qu’une liberté supplémentaire accordée par les concepteurs de Java et nous ne devrions certainement pas penser à arrêter cette pratique uniquement quand ils la restreignent :-)

Exemple: essayons de voir ce qui se passe si nous essayons de surcharger une méthode statique: -

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

Sortie: -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

Remarquez la deuxième ligne de la sortie. Si la méthode staticMethod avait été remplacée, cette ligne aurait dû être identique à la troisième, car nous invoquons la méthode 'staticMethod ()' sur un objet de type d'exécution sous la forme 'SubClass' et non 'SuperClass'. Cela confirme que les méthodes statiques sont toujours résolues en utilisant uniquement leurs informations de type de temps de compilation.

5
Rupesh Yadav

Dans Java (et de nombreuses langues OOP, mais je ne parle pas pour tout; et certaines n'ont pas du tout de statique), toutes les méthodes ont une signature fixe - les paramètres et les types. Dans une méthode virtuelle, le premier paramètre est impliqué: une référence à l'objet lui-même et lorsqu'il est appelé à partir de l'objet, le compilateur ajoute automatiquement this.

Il n'y a pas de différence pour les méthodes statiques - elles ont toujours une signature fixe. Cependant, en déclarant la méthode statique, vous avez explicitement déclaré que le compilateur ne doit pas inclure le paramètre d'objet impliqué au début de cette signature. Par conséquent, tout autre code qui appelle cela doit ne doit pas tenter de mettre une référence à un objet de la pile . Si tel était le cas, l'exécution de la méthode ne fonctionnerait pas car les paramètres seraient au mauvais endroit (décalés de un) sur la pile.

A cause de cette différence entre les deux; Les méthodes virtuelles ont toujours une référence à l’objet contextuel (c.-à-d. this). Il est donc possible de référencer tout élément du tas qui appartient à cette instance de l’objet. Mais avec les méthodes statiques, étant donné qu’aucune référence n’est transmise, cette méthode ne peut accéder aux variables d’objet ni aux méthodes car le contexte n’est pas connu.

Si vous souhaitez que Java modifie la définition de sorte qu'un contexte d'objet soit transmis à chaque méthode, statique ou virtuelle, vous ne disposez alors que de méthodes virtuelles.

Comme quelqu'un l'a demandé dans un commentaire sur l'opération - quelles sont les raisons pour lesquelles vous souhaitez cette fonctionnalité?

Je ne connais pas beaucoup Ruby, comme cela a été mentionné par l'OP, j'ai fait des recherches. Je vois que dans Ruby, les classes sont vraiment un type d'objet spécial et on peut créer (même dynamiquement) de nouvelles méthodes. Les classes sont des objets de classe complets en Ruby, elles ne le sont pas en Java. C’est simplement quelque chose que vous devrez accepter lorsque vous travaillerez avec Java (ou C #). Ce ne sont pas des langages dynamiques, bien que C # ajoute certaines formes de dynamique. En réalité, Ruby n'a pas de méthodes "statiques" pour autant que j'ai pu trouver - dans ce cas, il s'agit de méthodes sur l'objet de classe singleton. Vous pouvez ensuite remplacer ce singleton par une nouvelle classe et les méthodes de l'objet classe précédent appellent celles définies dans la nouvelle classe (correct?). Ainsi, si vous appelez une méthode dans le contexte de la classe d'origine, celle-ci n'exécutera que la statique d'origine, mais l'appel d'une méthode dans la classe dérivée appellera des méthodes à partir de la classe mère ou de la sous-classe. Intéressant et je peux voir une valeur en cela. Il faut un schéma de pensée différent.

Puisque vous travaillez en Java, vous devrez vous adapter à cette façon de faire. Pourquoi ils ont fait ça? Eh bien, probablement pour améliorer les performances à l'époque en fonction de la technologie et de la compréhension disponibles. Les langages informatiques évoluent constamment. Retournez assez loin et il n’existe pas de POO. À l'avenir, il y aura d'autres nouvelles idées.

EDIT: Un autre commentaire. Maintenant que je vois les différences et que je suis moi-même un développeur Java/C #, je peux comprendre pourquoi les réponses que vous obtenez des développeurs Java peuvent être déroutantes si vous venez d'un langage comme Ruby. Les méthodes Java static ne sont pas identiques aux méthodes Ruby class. Les développeurs Java auront du mal à comprendre cela, de même que ceux qui travaillent principalement avec un langage comme Ruby/Smalltalk. Je peux voir en quoi cela serait également très déroutant du fait que Java utilise également "méthode de classe" comme autre moyen de parler de méthodes statiques, mais ce même terme est utilisé différemment par Ruby. Java n'a pas de méthode de classe de style Ruby (désolé); Ruby ne possède pas de méthodes statiques de style Java, qui ne sont en réalité que de vieilles fonctions de style procédural, comme en C.

Au fait - merci pour la question! J'ai appris quelque chose de nouveau pour moi aujourd'hui sur les méthodes de classe (style Ruby).

5
Kevin Brock

En remplaçant, nous pouvons créer une nature polymorphe en fonction du type d'objet. La méthode statique n'a pas de relation avec l'objet. Donc, Java ne peut pas prendre en charge le remplacement de méthode statique.

4
DeveloperArnab

En général, il n’a pas de sens de permettre de "surcharger" des méthodes statiques car il n’y aurait pas de moyen efficace de déterminer laquelle appeler à l’exécution. Prenons l'exemple de l'employé, si nous appelons RegularEmployee.getBonusMultiplier () - quelle méthode est supposée être exécutée?

Dans le cas de Java, on pourrait imaginer une définition de langage dans laquelle il est possible de "remplacer" des méthodes statiques tant qu'elles sont appelées via une instance d'objet. Cependant, tout ce que cela ferait serait de ré-implémenter les méthodes de classe habituelles, en ajoutant de la redondance au langage sans ajouter réellement d'avantage.

4
Lars

J'aime et double le commentaire de Jay ( https://stackoverflow.com/a/2223803/1517187 ).
Je conviens que c’est la mauvaise conception de Java.
De nombreux autres langages supportent les méthodes statiques, comme nous le voyons dans les commentaires précédents. Je pense que Jay est également venu à Java de Delphi comme moi.
Delphi (Object Pascal) a été le premier langage à implémenter la POO.
Il est évident que de nombreuses personnes connaissaient déjà cette langue, qui était autrefois la seule à écrire des produits à interface graphique commerciale. Et - oui, nous pourrions dans Delphi remplacer les méthodes statiques. En fait, les méthodes statiques dans Delphi sont appelées "méthodes de classe", alors que Delphi avait le concept différent de "méthodes statiques Delphi" qui étaient des méthodes avec une liaison anticipée. Pour remplacer les méthodes que vous avez dû utiliser, une directive "virtuelle" a été déclarée. C'était donc très pratique et intuitif et je m'attendrais à cela en Java.

4
Patlatus

la substitution est réservée aux membres de l'exemple pour prendre en charge le comportement polymorphe. les membres statiques de la classe n'appartiennent pas à une instance particulière. Au lieu de cela, les membres statiques appartiennent à la classe et, par conséquent, le remplacement n'est pas pris en charge car les sous-classes héritent uniquement des membres des instances protégées et publiques et non des membres statiques. Vous pouvez définir une interface utilisateur et des modèles de conception d’usines et/ou de stratégies pour évaluer une autre approche.

4
Athens Holloway

Remplacer dans Java signifie simplement que la méthode particulière serait appelée en fonction du type d'exécution de l'objet et non de son type à la compilation (ce qui est le cas des méthodes statiques remplacées). Les méthodes statiques étant des méthodes de classe, elles ne sont pas des méthodes d'instance. Elles n'ont donc rien à voir avec le fait que la référence pointe vers quel objet ou instance, car, en raison de la nature de la méthode statique, elle appartient à une classe spécifique. Vous pouvez le redéclarer dans la sous-classe, mais cette sous-classe ne saura rien des méthodes statiques de la classe parente car, comme je l'ai dit, elle est spécifique à la classe dans laquelle elle a été déclarée. Leur accès en utilisant des références d’objet n’est qu’une liberté supplémentaire accordée par les concepteurs de Java et nous ne devrions certainement pas penser à arrêter cette pratique uniquement quand ils la restreignent avec plus de détails et d’exemples http: // faisalbhagat .blogspot.com/2014/09/method-overriding-and-method-hiding.html

2
faisalbhagat

En remplaçant, vous obtenez un polymorphisme dynamique. Lorsque vous dites remplacer les méthodes statiques, les mots que vous essayez d'utiliser sont contradictoires.

Static dit - le temps de compilation, le dépassement est utilisé pour le polymorphisme dynamique. Les deux sont de nature opposée et ne peuvent donc pas être utilisés ensemble.

Le comportement polymorphe dynamique survient lorsqu'un programmeur utilise un objet et accède à une méthode d'instance. JRE mappera différentes méthodes d'instance de différentes classes en fonction du type d'objet que vous utilisez.

Lorsque vous parlez de redéfinition des méthodes statiques, nous accédons aux méthodes statiques à l’aide du nom de la classe, qui sera liée lors de la compilation. Il n’existe donc aucun concept de liaison de méthodes à l’exécution avec des méthodes statiques. Donc, le terme "surcharger" des méthodes statiques en soi n'a pas de sens.

Remarque: même si vous accédez à une méthode de classe avec un objet, le compilateur Java est quand même assez intelligent pour le découvrir et fera des liens statiques.

2
user1923551

La réponse à cette question est simple, la méthode ou la variable marquée comme statique n'appartenant qu'à la classe, de sorte que la méthode statique ne peut pas être héritée dans la sous-classe car elles appartiennent uniquement à la super-classe.

2
G4uKu3_Gaurav

Une méthode statique, une variable, un bloc ou une classe imbriquée appartient à la classe entière plutôt qu'un objet.

Une méthode dans Java est utilisée pour exposer le comportement d'un objet/d'une classe. Ici, en tant que méthode est statique (c’est-à-dire que la méthode statique est utilisée pour représenter le comportement d’une classe uniquement.) modification/annulation le comportement de toute la classe violera le phénomène de l’un des piliers fondamentaux de la programmation orientée objet, à savoir cohésion élevée. (N'oubliez pas qu'un constructeur est un type de méthode spécial en Java.)

Cohésion élevée - Une classe ne devrait avoir qu'un seul rôle. Par exemple: Une classe de voiture ne doit produire que des objets de voiture et non des vélos, des camions, des avions, etc. Cependant, la classe de voiture peut avoir certaines caractéristiques (comportement) qui lui appartiennent uniquement.

Par conséquent, lors de la conception du langage de programmation Java. Les concepteurs de langage ont pensé permettre aux développeurs de garder certains comportements d’une classe pour eux-mêmes en rendant une méthode statique.


Le code de pièce ci-dessous tente de remplacer la méthode statique, mais not rencontrera une erreur de compilation.

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

En effet, ici, nous ne surchargons pas une méthode mais simplement re-déclarons. Java permet de redéclarer une méthode (statique/non statique).

Supprimer le mot-clé static de la méthode getVehileNumber () de la classe Car entraînera une erreur de compilation. Depuis, nous essayons de change la fonctionnalité de la méthode statique qui appartient à la classe Vehicle uniquement.

De même, si getVehileNumber () est déclaré comme final, le code ne sera pas compilé, car le mot-clé final empêche le programmeur de déclarer à nouveau la méthode.

public static final int getVehileNumber() {
return VIN;     }

Globalement, cela revient aux concepteurs de logiciels pour savoir où utiliser les méthodes statiques. Personnellement, je préfère utiliser des méthodes statiques pour effectuer certaines actions sans créer d'instance de classe. Deuxièmement, cacher le comportement d'une classe du monde extérieur.

1
Rohit Gaikwad

A quoi sert-il de remplacer les méthodes statiques? Vous ne pouvez pas appeler des méthodes statiques via une instance.

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

EDIT: Il semble que, à la suite d’un oubli malheureux dans la conception du langage, vous pouvez appelez des méthodes statiques par l’intermédiaire d’une instance. Généralement personne ne fait ça. Ma faute.

1
fastcodejava

Voici une explication simple. Une méthode statique est associée à une classe, tandis qu'une méthode d'instance est associée à un objet particulier. Les substitutions permettent d'appeler les différentes implémentations des méthodes substituées associées à l'objet particulier. Il est donc contre-intuitif de remplacer la méthode statique qui n'est même pas associée à des objets mais à la classe elle-même. Ainsi, les méthodes statiques ne peuvent pas être remplacées en fonction de l'objet qui l'appelle, elles seront toujours associées à la classe où elles ont été créées.

1
Rafsan Mobasher

Solution facile: utilisez une instance singleton. Cela autorisera les dérogations et l'héritage.

Dans mon système, j'ai la classe SingletonsRegistry, qui retourne l'instance de la classe passée. Si instance n'est pas trouvé, il est créé.

Cours de langue Haxe:

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
  }

}
1
Raivo Fishmeister