El modificador 'static' tiene un profundo impacto en el comportamiento de una variable o método por ello es que normalmente se trata a este modificador completamente separado de los demás. Para entender la forma en que un miembro estático (static) trabaja, veremos primeramente una razón para la cual utilizarlo.
Imaginemos que se cuenta con una clase de utilidad que tiene un método que siempre se ejecuta de la misma manera, por decir un ejemplo, un método que siempre devuelve un valor aleatorio. No importa qué instancia de la clase esté llamando a éste método, siempre se comportará de la misma manera. En otras palabras, el comportamiento del método es independiente de la instancia de la clase o, lo que es lo mismo, del estado actual del objeto.
Imaginemos otro escenario. Supongamos que se desea realizar un conteo de todas las instancias que se tienen de una clase en particular, ¿dónde debería de almacenarse dicha variable? no funcionará el mantenerla como una variable de instancia dentro de la clase a la cual se quiere realizar el conteo ya que al momento de instanciarla el contador se inicializará a su valor por defecto (como sucede con todas las variables de instancia), entonces, ¿cómo haremos para realizar este conteo?
Para resolver un poco la situación planteada anteriormente pongamos en claro que las variables y los métodos marcados con el modificador 'static', es decir, variables y métodos estáticos pertenecen a la clase, no a una instancia de dicha clase en particular. De hecho, se pueden utilizar componentes estáticos sin tener una instancia de la clase. Pero en caso de que existan instancias de dicha clase, el componente estático de la misma será compartido por todas aquellas instancias existentes en un momento dado; solo existe una copia.
El código a continuación declara y utiliza una variable para nuestro contador estático:
class MiClase{
//declaramos e inicializamos la variable estática
static int contador = 0;
public MiClase(){
//Se modifica el valor en el constructor
contador += 1;
}
public static void main (String[] args){
new MiClase();
new MiClase();
new MiClase();
System.out.println("El número de clases son: "+contador);
}
}
En el código anterior, la variable estática 'contador' es inicializada en cero cuando MiClase es cargada por primera vez en la JVM, antes de que cualquier instancia sea creada. Cada vez que una nueva instancia de la clase se crea se manda a llamar al constructor de la clase y el contador aumenta en uno. Cuando el código se ejecuta ya fueron creadas 3 instancias de la clase y el resultado es el siguiente:
El número de clases son: 3
Ahora imaginemos lo que puede suceder si 'contador' fuera una variable de instancia, en otras palabras, no estática:
class MiClase{
//declaramos e inicializamos la variable de instancia
int contador = 0;
public MiClase(){
//Se modifica el valor en el constructor
contador += 1;
}
public static void main (String[] args){
new MiClase();
new MiClase();
new MiClase();
System.out.println("El número de clases son: "+contador);
}
}
Cuando el código anterior se intenta ejecutar sigue creando las mismas 3 instancias de la clase dentro de main() pero el resultado es un error de compilador. Ya no pensamos siquiera en que corra sino en que por lo menos se pueda compilar. Cuando lo intentamos nos aparece un error como el siguiente:
MiClase.java: 11: non-static variable contador cannot be referenced from static context
System.out.println("El número de clases son: "+contador);
^
1 error
La JVM no sabe de qué objeto de MiClase estás tratando de imprimir su variable 'contador’. El problema principal es que el método main() en sí es estático y no está corriendo sobre un objeto en particular de la clase sino directamente en la clase. Un método estático no puede acceder a ningún componente (método o variable) no estático. Pensemos de la siguiente manera: estático (static) = clase, no-estático = instancia.
Acceder a métodos y variables estáticas::
De manera que no se necesita tener una instancia de la clase para invocar a un método o acceder a una variable estática, entonces, ¿cómo se invoca o se usa un componente estático? ¿cuál es la sintáxis?. La respuesta es simple, para acceder a un componente estático de una clase solamente basta con utilizar el operador punto (.) después del nombre de la clase y posteriormente hacer referencia al método o variable estática. P. ej:
class MiClase{
static int contador = 0;
public MiClase(){
contador += 1;
}
}
class ProbarMiClase{
public static void main(String[] args){
new MiClase();
new MiClase();
new MiClase();
System.out.printl("Contador: "+MiClase.contador);
}
}
De igual manera se puede acceder a un componente estático de una clase por medio de un objeto de dicha clase, pero recordemos que dicho valor no dependerá de la instancia y todos los métodos o variables arrojarán el mismo resultado independientemente de qué objeto lo esté invocando o accediendo.
MiClase mc = new MiClase();
int clases = mc.contador;
Por último, tengamos en cuenta que los métodos estáticos no pueden ser sobreescritos. Esto no significa que no puedan ser 'redefinidos' dentro de una clase, pero redefinir no es lo mismo que sobreescribir.
Alguna duda o algo qué decir? Deja tu comentario. Saludox.
Gracias por tu explicacion del comienzo, es decir del momento en que indicas las razones de cuando ocuparlo... vi muchas páginas donde intentaban explicar con ejemplos horribles. De hecho muchos copy paste en varias páginas. Leyendo tu aclaración quede perfecto.
ResponderBorrarGracias nuevamente
Podrias explicar que sucede con las variables definidas dentro de un método estatico, tambien son estaticas? o estas si son dependendientes e la instancia de la clase y al modificarlas en una no se modifican en las otras instancias...de antemano muchas gracias.
ResponderBorrarPara un aprendiz: excelente, me aclaró lo que no tenía claro. Gracias por tu ayuda
ResponderBorrarMuy Bien explicado y con unos ejemplos muy claros.
ResponderBorrarMil gracias!
Excelente Comentario por fin entendí muchas gracias hasta copie la explicación en un lugar especial para tenerla jaja...
ResponderBorrargracias por el comentario excelente explicación.
ResponderBorrarMuy bien explicado, los ejemplos sencillos son los que mejor enseñan. Muy bueno Luis.
ResponderBorrargracias por traducir el scjp :)
ResponderBorrarahora la pregunta clave.. una clase estatica consume mas memoria que una clave no estatica???
ResponderBorrarQue buena explicación. He encontrado pocas como ésta. Muchas gracias.
ResponderBorrarExcelente explicación! (Y)
ResponderBorrarcual es la diferencia entre redefinir y sobre escribir? o merjo dicho, como se redefine.
ResponderBorrarMuy buena explicación, estuve buscando mucho en la red y no encotré nada bueno, hasta ahora.
Solo quería decirte que da gusto buscar información y encontrar explicaciones como esta, un 10 :)
ResponderBorrarGracias. Esto me sirve como claro ejemplo en su uso en herencias para contar cada instancia hecha en el constructor de cada hijo :D
ResponderBorrarMuy bueno!! También me quedé con la interrogante sobre la diferencia entre sobre-escribir y re-definir :/
ResponderBorrarSi pudieras hacer un post al respecto, sería muy agradecido :D
Saludos desde Panamá :)
Qué tal,
ResponderBorrarAquí un más información al respecto:
Sobreescritura de métodos en Java
Saludos
Excelente explicación 10 puntos.
ResponderBorrarGracias muy bien explicado
ResponderBorrarsi, muy bien explicado. Gracias.
ResponderBorrarmuy buena explicación
ResponderBorrarGracias.
ResponderBorrarGracias es un buen aporte y práctico. Entendí sobre el uso de static en java.
ResponderBorrarGracias exelente explicacion, tenia problemas al cargar los niveles de mi juego de diferentes niveles y ahora pude seguir, gracias a tu explicacion :).
ResponderBorrarMuchas gracias por el aporte es muy útil la verdad, pero me surgió una duda cual es la diferencia entre sobreescrito y redefinido ??? es que no me queda claro
ResponderBorrarGracias.... muy sencilla y practica la explicación.
ResponderBorrarRedefinir y Sobrescribir es lo mismo. La diferencia está en Redefinir y Sobrecargar.
ResponderBorrarExcelente, todo entendido.
ResponderBorrar