Soy un programador de Java que es nuevo en el mundo corporativo. Recientemente desarrollé una aplicación usando Groovy y Java. Todo el código que escribí usaba una buena cantidad de estadísticas. El lote técnico superior me pidió que redujera la cantidad de estadísticas utilizadas. He buscado en Google casi lo mismo, y encuentro que muchos programadores están bastante en contra del uso de variables estáticas.
Encuentro que las variables estáticas son más convenientes de usar. Y supongo que también son eficientes (corríjame si me equivoco), porque si tuviera que hacer 10,000 llamadas a una función dentro de una clase, me encantaría hacer que el método sea estático y usarlo directamente Class.methodCall()
en lugar de abarrotando la memoria con 10,000 instancias de la clase, ¿verdad?
Además, las estadísticas reducen las interdependencias en las otras partes del código. Pueden actuar como titulares perfectos del estado. Además de esto, encuentro que las estadísticas están ampliamente implementadas en algunos idiomas como Smalltalk y Scala . Entonces, ¿por qué esta opresión por la estática prevalece entre los programadores (especialmente en el mundo de Java)?
PD: corríjame si mis suposiciones sobre la estática son incorrectas.
Respuestas:
Las variables estáticas representan el estado global. Es difícil razonar y probar: si creo una nueva instancia de un objeto, puedo razonar sobre su nuevo estado dentro de las pruebas. Si uso código que usa variables estáticas, podría estar en cualquier estado, y cualquier cosa podría estar modificándolo.
Podría continuar durante bastante tiempo, pero el concepto más amplio en el que pensar es que cuanto más limitado sea el alcance de algo, más fácil será razonar. Somos buenos para pensar en cosas pequeñas, pero es difícil razonar sobre el estado de un sistema de un millón de líneas si no hay modularidad. Esto se aplica a todo tipo de cosas, por cierto, no solo a las variables estáticas.
fuente
No está muy orientado a objetos: una razón por la cual algunas personas podrían considerar "estáticas" es que son contrarias al paradigma orientado a objetos . En particular, viola el principio de que los datos están encapsulados en objetos (que pueden extenderse, ocultar información, etc.). La estática, en la forma en que está describiendo su uso, es esencialmente usarlos como una variable global para evitar tratar problemas como el alcance. Sin embargo, las variables globales son una de las características definitorias del paradigma de programación de procedimiento o imperativo, no una característica del código orientado a objetos "bueno". Esto no quiere decir que el paradigma de procedimiento sea malo, pero tengo la impresión de que su supervisor espera que esté escribiendo "buen código orientado a objetos" y realmente desea escribir "
Hay muchos gotchyas en Java cuando comienzas a usar estadísticas que no siempre son obvias de inmediato. Por ejemplo, si tiene dos copias de su programa ejecutándose en la misma máquina virtual, ¿compartirán el valor de la variable estática y se meterán entre sí? ¿O qué sucede cuando amplías la clase, puedes anular el miembro estático? ¿Su máquina virtual se está quedando sin memoria porque tiene un número increíble de estadísticas y esa memoria no se puede recuperar para otros objetos de instancia necesarios?
Vida útil del objeto: además, las estadísticas tienen una vida útil que coincide con todo el tiempo de ejecución del programa. Esto significa que, incluso una vez que haya terminado de usar su clase, la memoria de todas esas variables estáticas no se puede recolectar basura. Si, por ejemplo, hizo que sus variables no sean estáticas, y en su función main () hizo una sola instancia de su clase, y luego le pidió a su clase que ejecutara una función particular 10,000 veces, una vez que se hicieron esas 10,000 llamadas , y elimina sus referencias a la instancia única, todas sus variables estáticas podrían ser recolectadas y reutilizadas.
Evita cierta reutilización: además, los métodos estáticos no se pueden usar para implementar una interfaz, por lo que los métodos estáticos pueden evitar que ciertas características orientadas a objetos sean utilizables.
Otras opciones: Si su principal preocupación es la eficiencia, puede haber otras formas mejores de resolver el problema de la velocidad que considerar solo la ventaja de que la invocación suele ser más rápida que la creación. Considere si los modificadores transitorios o volátiles son necesarios en cualquier lugar. Para preservar la capacidad de estar en línea, un método podría marcarse como final en lugar de estático. Los parámetros del método y otras variables se pueden marcar como finales para permitir ciertas optimizaciones del compilador basadas en suposiciones sobre qué puede cambiar esas variables. Un objeto de instancia podría reutilizarse varias veces en lugar de crear una nueva instancia cada vez. Puede haber interruptores de optimización del compilador que deberían estar activados para la aplicación en general. Quizás, el diseño debería configurarse de modo que las 10,000 ejecuciones puedan ser multiproceso y aprovechar los núcleos de múltiples procesadores. Si la portabilidad no es
Si por alguna razón no desea múltiples copias de un objeto, el patrón de diseño singleton, tiene ventajas sobre los objetos estáticos, como la seguridad de subprocesos (suponiendo que su singleton esté bien codificado), permitiendo una inicialización diferida, garantizando que el objeto se haya inicializado correctamente cuando se usa, subclases, ventajas en la prueba y refactorización de su código, sin mencionar que si en algún momento cambia de opinión acerca de querer solo una instancia de un objeto, es MUCHO más fácil eliminar el código para evitar instancias duplicadas que refactorizar todo el código de variable estática para usar variables de instancia. He tenido que hacer eso antes, no es divertido, y terminas teniendo que editar muchas más clases, lo que aumenta el riesgo de introducir nuevos errores ... mucho mejor para configurar las cosas "bien" la primera vez, incluso si parece que tiene sus desventajas. Para mi, el reprocesamiento requerido en caso de que decida en el futuro que necesita copias múltiples de algo es probablemente una de las razones más convincentes para usar la estática lo menos posible. Y por lo tanto, también estaría en desacuerdo con su afirmación de que las estadísticas reducen las interdependencias, creo que terminará con un código que está más acoplado si tiene muchas estadísticas a las que se puede acceder directamente, en lugar de un objeto que "sabe cómo hacerlo algo "en sí mismo.
fuente
synchronized
métodos), no significa que el código de llamada esté libre de condiciones de carrera con respecto al estado de singleton.Object Lifetime
, es un punto muy importante que mencionó @jessica.Mal es un término subjetivo.
No controlas las estadísticas en términos de creación y destrucción. Viven a instancias del programa de carga y descarga.
Dado que las estadísticas viven en un espacio, todos los hilos que deseen usarlas deben pasar por el control de acceso que debe administrar. Esto significa que los programas están más acoplados y este cambio es más difícil de imaginar y administrar (como dice J Skeet). Esto lleva a problemas de aislamiento del impacto del cambio y, por lo tanto, afecta la forma en que se administran las pruebas.
Estos son los dos problemas principales que tengo con ellos.
fuente
No. Los estados globales no son malvados per se. Pero tenemos que ver su código para ver si lo usó correctamente. Es muy posible que un novato abuse de los estados globales; al igual que abusaría de todas las características del lenguaje.
Los estados globales son una necesidad absoluta. No podemos evitar los estados globales. No podemos evitar el razonamiento sobre los estados globales. - Si nos interesa entender nuestra semántica de aplicación.
Las personas que intentan deshacerse de los estados globales por el bien, inevitablemente terminan con un sistema mucho más complejo, y los estados globales todavía están allí, disfrazados de manera inteligente / idiota bajo muchas capas de indirecciones; y todavía tenemos que razonar sobre los estados globales, después de desenvolver todas las indirecciones.
Al igual que las personas de Spring que declaran generosamente estados globales en xml y piensan que de alguna manera es superior.
@ Jon Skeet
if I create a new instance of an object
ahora tiene dos razones para razonar: el estado dentro del objeto y el estado del entorno que aloja el objeto.fuente
Hay 2 problemas principales con las variables estáticas:
fuente
Si está utilizando la palabra clave 'estática' sin la palabra clave 'final', esto debería ser una señal para considerar cuidadosamente su diseño. Incluso la presencia de un 'final' no es un pase libre, ya que un objeto final estático mutable puede ser igual de peligroso.
Estimaría en algún lugar alrededor del 85% de las veces que veo un 'estático' sin un 'final', es INCORRECTO. A menudo, encontraré soluciones extrañas para enmascarar u ocultar estos problemas.
Por favor no cree mutables estáticas. Especialmente colecciones. En general, las Colecciones deben inicializarse cuando se inicializa su objeto contenedor y deben diseñarse de modo que se restablezcan u olviden cuando se olvida su objeto contenedor.
El uso de estática puede crear errores muy sutiles que causarán dolor a los ingenieros. Lo sé, porque he creado y cazado estos errores.
Si desea más detalles, siga leyendo ...
¿Por qué no usar estadísticas?
Hay muchos problemas con la estática, incluida la escritura y ejecución de pruebas, así como errores sutiles que no son obvios de inmediato.
El código que se basa en objetos estáticos no se puede probar fácilmente en la unidad, y las estadísticas no se pueden burlar fácilmente (por lo general).
Si usa estadísticas, no es posible intercambiar la implementación de la clase para probar componentes de nivel superior. Por ejemplo, imagine un CustomerDAO estático que devuelve los objetos del Cliente que carga de la base de datos. Ahora tengo una clase CustomerFilter, que necesita acceder a algunos objetos de Customer. Si CustomerDAO es estático, no puedo escribir una prueba para CustomerFilter sin inicializar primero mi base de datos y completar información útil.
Y la población e inicialización de la base de datos lleva mucho tiempo. Y en mi experiencia, su marco de inicialización de DB cambiará con el tiempo, lo que significa que los datos se transformarán y las pruebas pueden romperse. Es decir, imagine que el Cliente 1 solía ser un VIP, pero el marco de inicialización de DB cambió, y ahora el Cliente 1 ya no es VIP, pero su prueba estaba codificada para cargar el Cliente 1 ...
Un mejor enfoque es crear una instancia de CustomerDAO y pasarlo al CustomerFilter cuando se construye. (Un enfoque aún mejor sería usar Spring u otro marco de Inversión de Control.
Una vez que haga esto, puede simular o eliminar rápidamente un DAO alternativo en su CustomerFilterTest, lo que le permite tener más control sobre la prueba,
Sin el DAO estático, la prueba será más rápida (sin inicialización de db) y más confiable (porque no fallará cuando cambie el código de inicialización de db). Por ejemplo, en este caso, asegurarse de que el Cliente 1 sea y siempre será un VIP, en lo que respecta a la prueba.
Ejecutando pruebas
Las estadísticas causan un problema real cuando se ejecutan conjuntos de pruebas unitarias juntas (por ejemplo, con su servidor de Integración Continua). Imagine un mapa estático de objetos de Socket de red que permanece abierto de una prueba a otra. La primera prueba podría abrir un Socket en el puerto 8080, pero se olvidó de borrar el Mapa cuando la prueba se derribó. Ahora, cuando se inicia una segunda prueba, es probable que se bloquee cuando intenta crear un nuevo Socket para el puerto 8080, ya que el puerto todavía está ocupado. Imagine también que las referencias de Socket en su Colección estática no se eliminan, y (con la excepción de WeakHashMap) nunca son elegibles para la recolección de basura, lo que causa una pérdida de memoria.
Este es un ejemplo demasiado generalizado, pero en sistemas grandes, este problema ocurre TODO EL TIEMPO. La gente no piensa en las pruebas unitarias que inician y detienen su software repetidamente en la misma JVM, pero es una buena prueba del diseño de su software, y si tiene aspiraciones de alta disponibilidad, es algo que debe tener en cuenta.
Estos problemas a menudo surgen con objetos de marco, por ejemplo, sus capas de acceso a la base de datos, almacenamiento en caché, mensajería y registro. Si está utilizando Java EE o algunos de los mejores frameworks, probablemente manejen mucho de esto por usted, pero si como yo está tratando con un sistema heredado, es posible que tenga muchos frameworks personalizados para acceder a estas capas.
Si la configuración del sistema que se aplica a estos componentes del marco cambia entre las pruebas unitarias, y el marco de prueba unitaria no destruye y reconstruye los componentes, estos cambios no pueden tener efecto, y cuando una prueba se basa en esos cambios, fallarán .
Incluso los componentes no marco están sujetos a este problema. Imagine un mapa estático llamado OpenOrders. Escribe una prueba que crea algunas órdenes abiertas y comprueba para asegurarse de que todas estén en el estado correcto, luego finaliza la prueba. Otro desarrollador escribe una segunda prueba que coloca los pedidos que necesita en el mapa de OpenOrders, luego afirma que el número de pedidos es exacto. Ejecutadas individualmente, ambas pruebas pasarían, pero cuando se ejecutan juntas en una suite, fallarán.
Peor aún, la falla puede basarse en el orden en que se ejecutaron las pruebas.
En este caso, al evitar la estática, se evita el riesgo de persistencia de datos en las instancias de prueba, lo que garantiza una mejor confiabilidad de la prueba.
Errores sutiles
Si trabaja en un entorno de alta disponibilidad, o en cualquier lugar donde los subprocesos puedan iniciarse y detenerse, la misma preocupación mencionada anteriormente con los conjuntos de pruebas unitarias puede aplicarse cuando su código también se ejecuta en producción.
Cuando se trata de hilos, en lugar de usar un objeto estático para almacenar datos, es mejor usar un objeto inicializado durante la fase de inicio del hilo. De esta manera, cada vez que se inicia el subproceso, se crea una nueva instancia del objeto (con una configuración potencialmente nueva) y evita que los datos de una instancia del subproceso se filtren a la siguiente instancia.
Cuando un hilo muere, un objeto estático no se restablece ni se recolecta basura. Imagine que tiene un hilo llamado "EmailCustomers", y cuando se inicia, completa una colección de cadenas estática con una lista de direcciones de correo electrónico, luego comienza a enviar cada una de las direcciones. Digamos que el hilo se interrumpe o cancela de alguna manera, por lo que su marco de alta disponibilidad reinicia el hilo. Luego, cuando se inicia el hilo, vuelve a cargar la lista de clientes. Pero debido a que la colección es estática, podría retener la lista de direcciones de correo electrónico de la colección anterior. Ahora algunos clientes pueden recibir correos electrónicos duplicados.
Un aparte: final estático
El uso de "static final" es efectivamente el equivalente de Java de un C #define, aunque existen diferencias de implementación técnica. AC / C ++ #define es intercambiado fuera del código por el preprocesador, antes de la compilación. Un "final estático" de Java terminará en la memoria residente en la pila. De esa manera, es más similar a una variable de "constante estática" en C ++ que a una #define.
Resumen
Espero que esto ayude a explicar algunas razones básicas por las que las estadísticas son problemáticas. Si está utilizando un marco Java moderno como Java EE o Spring, etc., es posible que no encuentre muchas de estas situaciones, pero si está trabajando con un gran cuerpo de código heredado, pueden volverse mucho más frecuentes.
fuente
Como nadie * lo ha mencionado: concurrencia. Las variables estáticas pueden sorprenderlo si tiene múltiples hilos que leen y escriben en la variable estática. Esto es común en aplicaciones web (por ejemplo, ASP.NET) y puede causar algunos errores bastante enloquecedores. Por ejemplo, si tiene una variable estática que una página actualiza y dos personas solicitan la página "casi al mismo tiempo", un usuario puede obtener el resultado esperado por el otro, o peor.
Espero que estés preparado para usar cerraduras y lidiar con la contención.
* En realidad, Preet Sangha lo mencionó.
fuente
Resumiendo algunas ventajas y desventajas básicas del uso de métodos estáticos en Java:
Ventajas:
Desventajas
fuente
Debe equilibrar la necesidad de encapsular datos en un objeto con un estado, en comparación con la necesidad de simplemente calcular el resultado de una función en algunos datos.
También lo hace la encapsulación. En aplicaciones grandes, las estadísticas tienden a producir código de espagueti y no permiten fácilmente la refactorización o prueba.
Las otras respuestas también brindan buenas razones contra el uso excesivo de estadísticas.
fuente
Las variables estáticas generalmente se consideran malas porque representan un estado global y, por lo tanto, son mucho más difíciles de razonar. En particular, rompen los supuestos de la programación orientada a objetos. En la programación orientada a objetos, cada objeto tiene su propio estado, representado por variables de instancia (no estáticas). Las variables estáticas representan estados entre instancias que pueden ser mucho más difíciles de probar en unidades. Esto se debe principalmente a que es más difícil aislar los cambios en las variables estáticas en una sola prueba.
Dicho esto, es importante hacer una distinción entre las variables estáticas regulares (generalmente consideradas malas) y las variables estáticas finales (constantes AKA; no tan malas).
fuente
En mi opinión, casi nunca se trata de rendimiento, se trata de diseño. No considero que el uso de métodos estáticos sea incorrecto en comparación con el uso de variables estáticas (pero supongo que en realidad estás hablando de llamadas a métodos).
Se trata simplemente de cómo aislar la lógica y darle un buen lugar. A veces eso justifica el uso de métodos estáticos, de los cuales
java.lang.Math
es un buen ejemplo. Creo que cuando nombras la mayoría de tus clasesXxxUtil
oXxxhelper
es mejor que reconsideres tu diseño.fuente
Acabo de resumir algunos de los puntos hechos en las respuestas. Si encuentra algo malo, no dude en corregirlo.
Escalado: tenemos exactamente una instancia de una variable estática por JVM. Supongamos que estamos desarrollando un sistema de administración de bibliotecas y decidimos poner el nombre del libro como una variable estática, ya que solo hay uno por libro. Pero si el sistema crece y estamos usando múltiples JVM, ¿entonces no tenemos una manera de averiguar con qué libro estamos tratando?
Seguridad de subprocesos: tanto la variable de instancia como la variable estática deben controlarse cuando se usan en entornos de subprocesos múltiples. Pero en el caso de una variable de instancia, no necesita protección a menos que se comparta explícitamente entre subprocesos, pero en el caso de una variable estática, siempre se comparte entre todos los subprocesos del proceso.
Pruebas: aunque el diseño comprobable no equivale a un buen diseño, pero rara vez observaremos un buen diseño que no sea comprobable. Como las variables estáticas representan el estado global y se hace muy difícil probarlas.
Razonamiento sobre el estado: si creo una nueva instancia de una clase, podemos razonar sobre el estado de esta instancia, pero si tiene variables estáticas, podría estar en cualquier estado. ¿Por qué? Debido a que es posible que la variable estática haya sido modificada por alguna instancia diferente, ya que la variable estática se comparte entre las instancias.
Serialización: la serialización tampoco funciona bien con ellos.
Creación y destrucción: la creación y destrucción de variables estáticas no se pueden controlar. Por lo general, se crean y destruyen en el momento de carga y descarga del programa. Significa que son malos para la administración de la memoria y también suman el tiempo de inicialización al inicio.
Pero, ¿y si realmente los necesitamos?
Pero a veces podemos tener una necesidad genuina de ellos. Si realmente sentimos la necesidad de muchas variables estáticas que se comparten en la aplicación, entonces una opción es utilizar el patrón de diseño Singleton que tendrá todas estas variables. O podemos crear algún objeto que tenga estas variables estáticas y se pueda pasar.
Además, si la variable estática se marca como final, se convierte en una constante y el valor que se le asigna una vez no se puede cambiar. Significa que nos salvará de todos los problemas que enfrentamos debido a su mutabilidad.
fuente
Me parece que está preguntando sobre variables estáticas, pero también señala métodos estáticos en sus ejemplos.
Las variables estáticas no son malas: tienen su adopción como variables globales como constantes en la mayoría de los casos combinadas con el modificador final, pero como se dice, no las uses en exceso.
Métodos estáticos, también conocido como método de utilidad. Por lo general, no es una mala práctica usarlos, pero la principal preocupación es que podrían obstruir pruebas.
Como ejemplo de un gran proyecto de Java que usa muchas estadísticas y lo hace correctamente, ¡mira Play! marco . También hay discusión respecto en SO.
Las variables / métodos estáticos combinados con la importación estática también se usan ampliamente en bibliotecas que facilitan la programación declarativa en java como: hacerlo fácil o Hamcrest . No sería posible sin muchas variables y métodos estáticos.
Por lo tanto, las variables estáticas (y los métodos) son buenos, ¡pero úselos sabiamente!
fuente
Lo más importante es que las variables estáticas crean problemas con la seguridad de los datos (en cualquier momento cambiado, cualquiera puede cambiar, acceso directo sin objeto, etc.)
Para más información lea esto Gracias.
fuente
Se puede sugerir que en la mayoría de los casos en los que usa una variable estática, realmente desea usar el patrón singleton .
El problema con los estados globales es que a veces lo que tiene sentido como global en un contexto más simple, debe ser un poco más flexible en un contexto práctico, y aquí es donde el patrón singleton se vuelve útil.
fuente
Otra razón más: fragilidad.
Si tiene una clase, la mayoría de las personas esperan poder crearla y usarla a voluntad.
Puede documentar que no es el caso, o protegerse contra él (patrón único / de fábrica), pero eso es un trabajo adicional y, por lo tanto, un costo adicional. Incluso entonces, en una gran empresa, es probable que alguien intente usar su clase en algún momento sin prestar atención a todos los comentarios agradables o la fábrica.
Si usa muchas variables estáticas, eso se romperá. Los errores son caros.
Entre una mejora de rendimiento de .0001% y la robustez para cambiar por parte de desarrolladores potencialmente desorientados, en muchos casos, la robustez es la buena opción.
fuente
Encuentro que las variables estáticas son más convenientes de usar. Y supongo que también son eficientes (corríjame si me equivoco) porque si tuviera que hacer 10,000 llamadas a una función dentro de una clase, me complacería hacer que el método sea estático y usar una clase directa. en lugar de saturar la memoria con 10.000 instancias de la clase, ¿verdad?
Veo lo que piensas, pero un patrón Singleton simple hará lo mismo sin tener que instanciar 10 000 objetos.
Se pueden usar métodos estáticos, pero solo para funciones que están relacionadas con el dominio del objeto y que no necesitan o usan propiedades internas del objeto.
ex:
fuente
Class.Instance
) es apenas mejor que una variable estática. Es un poco más comprobable, pero aún mucho peor que los diseños en los que se crea una sola instancia en lugar de crear su código suponiendo que solo haya una.Class.Instance
) que lleva un estado mutable es un mal diseño de la OMI. En ese caso, prefiero un diseño donde obtengo los singletons que necesito usar pasados como parámetro a la clase que los usa (generalmente con la ayuda de DI). Los singletons clásicos lógicamente inmutables están bien en mi opinión.El tema de 'La estática es malvada' es más un problema sobre el estado global. El momento apropiado para que una variable sea estática es si nunca tiene más de un estado; Las herramientas de IE a las que debe poder acceder todo el marco y que siempre devuelven los mismos resultados para las mismas llamadas a métodos nunca son 'malas' que las estadísticas. En cuanto a tu comentario:
Las estadísticas son la opción ideal y eficiente para variables / clases que nunca cambian .
El problema con el estado global es la inconsistencia inherente que puede crear. La documentación sobre las pruebas unitarias a menudo aborda este problema, ya que cada vez que hay un estado global al que pueden acceder más de varios objetos no relacionados, las pruebas unitarias estarán incompletas y no 'granuladas'. Como se menciona en este artículo sobre el estado global y los singletons , si los objetos A y B no están relacionados (ya que en uno no se da referencia expresa a otro), A no debería ser capaz de afectar el estado de B.
Hay algunas excepciones a la prohibición del estado global en un buen código, como el reloj. El tiempo es global y, en cierto sentido, cambia el estado de los objetos sin tener una relación codificada.
fuente
Mi $ .02 es que varias de estas respuestas confunden el problema, en lugar de decir "las estadísticas son malas". Creo que es mejor hablar sobre el alcance y las instancias.
Lo que yo diría es que una estática es una variable de "clase": representa un valor que se comparte en todas las instancias de esa clase. Por lo general, también debe tener un alcance de esa manera (protegido o privado para la clase y sus instancias).
Si planea poner un comportamiento a nivel de clase a su alrededor y exponerlo a otro código, entonces un singleton puede ser una mejor solución para soportar cambios en el futuro (como sugirió @Jessica). Esto se debe a que puede usar interfaces a nivel de instancia / singleton de maneras que no puede usar a nivel de clase, en particular la herencia.
Algunas reflexiones sobre por qué creo que algunos de los aspectos en otras respuestas no son fundamentales para la pregunta ...
La estática no es "global". En Java, el alcance se controla por separado de static / instance.
La concurrencia no es menos peligrosa para las estadísticas que los métodos de instancia. Todavía es un estado que necesita ser protegido. Claro que puede tener 1000 instancias con una variable de instancia cada una y solo una variable estática, pero si el código de acceso no está escrito de manera segura para los subprocesos, todavía está atornillado, puede que le tome un poco más de tiempo darse cuenta. .
La gestión del ciclo de vida es un argumento interesante, pero creo que es menos importante. No veo por qué es más difícil administrar un par de métodos de clase como init () / clear () que la creación y destrucción de una instancia singleton. De hecho, algunos podrían decir que un singleton es un poco más complicado debido a GC.
PD: en términos de Smalltalk, muchos de sus dialectos tienen variables de clase, pero en Smalltalk las clases son en realidad instancias de Metaclass, por lo que realmente son variables en la instancia de Metaclass. Aún así, aplicaría la misma regla general. Si se están utilizando para un estado compartido entre instancias, entonces está bien. Si son compatibles con la funcionalidad pública, debería mirar un Singleton. Suspiro, seguro que extraño a Smalltalk ...
fuente
Hay dos preguntas principales en tu publicación.
Primero, sobre las variables estáticas. Las variables estáticas son completamente innecesarias y su uso se puede evitar fácilmente. En los idiomas OOP en general, y en Java en particular, los parámetros de función se pasan por referencia, es decir, si pasa un objeto a una función, está pasando un puntero al objeto, por lo que no necesita definir variables estáticas ya que Puede pasar un puntero al objeto a cualquier ámbito que necesite esta información. Incluso si esto implica que llenará su memoria con punteros, esto no representará necesariamente un bajo rendimiento porque los sistemas de paginación de memoria reales están optimizados para manejar esto, y mantendrán en la memoria las páginas referenciadas por los punteros que pasó al nuevo alcance; El uso de variables estáticas puede hacer que el sistema cargue la página de memoria donde se almacenan cuando es necesario acceder (esto sucederá si la página no ha sido accedida durante mucho tiempo). Una buena práctica es reunir todo ese material estático en algunas pequeñas "clases de configuración", esto asegurará que el sistema lo ponga todo en la misma página de memoria.
En segundo lugar, sobre los métodos estáticos. Los métodos estáticos no son tan malos, pero pueden reducir rápidamente el rendimiento. Por ejemplo, piense en un método que compara dos objetos de una clase y devuelve un valor que indica cuál de los objetos es más grande (método de comparación típica), este método puede ser estático o no, pero al invocarlo, la forma no estática será más eficiente ya que tendrá que resolver solo dos referencias (una para cada objeto) frente a las tres referencias que deberán resolver la versión estática del mismo método (una para la clase más dos, una para cada objeto). Pero como digo, esto no es tan malo, si echamos un vistazo a la clase de Matemáticas, podemos encontrar muchas funciones matemáticas definidas como métodos estáticos. Esto es realmente más eficiente que poner todos estos métodos en la clase que define los números,
En conclusión: evite el uso de variables estáticas y encuentre el equilibrio de rendimiento correcto cuando trabaje con métodos estáticos o no estáticos.
PD: Perdón por mi inglés.
fuente
No hay nada malo con las variables estáticas per se. Es solo la sintaxis de Java que está rota. Cada clase Java en realidad define dos estructuras: un objeto singleton que encapsula variables estáticas y una instancia. Definir ambos en el mismo bloque fuente es pura maldad, y da como resultado un código que es difícil de leer. Scala hizo eso bien.
fuente
a) Razón sobre los programas.
Si tiene un programa de pequeño a mediano, donde se accede a la variable estática Global.foo, la llamada normalmente proviene de la nada: no hay una ruta y, por lo tanto, no hay una línea de tiempo, cómo la variable llega al lugar, donde es usado Ahora, ¿cómo sé quién lo configuró en su valor real? ¿Cómo sé qué sucede si lo modifico ahora? Tengo grep sobre toda la fuente, para recopilar todos los accesos, para saber qué está pasando.
Si sabe cómo lo usa, porque acaba de escribir el código, el problema es invisible, pero si intenta comprender el código extranjero, lo comprenderá.
b) ¿Realmente solo necesitas uno?
Las variables estáticas a menudo evitan que múltiples programas del mismo tipo se ejecuten en la misma JVM con diferentes valores. A menudo no prevé usos, donde más de una instancia de su programa es útil, pero si evoluciona, o si es útil para otros, pueden experimentar situaciones en las que les gustaría iniciar más de una instancia de su programa. .
Solo un código más o menos inútil que no será utilizado por muchas personas durante un tiempo prolongado de manera intensiva podría funcionar bien con variables estáticas.
fuente
todo (puede :) tiene su propósito, si tiene un montón de subprocesos que necesita compartir / almacenar datos en caché y también toda la memoria accesible (para que no se divida en contextos dentro de una JVM), la estática es la mejor opción
-> por supuesto, puede forzar solo una instancia, pero ¿por qué?
encuentro algunos de los comentarios en este hilo malvados, no las estadísticas;)
fuente
Las variables estáticas no son buenas ni malas. Representan atributos que describen toda la clase y no una instancia particular. Si necesita tener un contador para todas las instancias de una determinada clase, una variable estática sería el lugar adecuado para mantener el valor.
Los problemas aparecen cuando intenta utilizar variables estáticas para mantener valores relacionados con la instancia.
fuente
Todas las respuestas anteriores muestran por qué las estadísticas son malas. La razón por la que son malvados es porque da la falsa impresión de que está escribiendo código orientado a objetos, cuando en realidad no lo está. Eso es simplemente malvado.
fuente
Aquí hay muchas buenas respuestas que se suman,
Memoria: las variables estáticas están activas mientras el cargador de clases viva [en general hasta que VM muera], pero esto es solo en el caso de objetos / referencias masivas almacenados como estáticos.
Modularización: considere conceptos como IOC, dependenceInjection, proxy, etc. Todos están completamente en contra de implementaciones de acoplamiento / estáticas.
Otros inconvenientes: seguridad del hilo, capacidad de prueba
fuente
Piense que si tiene una aplicación con muchos usuarios y ha definido una forma estática, cada usuario modificará también todas las demás formas de otros usuarios.
fuente
Creo que el uso excesivo de variables globales con palabras clave estáticas también conducirá a una pérdida de memoria en algún momento de la aplicación.
fuente
Desde mi punto de vista, la
static
variable debe ser solo de lectura de datos o variables creadas por convención .Por ejemplo, tenemos una interfaz de usuario de algún proyecto, y tenemos una lista de países, idiomas, roles de usuario, etc. Y tenemos clase para organizar estos datos. Estamos absolutamente seguros de que la aplicación no funcionará sin estas listas. así que lo primero que hacemos en la aplicación init es verificar esta lista para ver si hay actualizaciones y obtener esta lista de la API (si es necesario). Por lo tanto, estamos de acuerdo en que estos datos están "siempre" presentes en la aplicación. Prácticamente son datos de solo lectura, por lo que no necesitamos ocuparnos de su estado; al pensar en este caso, realmente no queremos tener muchas instancias de esos datos; este caso parece un candidato perfecto para ser estático .
fuente
He jugado mucho con las estadísticas y ¿puedo darle una respuesta ligeramente diferente, o tal vez una forma ligeramente diferente de verlo?
Cuando utilicé estadísticas en una clase (Miembros y métodos, ambos) eventualmente comencé a notar que mi clase es en realidad dos clases que comparten la responsabilidad: existe la parte "Estática", que se parece mucho a un singleton y existe la no Parte estática (una clase normal). Hasta donde sé, siempre puedes separar esas dos clases por completo simplemente seleccionando todas las estadísticas para una clase y no estadísticas para la otra.
Esto solía suceder mucho cuando tenía una colección estática dentro de una clase que contenía instancias de la clase y algunos métodos estáticos para administrar la colección. Una vez que lo piensas, es obvio que tu clase no está haciendo "Solo una cosa", es ser una colección y hacer algo completamente diferente.
Ahora, refactoricemos un poco el problema: si divide su clase en una clase donde todo es estático y otra que es solo una "Clase normal" y se olvida de la "Clase normal", entonces su pregunta se convierte en una clase puramente estática vs Singleton que se aborda en detalle aquí (y probablemente una docena de otras preguntas).
fuente