¿Qué es la sintaxis de inicialización Double Brace ( {{ ... }}
) en Java?
java
initialization
double-brace-initialize
Sgokhales
fuente
fuente
Respuestas:
La inicialización de doble llave crea una clase anónima derivada de la clase especificada (las llaves externas ) y proporciona un bloque de inicializador dentro de esa clase (las llaves internas ). p.ej
Tenga en cuenta que un efecto del uso de esta inicialización de doble paréntesis es que está creando clases internas anónimas. La clase creada tiene un
this
puntero implícito a la clase externa circundante. Aunque normalmente no es un problema, puede causar dolor en algunas circunstancias, por ejemplo, cuando se serializa o se recolecta basura, y vale la pena tenerlo en cuenta.fuente
Cada vez que alguien usa la inicialización de doble llave, un gatito es asesinado.
Además de que la sintaxis es bastante inusual y no es realmente idiomática (el sabor es discutible, por supuesto), está creando innecesariamente dos problemas importantes en su aplicación, sobre los que acabo de bloguear recientemente con más detalle aquí .
1. Estás creando demasiadas clases anónimas
Cada vez que utiliza la inicialización de doble paréntesis, se crea una nueva clase. Por ejemplo, este ejemplo:
... producirá estas clases:
Eso es bastante sobrecarga para tu cargador de clases, ¡para nada! Por supuesto, no tomará mucho tiempo de inicialización si lo hace una vez. Pero si hace esto 20,000 veces en toda su aplicación empresarial ... ¿toda esa memoria de almacenamiento dinámico solo por un poco de "azúcar de sintaxis"?
2. ¡Potencialmente estás creando una pérdida de memoria!
Si toma el código anterior y devuelve ese mapa de un método, las personas que llaman de ese método podrían estar aferrándose a recursos muy pesados que no se pueden recolectar basura. Considere el siguiente ejemplo:
El devuelto
Map
ahora contendrá una referencia a la instancia adjunta deReallyHeavyObject
. Probablemente no quiera arriesgarse a que:Imagen de http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/
3. Puedes fingir que Java tiene literales de mapa
Para responder a su pregunta real, las personas han estado utilizando esta sintaxis para pretender que Java tiene algo así como literales de mapas, similar a los literales de matriz existentes:
Algunas personas pueden encontrar esto sintácticamente estimulante.
fuente
{{...}}
y se declara como unstatic
campo, no debería haber una posible pérdida de memoria, solo una clase anónima y ninguna referencia de instancia adjunta, ¿verdad?Map.of()
para ese propósito, por lo que será una mejor soluciónReallyHeavyObject
. Además, las clases internas anónimas capturan todas las variables locales utilizadas dentro del cuerpo de la clase, por lo que si usa no solo constantes para inicializar colecciones o mapas con este patrón, las instancias de la clase interna las capturarán todas y continuarán haciendo referencia a ellas incluso cuando realmente se eliminen de La colección o el mapa. En ese caso, estas instancias no solo necesitan el doble de memoria necesaria para las referencias, sino que tienen otra pérdida de memoria en ese sentido.Por ejemplo:
Cómo funciona
La primera llave crea una nueva clase interna anónima. Estas clases internas son capaces de acceder al comportamiento de su clase principal. Entonces, en nuestro caso, en realidad estamos creando una subclase de la clase HashSet, por lo que esta clase interna es capaz de usar el método put ().
Y el segundo conjunto de llaves no es más que inicializadores de instancia. Si recuerda los conceptos básicos de Java, puede asociar fácilmente los bloques de inicializador de instancia con inicializadores estáticos debido a un paréntesis similar como struct. La única diferencia es que el inicializador estático se agrega con una palabra clave estática y se ejecuta solo una vez; no importa cuántos objetos crees.
más
fuente
Para una aplicación divertida de inicialización de doble paréntesis, vea aquí la matriz de Dwemthy en Java .
Un experto
Y ahora, prepárate para el
BattleOfGrottoOfSausageSmells
y ... ¡tocino grueso!fuente
Creo que es importante enfatizar que no existe la "inicialización de doble paréntesis" en Java . El sitio web de Oracle no tiene este término. En este ejemplo, hay dos características utilizadas juntas: clase anónima y bloque inicializador. Parece que los desarrolladores han olvidado el antiguo bloque inicializador y causan cierta confusión en este tema. Cita de documentos de Oracle :
Los bloques de inicializador para las variables de instancia se parecen a los bloques de inicializador estático, pero sin la palabra clave estática:
fuente
1- No existe el uso de llaves dobles:
me gustaría señalar que no existe la inicialización de llaves dobles . Solo hay un bloque de inicialización de una llave tradicional tradicional. El segundo bloque de llaves no tiene nada que ver con la inicialización. Las respuestas dicen que esas dos llaves inicializan algo, pero no es así.
2- No se trata solo de clases anónimas sino de todas las clases:
casi todas las respuestas hablan de que es algo que se usa al crear clases internas anónimas. Creo que las personas que leen esas respuestas tendrán la impresión de que esto solo se usa al crear clases internas anónimas. Pero se usa en todas las clases. Parece que leer esas respuestas es una característica especial completamente nueva dedicada a clases anónimas y creo que es engañoso.
3- El propósito es solo colocar los corchetes uno detrás del otro, no es un concepto nuevo:
más allá, esta pregunta habla sobre la situación cuando el segundo corchete de apertura es justo después del primer corchete de apertura. Cuando se usa en la clase normal, generalmente hay algún código entre dos llaves, pero es totalmente lo mismo. Entonces se trata de colocar corchetes. Así que creo que no deberíamos decir que esto es algo nuevo y emocionante, porque es lo que todos sabemos, pero solo escrito con algún código entre paréntesis. No debemos crear un nuevo concepto llamado "inicialización de doble paréntesis".
4- Crear clases anónimas anidadas no tiene nada que ver con dos llaves:
no estoy de acuerdo con el argumento de que creas demasiadas clases anónimas. No los está creando porque es un bloque de inicialización, sino simplemente porque los creó. Se crearían incluso si no utilizara la inicialización de dos llaves, por lo que esos problemas ocurrirían incluso sin inicialización ... La inicialización no es el factor que crea los objetos inicializados.
fuente
Para evitar todos los efectos negativos de la inicialización de doble paréntesis, como:
hacer las siguientes cosas:
Ejemplo:
Uso:
Ventajas:
Desventajas
Y, como resultado, tenemos el patrón de generador de Java más simple que existe.
Ver todas las muestras en github: java-sf-builder-simple-example
fuente
Es, entre otros usos, un atajo para inicializar colecciones. Aprende más ...
fuente
te refieres a algo como esto?
es una inicialización de lista de matriz en tiempo de creación (pirateo)
fuente
Puede poner algunas declaraciones Java como bucle para inicializar la colección:
Pero este caso afecta el rendimiento, verifique esta discusión
fuente
Como se señaló en @Lukas Eder, se debe evitar la doble inicialización de colecciones.
Crea una clase interna anónima, y dado que todas las clases internas mantienen una referencia a la instancia principal, puede, y probablemente el 99% lo hará, evitar la recolección de basura si se hace referencia a estos objetos de recolección por más objetos que solo el declarante.
Java 9 ha introducido métodos de conveniencia
List.of
,Set.of
yMap.of
que se deben utilizar en su lugar. Son más rápidos y más eficientes que el inicializador de doble paréntesis.fuente
La primera llave crea una nueva clase anónima y el segundo conjunto de llaves crea una instancia de inicializadores como el bloque estático.
Como otros han señalado, no es seguro de usar.
Sin embargo, siempre puede usar esta alternativa para inicializar colecciones.
fuente
Esto parece ser lo mismo que con la palabra clave tan popular en flash y vbscript. Es un método para cambiar lo que
this
es y nada más.fuente
this
es. La sintaxis solo crea una clase anónima (por lo que cualquier referencia athis
se referiría al objeto de esa nueva clase anónima), y luego usa un bloque{...}
inicializador para inicializar la instancia recién creada.