Quel est l'avantage de déclarer une méthode comme statique

94

J'ai récemment parcouru mes avertissements dans Eclipse et suis tombé sur celui-ci:

avertissement statique

Cela donnera un avertissement au compilateur si la méthode peut être déclarée comme statique.

[modifier] Citation exacte dans l'aide Eclipse, avec un accent sur privé et final:

Lorsqu'il est activé, le compilateur émettra une erreur ou un avertissement pour les méthodes qui sont privées ou finales et qui ne font référence qu'à des membres statiques.

Oui, je sais que je peux l'éteindre, mais je veux connaître la raison de son activation?

Pourquoi serait-ce une bonne chose de déclarer chaque méthode possible comme statique?

Cela donnera-t-il des avantages en termes de performances? (dans un domaine mobile)

Soulignant une méthode comme statique, je suppose que cela montre que vous n'utilisez aucune variable d'instance et que vous pourriez donc être déplacé vers une classe de style utils?

À la fin de la journée, dois-je simplement désactiver cette option «ignorer» ou dois-je corriger les 100 avertissements qu'il m'a donnés?

Pensez-vous que ce ne sont que des mots-clés supplémentaires qui salissent le code, car le compilateur ne fera que mettre en ligne ces méthodes de toute façon? (un peu comme vous ne déclarez pas toutes les variables que vous pouvez finaliser mais que vous pourriez ).

Blundell
la source
Incertain, mais cela pourrait simplement être considéré comme une aide à la programmation. Les avertissements sont simplement des indications sur les choses à examiner.
James P.
1
Je suis curieux de connaître le type de fonctionnalité qu'effectuent ces méthodes. Peut-être que quelque chose n'a pas été très bien fait s'il y en a tant.
ArjunShankar
En relation: stackoverflow.com/q/790281
Brian Rasmussen

Réponses:

132

Chaque fois que vous écrivez une méthode, vous remplissez un contrat dans un périmètre donné. Plus la portée est étroite, plus il y a de chances que vous écriviez un bogue.

Lorsqu'une méthode est statique, vous ne pouvez pas accéder aux membres non statiques; par conséquent, votre portée est plus étroite. Donc, si vous n'avez pas besoin et n'aurez jamais besoin (même dans les sous - classes) de membres non statiques pour remplir votre contrat, pourquoi donner accès à ces champs à votre méthode? Déclarer la méthode staticdans ce cas permettra au compilateur de vérifier que vous n'utilisez pas de membres que vous n'avez pas l'intention d'utiliser.

De plus, cela aidera les personnes lisant votre code à comprendre la nature du contrat.

C'est pourquoi il est bon de déclarer une méthode staticquand elle implémente réellement un contrat statique.

Dans certains cas, votre méthode ne signifie que quelque chose de relatif à une instance de votre classe, et il arrive que son implémentation n'utilise en fait aucun champ ou instance non statique. Dans de tels cas, vous ne marqueriez pas la méthode static.

Exemples de cas où vous n'utiliseriez pas le staticmot - clé:

  • Un hook d'extension qui ne fait rien (mais pourrait faire quelque chose avec des données d'instance dans une sous-classe)
  • Un comportement par défaut très simple destiné à être personnalisable dans une sous-classe.
  • Implémentation du gestionnaire d'événements: l'implémentation variera avec la classe du gestionnaire d'événements mais n'utilisera aucune propriété de l'instance de gestionnaire d'événements.
Samuel Rossille
la source
1
+1 Il s'agit de minimiser les opportunités de se tirer une balle dans le pied et de réduire ce que vous devez savoir pour comprendre une méthode.
Peter Lawrey
7
De plus, vous n'avez pas besoin de jouer avec l'acquisition d'une instance juste pour appeler une fonction indépendante et autonome.
Marko Topolnik
1
Donc, dans d'autres mondes, toute méthode qui n'utilise pas de variables d'instance devrait être déclarée comme statique? J'ai toujours pensé que les méthodes ne devraient être statiques que si c'est souhaitable (comme les méthodes d'utilité).
Petr Mensik
18
@PetrMensik Si une privateméthode pouvait être déclarée statique, alors presque invariablement elle devrait l' être. Pour tout autre niveau d'accès, il existe d'autres facteurs à prendre en compte, comme la répartition dynamique.
Marko Topolnik
1
@JamesPoulson Je veux dire la répartition dynamique de la méthode, la chose se passe en essayant object.method()de sélectionner la méthode à appeler.
Marko Topolnik
15

Il n'y a pas de concept d'optimisation ici.

Une staticméthode est staticdue au fait que vous déclarez explicitement que la méthode ne repose sur aucune instance de la classe englobante simplement parce qu'elle n'en a pas besoin. Alors que l'avertissement Eclipse, comme indiqué dans la documentation:

Lorsqu'il est activé, le compilateur émettra une erreur ou un avertissement pour les méthodes qui sont privées ou finales et qui ne font référence qu'à des membres statiques.

Si vous n'avez besoin d'aucune variable d'instance et que votre méthode est privée (ne peut pas être appelée de l'extérieur) ou finale (ne peut pas être remplacée), il n'y a aucune raison de la laisser être une méthode normale au lieu d'une méthode statique. Une méthode statique est intrinsèquement plus sûre, même simplement parce que vous êtes autorisé à faire moins de choses avec elle (elle n'a besoin d'aucune instance, vous n'avez aucun thisobjet implicite ).

Jack
la source
7

Je n'ai pas d'informations sur les performances, je suppose que c'est légèrement meilleur au plus, car le code n'a pas besoin de faire une répartition dynamique en fonction du type.

Cependant, un argument beaucoup plus fort contre la refactorisation en méthodes statiques est que l'utilisation actuelle de la statique est considérée comme une mauvaise pratique. Les méthodes / variables statiques ne s'intègrent pas bien dans un langage orienté objet et sont également difficiles à tester correctement. C'est la raison pour laquelle certains langages plus récents abandonnent complètement le concept de méthodes / variables statiques, ou essaient de l'intérioriser dans le langage d'une manière qui joue mieux avec OO (par exemple, les objets dans Scala).

La plupart du temps, vous avez besoin de méthodes statiques pour implémenter des fonctions qui n'utilisent que des paramètres comme entrée et produisent une sortie en utilisant cela (par exemple, des fonctions utilitaires / d'assistance) Dans les langues modernes, il existe un concept de fonction de première classe qui permet cela, donc statique n'est pas nécessaire. Java 8 aura des expressions lambda intégrées, nous allons donc déjà dans cette direction.

Istvan Devai
la source
7
Les méthodes statiques sont simples à tester (du moment qu'elles sont autonomes - en particulier les fonctions pures, qui sont la cible principale d'une méthode statique). Le concept OO n'a rien à offrir dans ce cas. De plus, le concept de fonction de première classe n'a que très peu, voire rien, à voir avec le concept de méthode statique. Si jamais vous avez besoin d'une fonction de première classe qui fait le travail d'une méthode statique existante, il suffit de quelques caractères pour l'implémenter.
Marko Topolnik
5
La remarque de testabilité n'était probablement pas orientée directement vers la méthode statique, mais les méthodes statiques sont beaucoup plus difficiles à simuler, elles compliquent donc le test des méthodes qui appellent des méthodes statiques.
Buhb
2
Les méthodes statiques sont faciles à simuler si vous utilisez un puissant framework de simulation comme JMockit , PowerMock ou Groovy .
Jeff Olson
Ce sont des private staticméthodes, vous n'aurez donc pas besoin de vous moquer d'elles
Blundell
3

1. Méthode de déclarationstaticdonne un léger avantage en termes de performances, mais ce qui est plus utile, il permet de l'utiliser sans avoir d'instance d'objet à portée de main (pensez par exemple à la méthode factory ou à l'obtention d'un singleton). Il sert également le but documentaire de dire la nature de la méthode. Cet objectif documentaire ne doit pas être ignoré, car il donne une indication immédiate sur la nature de la méthode aux lecteurs du code et aux utilisateurs de l'API et sert également d'outil de réflexion pour le programmeur d'origine - être explicite sur la signification prévue aide vous pensez aussi bien et produisez un code de meilleure qualité (je pense que d'après mon expérience personnelle, mais les gens sont différents). Par exemple, il est logique et donc souhaitable de faire la distinction entre les méthodes opérant sur un type et les méthodes agissant sur une instance du type (comme indiqué parJon Skeet dans son commentaire à une question C # ).

Un autre cas d'utilisation des staticméthodes consiste à imiter l'interface de programmation procédurale. Pensez à la java.lang.System.println()classe et aux méthodes et attributs qu'elle contient. La classe java.lang.Systemest utilisée comme un espace de nom de regroupement plutôt que comme un objet instanciable.

2. Comment Eclipse (ou tout autre type d'entité programmée ou non - biocomposable ou non biocomposable) peut-il savoir avec certitude quelle méthode peut être déclarée statique? Même si une classe de base n'accède pas aux variables d'instance ou n'appelle pas de méthodes non statiques, les choses peuvent changer par le mécanisme d'héritage. Ce n'est que si la méthode ne peut pas être remplacée par l'héritage d'une sous-classe, que nous pouvons affirmer avec 100% de certitude que la méthode peut vraiment être déclarée static. Remplacer une méthode est impossible exactement dans les deux cas où

  1. private (aucune sous-classe ne peut l'utiliser directement et ne le sait même pas en principe), ou
  2. final (même si accessible par la sous-classe, il n'y a aucun moyen de changer la méthode pour faire référence aux données ou aux fonctions d'instance).

D'où la logique de l'option Eclipse.

3. L'affiche originale demande également: « En signalant une méthode comme statique, je suppose que cela montre que vous n'utilisez aucune variable d'instance et que vous pourriez donc être déplacé vers une classe de style utils? » C'est un très bon point. Parfois, ce type de modification de conception est indiqué par l'avertissement.

C'est une option très utile, que je m'assurerais personnellement d'activer, si j'utilisais Eclipse et si je programmais en Java.

FooF
la source
1

Voir la réponse de Samuel sur la manière dont la portée de la méthode change. Je suppose que c'est l'aspect principal pour rendre une méthode statique.

Vous avez également posé des questions sur les performances:

Il peut y avoir un petit gain de performances, car un appel à une méthode statique n'a pas besoin de la référence implicite «this» comme paramètre.

Cependant, cet impact sur les performances est vraiment minime. Par conséquent, tout dépend de la portée.

Noir
la source
1

À partir des consignes de performances Android:

Préférez statique à virtuel Si vous n'avez pas besoin d'accéder aux champs d'un objet, rendez votre méthode statique. Les invocations seront environ 15% à 20% plus rapides. C'est également une bonne pratique, car vous pouvez dire à partir de la signature de la méthode que l'appel de la méthode ne peut pas modifier l'état de l'objet.

http://developer.android.com/training/articles/perf-tips.html#PreferStatic

Blundell
la source
"que l'appel de la méthode ne peut pas modifier l'état de l'objet" - est incroyablement trompeur. Je ne sais pas pour vous, mais je considère certainement que les attributs statiques d'une classe font partie de l'état d'un objet.
Adam Parkin le
0

Eh bien, la documentation Eclipse dit à propos de l'avertissement en question:

La méthode peut être statique

Lorsqu'il est activé, le compilateur émettra une erreur ou un avertissement pour les méthodes qui sont privées ou finales et qui ne font référence qu'aux membres statiques

Je pense que cela dit à peu près tout. Si la méthode est privée et finale et ne fait référence qu'à des membres statiques, la méthode en question pourrait tout aussi bien être déclarée statique et, par là, rendre évident que nous avons uniquement l'intention d'accéder au contenu statique à partir d'elle.

Honnêtement, je ne pense pas qu'il y ait une autre raison mystérieuse derrière cela.

Edwin Dalorzo
la source
0

Il me manquait quelques chiffres pour les différences de vitesse. J'ai donc essayé de les comparer, ce qui s'est avéré pas si facile: la boucle Java devient plus lente après quelques exécutions / la faute de JIT?

J'ai finalement utilisé Caliper et les résultats sont les mêmes que pour exécuter mes tests à la main:

Il n'y a pas de différence mesurable pour les appels statiques / dynamiques. Du moins pas pour Linux / AMD64 / Java7.

Les résultats de Caliper sont ici: https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName,scenario.vmSpec.options.CMSLargeCoalSurplusPercent,Scenario.vecent. CMSLargeSplitSurplusPercent, scenario.vmSpec.options.CMSSmallCoalSurplusPercent, scenario.vmSpec.options.CMSSmallSplitSurplusPercent, scenario.vmSpec.options.FLSLargestBlockCoalesceProity, scenario.vmSpec.optionsMarkteximity.vmSpec.options

et mes propres résultats sont:

Static: 352 ms
Dynamic: 353 ms
Static: 348 ms
Dynamic: 349 ms
Static: 349 ms
Dynamic: 348 ms
Static: 349 ms
Dynamic: 344 ms

La classe de test d'étrier était:

public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark {

    public static void main( String [] args ){

        CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args );
    }

    public int timeAddDynamic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addDynamic( 1, i );
        }
        return r;
    }

    public int timeAddStatic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addStatic( 1, i );
        }
        return r;
    }

    public int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

Et ma propre classe de test était:

public class TestPerformanceOfStaticVsDynamicCalls {

    private static final int RUNS = 1_000_000_000;

    public static void main( String [] args ) throws Exception{

        new TestPerformanceOfStaticVsDynamicCalls().run();
    }

    private void run(){

        int r=0;
        long start, end;

        for( int loop = 0; loop<10; loop++ ){

            // Benchmark

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addStatic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Static: " + ( end - start ) + " ms" );

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addDynamic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Dynamic: " + ( end - start ) + " ms" );

            // Do something with r to keep compiler happy
            System.out.println( r );

        }

    }

    private int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}
Scheintod
la source
serait intéressant de voir les résultats sur divers appareils et versions Android
Blundell
Oui. Je pensais que vous seriez intéressé :) Mais puisque vous créez un logiciel Android et que vous avez probablement un appareil Android connecté à votre station de développement, je vous suggère de choisir le code, de l'exécuter et de partager les résultats?
Scheintod
-2

Les méthodes que vous pouvez déclarer comme statiques sont celles qui ne nécessitent pas d'instanciation, telles que

public class MyClass
{
    public static string InvertText(string text)
    {
        return text.Invert();
    }
}

Ce que vous pouvez ensuite appeler en retour dans n'importe quelle autre classe sans instancier cette classe.

public class MyClassTwo
{
    public void DoSomething()
    {
        var text = "hello world";
        Console.Write(MyClass.InvertText(text));
    }
}

... Mais c'est quelque chose que vous savez probablement déjà. Cela ne vous donne aucun avantage réel en soi, si ce n'est de préciser que la méthode n'utilise aucune variable d'instance.

En d'autres termes, vous pouvez l'éteindre complètement en toute sécurité. Si vous savez que vous n'utiliserez jamais une méthode dans d'autres classes (dans ce cas, elle ne devrait être que privée), vous n'avez pas du tout besoin qu'elle soit statique.

NeroS
la source
1
Quelle est cette langue? Cet exemple compile-t-il? Rien n'est statique ici.
Piotr Perak
En effet, il semble que j'ai oublié «statique» de la méthode InvertText. Et c'est un exemple basé sur c #
NeroS