Static

De ChuWiki

static[editar]

Cuando en un atributo o método le ponemos delante static

static int a;
static void metodo();

ese atributo o método tiene una seria de características especiales:

  • Existe sin necesidad de instanciar la clase. Si la clase que lo contiene se llama Clase, podemos usarlos sin necesidad de instanciar esa clase. Todo lo siguiente es válido
Clase.a;
Clase.metodo();
Clase unaInstancia = new Clase();
unaInstaacia.a;  // Es valido, aunque puede dar un warning
unaInstancia.metodo();   // Es valido, aunque puede dar un warning
  • Este atributo o método es compartido por todas las instancias de la clase.
Clase unaInstancia = new Clase();
Clase otraIntancia = new Clase();
unaInstancia.a = 3;
System.out.println(otraInstancia.a); // Esto escribe 3
System.out.println(Clase.a); // Esto tambien escribe 3

static - no static[editar]

Como hemos comentado, un atributo o método static existe sin necesidad de instanciar la clase y es compartido por todas las instancias de esa clase. Por el contrario, un atributo o método no static, no existe hasta que se haga un new de la clase y los atributos no son compartidos por las distintas instancia. Cada instancia tiene su propia copia del atributo.

Esto hace que desde un método no static podamos usar sin problemas los atributos y métodos static, pero no al revés. Desde un método static no se puede usar o llamar directamente a un atributo o método no static. Al igual que en cualquier otro sitio del código, desde un método static debemos decir de qué instancia queremos usar el método o atributo no static.

En el siguiente ejemplo, la llamada al atributo y al metodo darán error, ya que main() es static, pero los atributos no lo son.

public class Clase
{
   public int atributo=3;
   public void metodo() {
      // hace cosas
   }
   public static void main (String [] args) {
      // Estas llamadas dan error. Mientras no se haga el new de Clase,
      // no existen ni atributo ni metodo().
      System.out.println (atributo);
      metodo();
   }
}

Lo correcto es hacer uno o más new de Clase y luego usar el atributo o método concreto de una de las instancias.

public class Clase
{
   public int atributo=3;
   public void metodo() {
      // hace cosas
   }
   public static void main (String [] args) {
      Clase a = new Clase();
      System.out.println (a.atributo);
      a.metodo();

      Clase b = new Clase();
      System.out.println (b.atributo);
      b.metodo();

      // a.atributo y b.atributo son distintos.
   }
}

Posibles utilidades de static[editar]

Las posibles utilidades para esto son, entre otras:

  • Definir constantes final. Si no las hacemos static, cada instancia de la clase tiene su propia copia de la constante, lo que es un desperdicio de memoria. Salvo este tipo de constantes, las buenas prácticas de programación desaconsejan hacer los atributos públicos.
 public static final double PI = 3.1416;
  • Definir atributos que interese que sean compartidos entre todas las instancias. Por ejemplo, si queremos un contador de cuántas veces se ha instanciado la clase, ponemos un contador entero static en la clase. En cada constructor de la clase se incrementa el contador.
 public class Clase {
    protected static int contador=0;
    public Clase ()
    {
       contador++;
       ...
    }
    ...
 }
  • Definir métodos que no usen atributos de la clase. Es una forma de poder usarlos sin instanciar la clase, ahorrando espacio de memoria y velocidad cada vez que se quiere usar dicho método. Suelen ser métodos de "utilidad", por ejemplo, para obtener un int a partir de un String, se puede usar Integer.parseInt(String). Es static y así podemos usarlo sin necesidad de instanciar un Integer cada vez que lo necesitemmos.
 int valor = Integer.parseInt("323"); // No es necesario instanciar Integer.
  • Aunque no creo que haya sido pensado para eso, es una forma de conseguir variables globales o funciones en java. Si el atributo static es public, se puede acceder a él directamente desde cualquier sitio, sin más que hacer el import de la clase. Nos ahorra el andar pasando una instancia de la clase como parámetro en constructores o métodos setClase().
 import Clase;
 ...
 Clase.a;
 Clase.metodo();
Sin embargo, hay que tener en cuenta que las variables globales y los atributos public no son buenas prácticas de programación.