La diferencia entre variables miembro estáticas y variables miembro no estáticas
Tome el siguiente ejemplo como ejemplo.
paquete cn.galc.test;public class Cat { /** * Variable miembro estática*/ private static int sid = 0; private String name; } public void info() { System.out.println("Mi nombre es " + nombre + ",NO." + id } public static void main(String[] args) { Cat.sid); = 100; Gato mimi = nuevo Gato("mimi"); Gato pipi = nuevo Gato("mimi.info());Comprender el proceso de ejecución de todo el programa dibujando diagramas de análisis de memoria.
Al ejecutar la primera oración del programa: Cat.sid = 100;, el sid aquí es una variable miembro estática. La variable estática se almacena en el área de datos (seg. de datos), así que primero asigne un pequeño espacio sid en el área de datos. Una vez ejecutada la oración, el sid contiene un valor de 100.
El diagrama de diseño de la memoria en este momento es el siguiente:
A continuación, el programa ejecuta:
Gato mimi = nuevo Gato(“mimi”);
Aquí, se llama al método constructor Cat (nombre de cadena) de la clase Cat. El método constructor se define de la siguiente manera:
Gato (nombre de cadena){ this.name = nombre; id=sid++ } Al llamar, primero asigne una pequeña porción de memoria mm en la memoria de la pila, que contiene la dirección del objeto de instancia de la clase Cat en la memoria del montón. mm es el objeto de referencia del objeto de la clase Cat en la memoria del montón. Este constructor declara una variable de parámetro formal de tipo cadena, por lo que "mimi" se pasa al constructor como un parámetro real. Dado que la constante de cadena se asigna y almacena en el área de datos, hay una pequeña porción de memoria adicional en el área de datos. Se utiliza para almacenar la cadena "mimi". La distribución de memoria en este momento se muestra en la siguiente figura:
Al llamar al constructor, primero asigne un pequeño espacio en la memoria de la pila para el nombre del parámetro formal y luego pase la cadena "mimi" como parámetro real para nombrar. La cadena también es un tipo de referencia, excepto por esos cuatro y ocho. tipos de datos básicos, todos los demás son tipos de referencia, por lo que se puede considerar que una cadena también es un objeto. Entonces esto equivale a pasar la referencia del objeto "mimi" al nombre, por lo que ahora el nombre apunta a "mimi". Entonces, el diseño de la memoria en este momento es el que se muestra a continuación:
A continuación, ejecute el código en el cuerpo del constructor:
this.nombre=nombre;
Esto aquí se refiere al objeto actual, que se refiere al gato en la memoria del montón. Aquí, el valor contenido en el nombre en la pila se pasa al atributo de nombre del objeto cat en la memoria del montón, por lo que en este momento el valor contenido en el nombre también se puede encontrar en el objeto de cadena "mimi" ubicado en el En este momento, este nombre también es un objeto de referencia del objeto de cadena "mimi". A través de su valor de atributo, se puede encontrar el objeto de cadena "mimi" ubicado en el área de datos. La distribución de memoria en este momento se muestra en la siguiente figura:
A continuación, ejecute otra línea de código en el cuerpo del método:
id=sid++;
Aquí, el valor de sid se pasa a id, por lo que el valor de id es 100. Después de pasar sid, agregue 1. En este momento, sid se convierte en 101. El diseño de la memoria en este momento se muestra en la siguiente figura.
En este punto, se llama al método constructor y todo el espacio de memoria ocupado por las variables locales asignadas a este método constructor desaparecerá, por lo que la memoria de nombres ubicada en el espacio de la pila desaparece. La referencia al objeto de cadena "mimi" en el área de datos de la memoria de la pila también desaparece. En este momento, solo queda la referencia al objeto de cadena "mimi" en la memoria del montón. El diseño de la memoria en este momento es el que se muestra a continuación:
Siguiente ejecutar:
Gato pipi = nuevo Gato("pipi"); Aquí está la segunda llamada al método constructor Cat (). Todo el proceso de llamada es el mismo que la primera vez. Una vez completada la llamada, el diseño de la memoria en este momento se muestra en la siguiente figura:
Las dos últimas líneas de código se imprimen llamando al método info(). Los resultados de la impresión son los siguientes:
A través de este programa, podemos ver el papel de esta variable miembro estática sid, que se puede contar. Cada vez que salga un gato nuevo, dale un número. Deja que sume 1 por sí solo.
Una vez ejecutado el programa, todo el diseño en la memoria será como se muestra en la figura anterior. Continúa hasta el momento antes de que se complete la llamada al método principal.
Aquí, se llama al método constructor Cat(String name) para crear dos gatos. Primero, se asignan dos espacios pequeños, mimi y pipi, en la memoria de la pila, que contienen las direcciones donde se corresponden los dos gatos. a las direcciones en la memoria del montón. Dos comillas de gato. El método de construcción aquí declara una variable de tipo cadena. La constante de cadena se asigna en el área de datos, por lo que las cadenas pasadas mimi y pipi se almacenarán en el área de datos. Por lo tanto, al área de datos se le asignan dos pequeños bloques de memoria para almacenar las cadenas mimi y pipi, que contienen las cadenas "mimi" y "pipi". Además de los cuatro y ocho tipos de datos básicos, las cadenas también son tipos de referencia. Todos los tipos de datos son tipos de referencia. Entonces puedes pensar en una cuerda como un objeto.
Aquí hay dos gatos nuevos. Ambos gatos tienen sus propios atributos de identificación y nombre, por lo que la identificación y el nombre aquí son variables miembro no estáticas, es decir, no hay modificaciones estáticas. Entonces, cada vez que se crea un nuevo gato, este nuevo gato tiene su propia identificación y nombre, es decir, las variables miembro no estáticas identificación y nombre tienen copias separadas para cada objeto. Pero para las variables miembro estáticas, solo hay una copia. No importa cuántos objetos sean nuevos, incluso si no hay objetos nuevos, las variables miembro estáticas retendrán una copia en el área de datos. Al igual que el sid aquí, el sid se almacena en el área de datos, no importa cuántos gatos nuevos haya en la memoria del montón, solo hay una copia del sid y solo se guarda una copia en el área de datos.
Las variables miembro estáticas pertenecen a toda la clase, no pertenecen a un objeto específico. Entonces, ¿cómo acceder al valor de esta variable miembro estática? En primer lugar, cualquier objeto puede acceder a este valor estático y, al acceder, accede a la misma memoria. El segundo punto es que puede acceder a este valor estático incluso si no hay ningún objeto. Puede acceder a este valor estático a través de "nombre de clase.nombre de variable miembro estática", por lo que en el futuro verá un determinado nombre de clase más "." seguido de Si hay una cosa, entonces la siguiente debe ser estática, como "System.out". Aquí, se accede a esta salida a través del nombre de la clase (clase System) más ".", por lo que esta salida debe ser estática.
Si un miembro de la clase se declara estático, se puede acceder a él antes de que se cree cualquier objeto de la clase sin tener que hacer referencia a ningún objeto. El ejemplo más común de un miembro estático es main(). Debido a que se debe llamar a main() cuando el programa comienza a ejecutarse, se declara estático.
Las variables declaradas estáticas son esencialmente variables globales. Cuando se declara un objeto, no se genera una copia de la variable estática, pero todas las variables de instancia de la clase comparten la misma variable estática. Por ejemplo: declarar un recuento de variables estáticas como el recuento de nuevas instancias de clase. Los métodos declarados estáticos tienen las siguientes restricciones:
(1). Solo pueden llamar a otros métodos estáticos.
(2) Solo pueden acceder a datos estáticos.
(3) No pueden hacer referencia a esto o super de ninguna manera.
Si necesita inicializar sus variables estáticas mediante cálculo, puede declarar un bloque estático. El bloque estático solo se ejecuta una vez cuando se carga la clase. El siguiente ejemplo muestra
La clase tiene un método estático, algunas variables estáticas y un bloque de inicialización estático: public class UserStatic { static int a = 3; static void meth(int x) { System.out.println("x = " + x); System.out.println("a = " + a); System.out.println("b = " + b); estático { System.out.println("Bloque estático); inicializado."); b = a * 4; } public static void main(String args[]) { meth(42); } } Una vez cargada la clase UseStatic, se ejecutan todas las declaraciones estáticas. Primero, a se establece en 3, luego se ejecuta el bloque estático (imprimiendo un mensaje) y, finalmente, b se inicializa en a*4 o 12. Luego se llama a main(), main() llama a meth(), pasando el valor 42 a x. Las tres declaraciones println () se refieren a dos variables estáticas a y b, y a la variable local x.
Nota: Es ilegal hacer referencia a variables de instancia en un método estático.
Aquí está el resultado de este programa:
Bloque estático inicializado x = 42 a = 3 b = 12.
Los métodos y variables estáticos se pueden utilizar independientemente de cualquier objeto fuera de la clase en la que están definidos. En este caso, sólo necesita agregar el operador punto (.) después del nombre de la clase. Por ejemplo, si desea llamar a un método estático desde fuera de la clase, puede utilizar el siguiente formato general:
nombre de clase.método()
Aquí, nombre de clase es el nombre de la clase en la que se define el método estático. Como puede ver, este formato es similar al formato de llamar a métodos no estáticos a través de variables de referencia de objetos. Se puede acceder a una variable estática en el mismo formato: el nombre de la clase más el operador de punto. Así es como Java implementa una versión controlada de funciones globales y variables globales.
Resumir:
(1) Las instancias creadas por la clase en la que se encuentran no pueden acceder a los miembros estáticos.
(2) Si los miembros sin modificación estática son miembros de objetos, son propiedad de cada objeto.
(3) Los miembros modificados con estática son miembros de clase, que una clase puede llamar directamente y son comunes a todos los objetos.
Java Static: como modificador, se puede utilizar para modificar variables, métodos y bloques de código (pero no debe modificar clases).
(1) Modificar variables:
Una propiedad compartida por todos los objetos de una clase, también llamada variable de clase. Esto es similar a las variables globales en lenguaje C. Las variables de clase se inicializan cuando se carga la clase y solo se inicializan una vez. Cuando cualquier objeto en el programa modifica una variable estática, otros objetos verán el valor modificado. Entonces las variables de clase se pueden usar como contadores. Además, se puede acceder a las variables estáticas de Java directamente utilizando el nombre de la clase sin necesidad de un objeto.
(2) Método de modificación:
Una función común a todos los objetos de una clase se llama método estático. También se puede acceder a los métodos estáticos directamente utilizando el nombre de la clase, sin necesidad de un objeto. Por lo tanto, no se puede acceder directamente a variables no estáticas y métodos no estáticos en métodos estáticos, y palabras clave como esta o super no pueden aparecer en métodos estáticos.
(3) Modificar bloques de código Java:
Utilice estático para modificar un bloque de código independiente en una clase, que se denomina bloque de código estático. Los bloques de código estático se ejecutan cuando la clase se carga por primera vez, y sólo una vez. Los bloques de código estático no tienen nombre, por lo que no se pueden llamar explícitamente, sino que solo los llama la máquina virtual cuando se carga la clase. Se utiliza principalmente para completar algunas operaciones de inicialización.
(4) Hablemos de la carga de clases:
Cuando la JVM usa una clase por primera vez, irá a la ruta especificada por la ruta de clase para encontrar el archivo de código de bytes correspondiente a la clase, lo leerá en la JVM y lo guardará. Este proceso se llama carga de clases.
Se puede ver que ya sea una variable, método o bloque de código, siempre que se modifique con estática, estará "listo" cuando se cargue la clase, es decir, se puede usar o ya se ha ejecutado. Todo se puede ejecutar sin objetos. Por el contrario, si no hay estática, se debe acceder a ella a través del objeto.