Entendiendo la palabra clave estática

14

Tengo algo de experiencia en el desarrollo con Java, Javascript y PHP.

Estoy leyendo Microsoft Visual C # 2010 Paso a paso, que creo que es un muy buen libro sobre cómo presentarte el lenguaje C #.

Parece que tengo problemas para entender la palabra clave estática. Por lo que entiendo hasta aquí, si una clase se declara estática, todos los métodos y variables deben ser estáticos. El método principal siempre es un método estático, por lo que en la clase que existe el método principal, todas las variables y métodos se declaran estáticos si tiene que llamarlos en el método principal. También me he dado cuenta de que, para llamar a un método estático de otra clase, no es necesario crear un objeto que pueda utilizar el nombre de la clase.

¿Pero cuál es el propósito real de la palabra clave estática? ¿Cuándo debo declarar variables y métodos estáticos?

    
pregunta Nistor Alexandru 03.09.2012 - 12:12

6 respuestas

14

La palabra clave 'estática' en C # se refiere a algo en la clase, o la clase en sí, que se comparte entre todas las instancias de la clase. Por ejemplo, se puede acceder a un campo marcado como estático desde todas las instancias de esa clase a través del nombre de la clase.

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

}

Honestamente puedo decir que nunca he usado una clase marcada como estática con la excepción de crear métodos de extensión ( Tutorial rápido sobre métodos de extensión ).

De todos modos, hay patrones de diseño específicos para utilizar métodos estáticos, como patrón de fábrica y singleton pattern , pero lo importante es recordar que los métodos estáticos y los constructores no se ocupan de ninguna instancia específica de una clase (a menos que pasar uno en), generalmente para hacer cálculos o para hacer una comparación entre objetos. El método "Principal" al que se refiere es siempre estático, pero para verlo desde un punto de vista diferente, vea este artículo .

Para continuar con esto, aquí está cómo se llama la diferencia entre métodos, campos y propiedades estáticos e instanciados.

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
}

También, consulte esta publicación para una descripción más detallada. mirar en clases estáticas.

    
respondido por el iMortalitySX 04.09.2012 - 21:17
17

Esta es la manera en que Joshua Bloch lo explica, lo cual me parece genial, como la mayoría de lo que dice (sí, soy un fanático de Joshua Bloch :)). Esto se cita de memoria.

Imagina que una clase es el equivalente a un plano para una casa. Imagen entonces que una casa es para el plano como una instancia de la clase es para la clase. Puede tener una clase (impresión azul) y varias instancias (casas) creadas a partir de ella.

Ahora el sentido común dicta que la mayoría de las funciones / comportamientos que una casa (instancia) puede tener / hacer, incluso si se declaran en el plano azul, no se pueden usar hasta que una casa real (instancia) esté hecha de que blue-print (clase). Por ejemplo, su huella azul puede contener en ella el lugar donde deben ir los focos y las bombillas, pero no tiene forma de hacer que esos trabajos funcionen en el plano azul, tiene que construir la casa para poder encienda y apague el interruptor de la luz y encienda y apague ciertas bombillas.

Sin embargo, es posible que tenga algún comportamiento que se aplique directamente a la copia azul, y que pueda usar / acceder directamente a la ventana azul sin necesidad de convertir una casa real en esa casa azul. Imagine que su plano azul tiene un botón que, al presionar, mostrará la huella de la casa contenida en ese plano azul (calculando todas las longitudes de las paredes y demás). Obviamente, PODRÍAS construir una casa primero, luego medir su huella, pero puedes hacerlo solo con la copia azul, por lo que sería más útil tener este comportamiento implementado en la ventana azul. Un botón incrustado de este tipo que imprima la huella de la casa equivale a tener una función estática en una clase.

    
respondido por el Shivan Dragon 03.09.2012 - 12:36
10

Mirarlo de esta manera me ayuda:

  • Cada tipo tiene una instancia estática.
  • La instancia estática se crea la primera vez que accede al tipo, ya sea a través de la instancia estática o creando otra instancia.
  • Puede crear tantas instancias no estáticas como desee, pero solo hay una instancia estática.
  • Cualquier cosa dentro de una clase que se declare como estática pertenece a la instancia estática y, por lo tanto, no tiene acceso a ninguna otra instancia que cree. Pero las otras instancias TIENEN acceso a la instancia estática.
  • Si una clase se declara como estática, entonces no puede crear otras instancias, solo puede existir la instancia estática.
  • Puede declarar un constructor estático para la instancia estática al igual que un constructor para una instancia normal (pero declarándolo estático).

En cuanto a cuándo usar la palabra clave estática:

  • Cualquier método que no necesite acceso a las propiedades locales puede y probablemente debería declararse estático.
  • Las clases de ayuda que no tienen ningún estado (lo que debería ser raro de todos modos) y que nunca se burlarán pueden declararse estáticas. Si deben o no es otro asunto; usa esta funcionalidad con moderación.
  • Las propiedades y los campos a los que deben acceder todas las instancias de una clase deben declararse estáticos. Pero use esto solo cuando no haya otra opción.
respondido por el pdr 03.09.2012 - 12:20
2

La explicación más simple --- Estático = > Solo existirá una copia por entorno.

Por lo tanto, dentro de una VM o CLR solo habrá una copia de una clase estática, y cualquier otra clase que haga referencia tendrá que compartir sus métodos y datos con todas las demás clases que hacen referencia a ella.

Para una variable estática, solo habrá una instancia de esta variable en el entorno de tiempo de ejecución, sin importar cuántas copias de la clase propietaria se creen cuando hacen referencia a una variable estática, todas ellas harán referencia al mismo almacenamiento.

    
respondido por el James Anderson 18.05.2015 - 18:16
1

Los miembros estáticos están asociados con la Clase, no con ninguna instancia de esa Clase.

Ya que estamos hablando de .Net, considere la clase Cadena , en particular los métodos Dividir y Unirse .

Split es un método de instancia . Crea una variable de cadena, dale un valor y puedes llamar a Split () en esa variable / valor y recuperar una matriz de "bits":

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

Entonces, por ejemplo, los métodos, el valor contenido dentro de la instancia de clase dada importa .

Join es un método static . De acuerdo, produce un resultado de String cuando se le da un delimitador y una matriz de String para que mastique, por lo que es "algo que ver con" la Clase de String, pero no está asociado con cualquier valor en particular en cualquier instancia de String (de hecho, los valores de instancia no están disponibles para métodos estáticos).
En otros idiomas, el método Unirse podría haberse "pegado" a la Clase Array (o, quizás mejor, una Clase StringArray), pero Nuestros Amigos en Redmond decidieron que era más "relevante" para la clase String, por lo que lo pusieron allí. .

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

Otra alternativa podría haber sido tener un método de combinación instancia , donde el valor contenido dentro de la Cadena [instancia de clase] se usó como delimitador de unión, algo como:

// Maybe one day ... 
String s4 = "," ; 
s1 = s4.Join( array3 ) ; 
    
respondido por el Phill W. 18.05.2015 - 13:27
1

La palabra clave static puede ser un poco difícil de entender para los novatos. Su propósito principal es identificar a un miembro de la clase como no perteneciente a ninguna instancia única de la clase, sino a la clase en sí.

Sin entrar en demasiados detalles, C # (y Java) aplican rígidamente el ideal orientado a objetos de que todo el código y los datos deben pertenecer a un objeto y, por lo tanto, tienen un alcance, visibilidad y vida útil limitados. En general, es la mejor práctica dondequiera que se aplique el principio fundamental de un objeto que representa algo del mundo real. Sin embargo, no siempre; a veces, lo que necesita es una función o variable a la que puede acceder desde en cualquier lugar en el código, sin que tenga que pasar una referencia a un objeto que lo contiene, y con la garantía de que los datos que busca En o cambiar es exactamente de lo que todos los demás están tratando, y no una copia que pertenezca a una instancia diferente de un objeto.

Tal comportamiento estaba disponible en C y C ++ en la forma de la función o variable "global", que no estaba encapsulada en un objeto. Entonces, como compromiso, C # y Java admiten el "alcance estático", un punto intermedio entre el código verdaderamente global sin objeto primario y miembros de instancia de alcance limitado.

Cualquier "miembro de código" (función, propiedad, campo) declarado como static entra en el alcance desde la primera línea de la función main() del programa, y no lo deja hasta que la función main() termine. En un lenguaje sencillo, existe un miembro estático y se puede usar mientras el programa se esté ejecutando. Además, los miembros estáticos se invocan llamándolos como miembros del tipo en sí, no como miembros de ninguna instancia de ese tipo:

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

Esto hace que los miembros estáticos sean visibles para cualquier código que tenga conocimiento del tipo, ya sea que conozcan o no una instancia única de él.

Para responder a su pregunta, el beneficio principal de marcar algo como estático es que se hace visible donde se conoce el tipo, independientemente de si el código consumidor tiene o puede obtener una instancia del objeto que lo contiene. También hay un beneficio de rendimiento ligero ; Debido a que el método está en el alcance estático, solo puede acceder a otros miembros estáticos (de la misma clase u otros), y lo que se pasa como parámetro. Por lo tanto, el tiempo de ejecución no tiene que resolver ninguna referencia a la instancia actual del objeto contenedor, ya que normalmente tendría que hacerlo con un método de instancia para proporcionar información de estado específica del contexto.

Las clases enteras también se pueden marcar como estáticas; Al hacerlo, le dice al compilador que la declaración de clase constará únicamente de miembros estáticos y, por lo tanto, no se puede crear una instancia. Esta es una manera fácil de asegurar que haya una, y solo una, copia de un objeto en la memoria; hacer la clase y todo en ella estática. Sin embargo, es muy raro que esta sea la mejor solución para tal necesidad. En una situación donde se requiere exactamente una copia de un conjunto de datos, el "singleton" se recomienda en su lugar; esta es una clase no estática, que utiliza un descriptor de acceso estático y un constructor no público para proporcionar acceso a una sola instancia de sí misma. Teóricamente, un singleton proporciona los mismos beneficios que una clase completamente estática, pero con la capacidad adicional de usar la clase de forma orientada a objetos basada en instancias.

    
respondido por el KeithS 17.11.2014 - 21:57

Lea otras preguntas en las etiquetas