Una guía para la palabra clave estática en Java

1. Introducción

En este artículo, exploraremos la palabra clave estática del lenguaje Java en detalle. Descubriremos cómo podemos aplicar estática de palabras clave a variables, métodos, bloques, clases anidadas y qué diferencia hay.

2. La anatomía de la palabra clave estática

En el lenguaje de programación Java, la palabra clave static indica que el miembro en particular pertenece a un tipo en sí mismo, en lugar de a una instancia de ese tipo .

Esto significa que solo se crea una instancia de ese miembro estático que se comparte en todas las instancias de la clase.

La palabra clave se puede aplicar a variables, métodos, bloques y clases anidadas.

3. Los campos estáticos (o variables de clase)

En Java, si un campo se declara estático , se crea exactamente una única copia de ese campo y se comparte entre todas las instancias de esa clase . No importa cuántas veces inicialicemos una clase; siempre habrá solo una copia del campo estático que le pertenezca. El valor de este campo estático se compartirá entre todos los objetos de cualquier clase diferente.

Desde la perspectiva de la memoria, las variables estáticas van en un grupo particular en la memoria de JVM llamado Metaspace (antes de Java 8, este grupo se llamaba Generación Permanente o PermGen, que fue completamente eliminado y reemplazado por Metaspace).

3.1. Ejemplo del campo estático

Supongamos que tenemos una clase Car con varios atributos (variables de instancia) . Siempre que se inicialicen nuevos objetos a partir de este modelo de coche , cada nuevo objeto tendrá su copia distinta de estas variables de instancia.

Sin embargo, suponga que estamos buscando una variable que contenga el recuento de la cantidad de objetos Car que se inicializan y se comparte en todas las instancias de modo que puedan acceder a ella e incrementarla tras su inicialización.

Ahí es donde entran las variables estáticas :

public class Car { private String name; private String engine; public static int numberOfCars; public Car(String name, String engine) { this.name = name; this.engine = engine; numberOfCars++; } // getters and setters }

Ahora, para cada objeto de esta clase que se inicializa, se incrementa la misma copia de la variable numberOfCars . Entonces, para este caso, las siguientes afirmaciones serán verdaderas:

@Test public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() { new Car("Jaguar", "V8"); new Car("Bugatti", "W16"); assertEquals(2, Car.numberOfCars); }

3.2. Razones convincentes para utilizar campos estáticos

  • Cuando el valor de la variable es independiente de los objetos
  • Cuando se supone que el valor se comparte entre todos los objetos

3.3. Puntos clave para recordar

  • Dado que las variables estáticas pertenecen a una clase, se puede acceder a ellas directamente usando el nombre de la clase y no necesitan ninguna referencia de objeto
  • las variables estáticas solo se pueden declarar a nivel de clase
  • Se puede acceder a los campos estáticos sin inicialización del objeto.
  • Aunque podemos acceder a campos estáticos usando una referencia de objeto (como ford.numberOfCars ++ ), debemos abstenernos de usarlo ya que en este caso se vuelve difícil determinar si es una variable de instancia o una variable de clase; en su lugar, siempre debemos referirnos a variables estáticas usando el nombre de la clase (por ejemplo, en este caso, Car.numberOfCars ++ )

4. Los métodos estáticos (o métodos de clase)

Al igual que los campos estáticos , los métodos estáticos también pertenecen a una clase en lugar del objeto, por lo que se pueden llamar sin crear el objeto de la clase en la que residen. Están diseñados para usarse sin crear objetos de la clase.

4.1. Ejemplo de método estático

Los métodos estáticos se utilizan generalmente para realizar una operación que no depende de la creación de la instancia.

Si hay un código que se supone que debe compartirse en todas las instancias de esa clase, escriba ese código en un método estático :

public static void setNumberOfCars(int numberOfCars) { Car.numberOfCars = numberOfCars; }

Los métodos estáticos también se utilizan ampliamente para crear clases de utilidad o ayuda para que se puedan obtener sin crear un nuevo objeto de estas clases.

Simplemente eche un vistazo a las clases de utilidad de Colecciones o Matemáticas de JDK, StringUtils de Apache o CollectionUtils de Spring framework y observe que todos los métodos son estáticos .

4.2. Razones convincentes para utilizar métodos estáticos

  • Para acceder / manipular variables estáticas y otros métodos estáticos que no dependen de objetos
  • Los métodos estáticos se utilizan ampliamente en clases de utilidad y ayuda.

4.3. Puntos clave para recordar

  • Los métodos estáticos en Java se resuelven en tiempo de compilación. Dado que la anulación de métodos es parte del polimorfismo en tiempo de ejecución, los métodos estáticos no se pueden anular
  • los métodos abstractos no pueden ser estáticos
  • Los métodos estáticos no pueden usar esta o súper palabras clave
  • Son válidas las siguientes combinaciones de instancia, métodos de clase y variables:
    1. Los métodos de instancia pueden acceder directamente tanto a métodos de instancia como a variables de instancia
    2. Los métodos de instancia también se puede acceder estáticas variables y estáticos métodos directamente
    3. Los métodos estáticos pueden acceder a todas las variables estáticas y otros métodos estáticos.
    4. los métodos estáticos no pueden acceder directamente a variables de instancia y métodos de instancia ; necesitan alguna referencia de objeto para hacerlo

5. Un bloque estático

Un bloque estático se utiliza para inicializar variables estáticas . Aunque las variables estáticas se pueden inicializar directamente durante la declaración, hay situaciones en las que se nos pide que realicemos el procesamiento de varias líneas.

En tales casos, los bloques estáticos son útiles.

Si las variables estáticas requieren una lógica adicional de declaraciones múltiples durante la inicialización, se puede usar un bloque estático .

5.1. El ejemplo de bloque estático

Supongamos que queremos inicializar un objeto de lista con algunos valores predefinidos.

Esto se vuelve fácil con bloques estáticos :

public class StaticBlockDemo { public static List ranks = new LinkedList(); static { ranks.add("Lieutenant"); ranks.add("Captain"); ranks.add("Major"); } static { ranks.add("Colonel"); ranks.add("General"); } }

En este ejemplo, no sería posible inicializar el objeto List con todos los valores iniciales junto con la declaración; y es por eso que hemos utilizado el bloque estático aquí.

5.2. Razones convincentes para utilizar bloques estáticos

  • Si la inicialización de variables estáticas requiere alguna lógica adicional, excepto la asignación
  • Si la inicialización de variables estáticas es propensa a errores y requiere manejo de excepciones

5.3. Puntos clave para recordar

  • Una clase puede tener varios bloques estáticos.
  • Los campos estáticos y los bloques estáticos se resuelven y ejecutan en el mismo orden en que están presentes en la clase.

6. Una clase estática

El lenguaje de programación Java nos permite crear una clase dentro de una clase. Proporciona una forma convincente de agrupar elementos que solo se usarán en un lugar, esto ayuda a mantener nuestro código más organizado y legible.

La arquitectura de clases anidadas se divide en dos:

  • Las clases anidadas que se declaran estáticas se denominan clases anidadas estáticas mientras que,
  • Las clases anidadas que no son estáticas se denominan clases internas.

La principal diferencia entre estos dos es que las clases internas tienen acceso a todos los miembros de la clase adjunta (incluida la privada), mientras que las clases anidadas estáticas solo tienen acceso a los miembros estáticos de la clase externa.

De hecho, las clases anidadas estáticas se comportaron exactamente como cualquier otra clase de nivel superior, pero encerradas en la única clase que accederá a ella, para proporcionar una mejor conveniencia de empaquetado.

6.1. Ejemplo de clase estática

El enfoque más utilizado para crear objetos singleton es a través de la clase anidada estática , no requiere ninguna sincronización y es fácil de aprender e implementar:

public class Singleton { private Singleton() {} private static class SingletonHolder { public static final Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }

6.2. Compelling Reasons to Use a static Inner Class

  • Grouping classes that will be used only in one place increases encapsulation
  • The code is brought closer to the place that will be only one to use it; this increases readability and code is more maintainable
  • If nested class doesn't require any access to it's enclosing class instance members, then it's better to declare it as static because this way, it won't be coupled to the outer class and hence will be more optimal as they won't require any heap or stack memory

6.3. Key Points to Remember

  • static nested classes do not have access to any instance members of the enclosing outer class; it can only access them through an object's reference
  • Las clases anidadas estáticas pueden acceder a todos los miembros estáticos de la clase envolvente, incluidos los privados.
  • La especificación de programación de Java no nos permite declarar la clase de nivel superior como estática ; solo las clases dentro de las clases (clases anidadas) se pueden hacer como estáticas

7. Conclusión

En este artículo, vimos la palabra clave estática en acción. También leemos sobre las razones y ventajas de usar campos estáticos, métodos estáticos, bloques estáticos y clases internas estáticas.

Como siempre, podemos encontrar el código completo en GitHub.