Comprendre le mot-clé statique

16

J'ai une certaine expérience dans le développement avec Java, Javascript et PHP.

Je lis Microsoft Visual C # 2010 étape par étape, ce qui me semble être un très bon livre pour vous initier au langage C #.

Il semble que je rencontre des problèmes pour comprendre le mot clé statique. D'après ce que je comprends jusqu'à présent, si une classe est déclarée statique, toutes les méthodes et variables doivent être statiques. La méthode principale est toujours une méthode statique, donc dans la classe que la méthode principale existe, toutes les variables et méthodes sont déclarées statiques si vous devez les appeler dans la méthode principale. J'ai également remarqué que pour appeler une méthode statique d'une autre classe, vous n'avez pas besoin de créer un objet dont vous pouvez utiliser le nom de classe.

Mais quel est le but réel du mot-clé statique? Quand dois-je déclarer une variable statique et des méthodes?

Nistor Alexandru
la source
4
statique en C # est presque identique à statique en Java. Si vous le comprenez en Java, vous ne devez pas avoir de problèmes en C #
superM
Java a été mon premier langage de programmation et je ne comprenais pas ce concept là - bas either.I ont seulement utilisé Java pour une courte période de temps
Nistor Alexandru
En bref: utilisez "statique" lorsque vous n'avez besoin d'aucune orientation d'objet, par exemple, seulement quelques méthodes ou variables autonomes. Déclarer une classe statique signifie placer ces fonctions et variables non orientées objet uniquement dans un nom commun (espace), le nom de la classe.
Doc Brown

Réponses:

15

Le mot clé 'statique' en C # fait référence à quelque chose dans la classe, ou la classe elle-même, qui est partagée entre toutes les instances de la classe. Par exemple, un champ marqué comme statique est accessible à partir de toutes les instances de cette classe via le nom de la classe.

public class SomeObject
{
    //Static Field
    static int Foo = 3;

    //instance field
    private int _Foo2 = 4;

    //instance property
    public int Foo2{get{return _Foo2;}set{_Foo2 = value;}}


    //static factory method
    public static SomeObject CreateSomeObject(int fooValue)
    {
        SomeObject retVal = new SomeObject();
        retVal.Foo2 = fooValue;
        return retVal;
    }

    //Parameterless instance constructor
    public SomeObject()
    {
    }

    public static int Add(int x)
    {
        //Static methods can only deal with local variables, or fields that
        //  are also static in the class.  This one adds x to the static member foo
        return x + Foo;

        //Foo2 is not accessable here!
    }

      //Instance method
    public int AddSomething(int x)
    {
        //Add x to the property value of Foo2
        return x + this.Foo2;

        //Note that Foo *is* accessable here as 'SomeObject.Foo'
    }

}

Je peux honnêtement dire que je n'ai jamais utilisé une classe marquée comme statique à l'exception de la création de méthodes d'extention ( Tutoriel rapide sur les méthodes d'extension ).

Quoi qu'il en soit, il existe des modèles de conception spécifiques pour l'utilisation de méthodes statiques, telles que le modèle d'usine et le modèle singleton , mais la chose importante à retenir est que les méthodes statiques et les constructeurs ne traitent pas d'instance spécifique d'une classe (sauf si vous en transmettez une), généralement pour faire des calculs ou faire une comparaison entre les objets. La méthode «principale» à laquelle vous faites référence est toujours statique, mais pour la voir d'un point de vue différent, consultez cet article .

Pour poursuivre, voici comment la différence entre les méthodes, les champs et les propriétés statiques et instanciés est appelée.

public static void Main(string[] args)
{
    //This is a static method that starts a thread in an application
    // space.  At this point not everything actually has to be static...

    //Here is an instantiation with a parameterless contruction
    SomeObject obj = new SomeObject();

    //Here is an instantiation using a static factory method
    SomeObject obj2 = SomeObject.CreateSomeObject(3);

    //Getting field value from static field
    // Notice that this references the class name, not an instance
    int fooValue1 = SomeObject.Foo;

    //Getting property value from instance
    //  Note that this references an object instance
    int fooValue2 = obj2.Foo2;

    //Instance method must be called through an object
    obj2.AddSomething(4);  //if default constructor, would return 8

    //Static methods must be called through class name
    SomeObject.Add(4); //Returns 7
}

Consultez également ce post pour un examen plus approfondi des classes statiques.

iMortalitySX
la source
18

Voici la façon de l'expliquer de Joshua Bloch, que je trouve génial comme la plupart de ses propos (oui, je suis un fan de Joshua Bloch :)). Ceci est cité de mémoire.

Imaginez qu'une classe soit l'équivalent d'un plan pour une maison. Imaginez alors qu'une maison est au plan comme une instance de la classe l'est pour la classe. Vous pouvez créer une classe (blue-print) et plusieurs instances (maisons).

Maintenant, le bon sens dicte que la plupart des fonctions / comportements qu'une maison (instance) peut avoir / faire, même si elles sont déclarées dans le plan, ne peuvent pas être utilisées jusqu'à ce qu'une maison réelle (instance) soit faite de ce bleu -print (classe). Par exemple, votre plan pourrait contenir en lui l'endroit où les interrupteurs d'éclairage et les ampoules devraient aller, mais vous n'avez aucun moyen de les faire fonctionner sur le plan, vous devez réellement construire la maison afin de pouvoir pour allumer et éteindre l'interrupteur d'éclairage et allumer et éteindre certaines ampoules.

Cependant, vous pouvez avoir un comportement qui s'applique directement au plan directeur et auquel vous pouvez utiliser / accéder directement sur le plan sans avoir besoin de créer une maison réelle à partir de ce plan. Imaginez que votre plan a un bouton qui, en appuyant sur, affichera l'empreinte de la maison contenue dans ce plan (en calculant toutes les longueurs des murs et autres). Évidemment, vous POUVEZ d'abord construire une maison, puis mesurer son empreinte, mais vous pouvez le faire avec le plan seul, il serait donc plus utile d'avoir ce comportement implémenté dans le plan. Un tel bouton intégré en bleu qui calcule l'empreinte de la maison équivaut à avoir une fonction statique dans une classe.

Shivan Dragon
la source
Ou vous auriez une Blueprintclasse qui implémente la fonctionnalité du plan, y compris la capacité de calculer l'empreinte de la maison exprimée par le plan. Cette instance de plan directeur est ensuite envoyée à un Builder(à son tour probablement une instance), qui à son tour fait ce qui est nécessaire pour construire et produire un nombre potentiellement arbitraire d' Buildinginstances basé sur un plan directeur.
un CVn du
12

Le regarder de cette façon m'aide:

  • Chaque type a une instance statique.
  • L'instance statique est créée la première fois que vous accédez au type, soit via l'instance statique, soit en créant une autre instance.
  • Vous pouvez créer autant d'instances non statiques que vous le souhaitez, mais il n'y a qu'une seule instance statique.
  • Tout élément d'une classe déclaré comme statique appartient à l'instance statique et n'a donc pas accès aux autres instances que vous créez. Mais les autres instances ont accès à l'instance statique.
  • Si une classe est déclarée comme statique, vous ne pouvez pas créer d'autres instances, seule l'instance statique peut jamais exister.
  • Vous pouvez déclarer un constructeur statique pour l'instance statique comme un constructeur pour une instance normale (mais en le déclarant statique).

Quant à savoir quand utiliser le mot-clé statique:

  • Toute méthode qui n'a pas besoin d'accéder aux propriétés locales peut et doit probablement être déclarée statique.
  • Les classes d'assistance qui n'ont aucun état (ce qui devrait être rare de toute façon) et qui ne seront jamais moquées peuvent être déclarées statiques. Qu'ils le fassent est une autre affaire; utilisez cette fonctionnalité avec parcimonie.
  • Les propriétés et les champs auxquels doivent accéder toutes les instances d'une classe doivent être déclarés statiques. Mais utilisez-le uniquement lorsqu'il n'y a pas d'autre option.
pdr
la source
+1, pour un bon résumé, je ne savais pas que chaque type a 1 instance statique et je trouve étrange de vous dire la vérité.
NoChance
2
@EmmadKareem C'est juste un modèle mental utilisé par pdr, parce que "Looking at it this way helps"lui. Vous trouvez cela étrange parce que ce n'est pas tout à fait vrai, mais vous pouvez y penser comme ça si vous voulez. Connaissez-vous le modèle Bohr? Il s'agit d'un ensemble de règles et d'idées sur la façon dont les atomes et les électrons interagissent les uns avec les autres. Le modèle fonctionne en fonction de ce que vous faites, mais ce n'est pas la réalité.
phant0m
@ phant0m, merci pour l'explication, j'avais l'impression que ce n'était pas un modèle réel et j'ai été surpris à cause de cela.
NoChance
En fait, il y a parfois des raisons pour lesquelles vous ne voudrez peut-être pas créer une méthode staticmême si elle n'utilise pas les propriétés locales. Faire des choses staticpeut ajouter du couplage aux clients car ils doivent s'adresser directement à la classe. Par exemple, cela peut rendre plus difficile le test unitaire avec moquerie.
Allan
@Allan: Sans doute, si vous appelez une méthode publique sur une classe qui n'affecte pas l'état d'une instance de cette classe, elle DEVRAIT être statique, pour que cela soit clair pour le développeur client. Si cette méthode fait tellement qu'elle a besoin de se moquer, c'est un problème différent qui peut être résolu de différentes manières.
pdr
4

Explication la plus simple --- Statique => Une seule copie existera par environnement.

Ainsi, au sein d'une machine virtuelle ou d'un CLR, il n'y aura jamais qu'une seule copie d'une classe statique, et toute autre classe qui la référencera devra partager ses méthodes et ses données avec toutes les autres classes qui la référencent.

Pour une variable statique, il n'y aura qu'une seule instance de cette variable dans l'environnement d'exécution, quel que soit le nombre de copies de la classe propriétaire créées lorsqu'elles font référence à une variable statique, elles feront toutes référence au même élément de stockage.

James Anderson
la source
2

Les membres statiques sont associés à la classe, et non à aucune instance de cette classe.

Puisque nous parlons de .Net, considérons la classe String , en particulier les méthodes Split et Join .

Le fractionnement est une méthode d' instance . Créez une variable String, donnez-lui une valeur et vous pouvez appeler Split () sur cette variable / valeur et récupérer un tableau de "bits":

String s1 = "abc,def,ghi" ; 
String[] array2 = s1.Split( ',' ) ; 

Ainsi, pour les méthodes d'instance, la valeur contenue dans l'instance de classe donnée est importante .

Join est une méthode statique . OK, il donne un résultat String lorsqu'on lui donne un délimiteur et un tableau String à mâcher, donc c'est "quelque chose à voir avec" la classe String, mais il n'est associé à aucune valeur particulière dans aucune instance String (en effet, les valeurs d'instance sont non disponible pour les méthodes statiques).
Dans d'autres langues, la méthode Join aurait pu être «bloquée» sur la classe Array (ou, peut-être mieux, une classe StringArray) mais nos amis de Redmond ont décidé qu'elle était plus «pertinente» pour la classe String, alors ils l'ont mise là .

String[] array3 = { ... } 
s1 = String.Join( array3, "," ) ; 

Une autre alternative aurait pu être d'avoir une méthode Join d' instance , où la valeur contenue dans la String [instance de classe] us utilisée comme délimiteur de jointure, quelque chose comme:

// Maybe one day ... 
String s4 = "," ; 
s1 = s4.Join( array3 ) ; 
Phill W.
la source
2

Le staticmot-clé peut être un peu difficile à saisir pour les débutants. Son objectif principal est d'identifier un membre de la classe comme n'appartenant à aucune instance unique de la classe, mais plutôt à la classe elle-même.

Sans entrer dans trop de détails, C # (et Java) appliquent de manière rigide l'idéal orienté objet selon lequel tout le code et les données doivent appartenir à un objet, et sont donc limités en portée, visibilité et durée de vie. C'est généralement la meilleure pratique partout où le principe fondamental d'un objet représentant quelque chose du monde réel s'applique. Cependant, ce n'est pas toujours le cas; parfois ce que vous avez besoin est une fonction ou variable que vous pouvez obtenir à partir de n'importe où dans le code, sans vous obliger à passer autour d' une référence à un objet contenant, et avec la garantie que les données que vous regardez ou le changement est exactement ce que tout le monde sinon, il ne s'agit pas d'une copie appartenant à une instance différente d'un objet.

Un tel comportement était disponible en C et C ++ sous la forme de la fonction ou variable "globale", qui n'était pas encapsulée dans un objet. Ainsi, en guise de compromis, C # et Java prennent en charge la «portée statique», à mi-chemin entre le code véritablement global sans objet parent et les membres d'instance à portée limitée.

Tout "membre de code" (fonction, propriété, champ) déclaré comme staticentrant dans la portée à partir de la première ligne de la main()fonction du programme , et ne le laisse pas avant la main()fin de la fonction. En clair, un membre statique existe et peut être utilisé tant que le programme est en cours d'exécution. De plus, les membres statiques sont invoqués en les appelant en tant que membres du type lui-même, et non membres d'une instance de ce type:

public class Foo
{
   public int MyInt {get;set;} //this is an "instance member"
   public static int MyStaticInt {get;set;} //this is a "static member"
}

...

var myFoo = new Foo();
myFoo.MyInt = 5; //valid
myFoo.MyStaticInt = 5; //invalid; MyStaticInt doesn't belong to any one Foo

Foo.MyInt = 5; //invalid; MyInt only has meaning in the context of an instance
Foo.MyStaticInt = 2; //valid

Cela rend les membres statiques visibles par tout code connaissant le type, qu'ils en connaissent ou non une seule instance.

Pour répondre à votre question, le principal avantage de marquer un élément comme statique est qu'il devient visible partout où le type lui-même est connu, que le code consommateur possède ou puisse obtenir une instance de l'objet conteneur. Il y a aussi un léger avantage en termes de performances; car la méthode a une portée statique, elle ne peut accéder qu'aux autres membres statiques (de la même classe ou d'autres) et à tout ce qui est passé en tant que paramètre. Par conséquent, le runtime n'a à résoudre aucune référence à l'instance actuelle de l'objet conteneur, comme il le devrait normalement pour une méthode d'instance afin de fournir des informations d'état spécifiques au contexte.

Des classes entières peuvent également être marquées comme statiques; ce faisant, vous indiquez au compilateur que la déclaration de classe sera uniquement composée de membres statiques et ne pourra donc pas être instanciée. Il s'agit d'un moyen simple de s'assurer qu'il existe une et une seule copie d'un objet en mémoire; rendre la classe et tout ce qu'il contient statique. Cependant, il est très rare que ce soit la meilleure solution à un tel besoin. Dans une situation où exactement une copie d'un ensemble de données est requise, le "singleton" est généralement recommandé à la place; il s'agit d'une classe non statique, qui utilise un accesseur statique et un constructeur non public pour fournir l'accès à une seule instance de lui-même. Théoriquement, un singleton offre à peu près les mêmes avantages qu'une classe entièrement statique, mais avec la possibilité supplémentaire d'utiliser la classe d'une manière orientée objet et basée sur une instance.

KeithS
la source