¿Qué es la inicialización de Double Brace en Java?

Resuelto Saurabh Gokhale asked hace 14 años • 13 respuestas

¿ Qué es la sintaxis de inicialización de Double Brace ( {{ ... }}) en Java?

Saurabh Gokhale avatar Dec 24 '09 22:12 Saurabh Gokhale
Aceptado

La inicialización de doble llave crea una clase anónima derivada de la clase especificada (las llaves externas ) y proporciona un bloque inicializador dentro de esa clase (las llaves internas ). p.ej

new ArrayList<Integer>() {{
   add(1);
   add(2);
}};

Tenga en cuenta que un efecto de usar esta inicialización de doble llave es que está creando clases internas anónimas. La clase creada tiene un thispuntero implícito a la clase externa circundante. Aunque normalmente no es un problema, puede causar molestias en algunas circunstancias, por ejemplo, al serializar o recolectar basura, y vale la pena ser consciente de esto.

Brian Agnew avatar Dec 24 '2009 16:12 Brian Agnew

Cada vez que alguien usa la inicialización de doble llave, mata a un gatito.

Aparte de que la sintaxis es bastante inusual y no realmente idiomática (el gusto es discutible, por supuesto), estás creando innecesariamente dos problemas importantes en tu aplicación, sobre los cuales recientemente escribí con más detalle aquí .

1. Estás creando demasiadas clases anónimas

Cada vez que utiliza la inicialización de doble llave, se crea una nueva clase. Por ejemplo, este ejemplo:

Map source = new HashMap(){{
    put("firstName", "John");
    put("lastName", "Smith");
    put("organizations", new HashMap(){{
        put("0", new HashMap(){{
            put("id", "1234");
        }});
        put("abc", new HashMap(){{
            put("id", "5678");
        }});
    }});
}};

... producirá estas clases:

Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class

Eso es una gran sobrecarga para su cargador de clases, ¡para nada! Por supuesto, no llevará mucho tiempo de inicialización si lo hace una vez. Pero si hace esto 20.000 veces en su aplicación empresarial... ¿toda esa memoria acumulada sólo por un poco de "azúcar de sintaxis"?

2. ¡Posiblemente estás creando una pérdida de memoria!

Si toma el código anterior y devuelve ese mapa desde un método, las personas que llaman a ese método podrían estar reteniendo sin sospechar recursos muy pesados ​​que no pueden ser recolectados como basura. Considere el siguiente ejemplo:

public class ReallyHeavyObject {

    // Just to illustrate...
    private int[] tonsOfValues;
    private Resource[] tonsOfResources;

    // This method almost does nothing
    public Map quickHarmlessMethod() {
        Map source = new HashMap(){{
            put("firstName", "John");
            put("lastName", "Smith");
            put("organizations", new HashMap(){{
                put("0", new HashMap(){{
                    put("id", "1234");
                }});
                put("abc", new HashMap(){{
                    put("id", "5678");
                }});
            }});
        }};

        return source;
    }
}

El archivo devuelto Mapahora contendrá una referencia a la instancia adjunta de ReallyHeavyObject. Probablemente no quieras arriesgarte a eso:

Pérdida de memoria aquí mismo

Imagen de http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

3. Puedes fingir que Java tiene mapas literales.

Para responder a su pregunta real, la gente ha estado usando esta sintaxis para pretender que Java tiene algo así como literales de mapa, similares a los literales de matriz existentes:

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};

Algunas personas pueden encontrar esto estimulante sintácticamente.

Lukas Eder avatar Dec 17 '2014 08:12 Lukas Eder
  • La primera llave crea una nueva clase interna anónima.
  • El segundo conjunto de llaves crea inicializadores de instancia como un bloque estático en Clase.

Por ejemplo:

   public class TestHashMap {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<String,String>(){
        {
            put("1", "ONE");
        }{
            put("2", "TWO");
        }{
            put("3", "THREE");
        }
        };
        Set<String> keySet = map.keySet();
        for (String string : keySet) {
            System.out.println(string+" ->"+map.get(string));
        }
    }
    
}

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 son más que inicializadores de instancia. Si recuerda los conceptos básicos de Java, puede asociar fácilmente bloques de inicializador de instancia con inicializadores estáticos debido a una estructura similar a una llave. La única diferencia es que el inicializador estático se agrega con la palabra clave estática y se ejecuta solo una vez; no importa cuántos objetos crees.

más

Premraj avatar Aug 05 '2015 09:08 Premraj