Mise à jour: Ajout d'une expérience pour évaluer la performance de la double accolade de l'initialisation.
Voici le problème quand je suis trop loin avec les classes internes anonymes:
2009/05/27 16:35 1,602 DemoApp2$1.class
2009/05/27 16:35 1,976 DemoApp2$10.class
2009/05/27 16:35 1,919 DemoApp2$11.class
2009/05/27 16:35 2,404 DemoApp2$12.class
2009/05/27 16:35 1,197 DemoApp2$13.class
/* snip */
2009/05/27 16:35 1,953 DemoApp2$30.class
2009/05/27 16:35 1,910 DemoApp2$31.class
2009/05/27 16:35 2,007 DemoApp2$32.class
2009/05/27 16:35 926 DemoApp2$33$1$1.class
2009/05/27 16:35 4,104 DemoApp2$33$1.class
2009/05/27 16:35 2,849 DemoApp2$33.class
2009/05/27 16:35 926 DemoApp2$34$1$1.class
2009/05/27 16:35 4,234 DemoApp2$34$1.class
2009/05/27 16:35 2,849 DemoApp2$34.class
/* snip */
2009/05/27 16:35 614 DemoApp2$40.class
2009/05/27 16:35 2,344 DemoApp2$5.class
2009/05/27 16:35 1,551 DemoApp2$6.class
2009/05/27 16:35 1,604 DemoApp2$7.class
2009/05/27 16:35 1,809 DemoApp2$8.class
2009/05/27 16:35 2,022 DemoApp2$9.class
Ce sont toutes les classes qui ont été générés, quand je faisais une application simple, et utilisé de grandes quantités d'anonymous inner classes: chaque classe seront compilées dans un distinct class
le fichier.
Le "double croisillon d'initialisation", comme déjà mentionné, est un anonyme intérieur de la classe avec un exemple d'initialisation du bloc, ce qui signifie qu'une nouvelle classe est créée pour chaque "initialisation", tous dans le but de faire un objet unique.
Considérant que la Machine Virtuelle Java aurez besoin de lire toutes les classes lors de leur utilisation, qui peut conduire à un certain temps dans le bytecode de la vérification du processus et de ces. Pour ne pas mentionner l'augmentation de l'espace disque nécessaire pour stocker tous ces class
fichiers.
Il me semble que si il ya un peu de surcharge lors de l'utilisation de la double accolade de l'initialisation, donc c'est probablement pas une bonne idée d'aller trop trop loin avec elle. Mais comme Eddie a noté dans les commentaires, il n'est pas possible d'être absolument sûr de l'impact.
Juste pour la référence, double croisillon d'initialisation est la suivante:
List<String> list = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
Il ressemble à un "caché" de Java, mais c'est juste une réécriture de:
List<String> list = new ArrayList<String>() {
// Instance initialization block
{
add("Hello");
add("World!");
}
};
C'est en fait une instance de l'initialisation du bloc qui fait partie d'un anonyme intérieur de la classe.
Comme une note ajoutée, si Joshua Bloch de Collecte des Littéraux de proposition pour le Projet de Pièce de monnaie de passe, nous pouvons être en mesure de voir ce genre de syntaxe dans Java 7:
List<Integer> intList = [1, 2, 3, 4];
Set<String> strSet = {"Apple", "Banana", "Cactus"};
Map<String, Integer> truthMap = { "answer" : 42 };
Si ce changement rend à Java 7, il peut éliminer une bonne partie des cas d'utilisation pour la double accolade de l'initialisation.
Expérience
Voici l'expérience simple que j'ai testé-faire 1000 ArrayList
s avec les éléments "Hello"
et "World!"
ajoutée par l'intermédiaire de l' add
méthode, à l'aide de deux méthodes:
Méthode 1: Double Croisillon D'Initialisation
List<String> l = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
Méthode 2: Instancier un ArrayList
et add
List<String> l = new ArrayList<String>();
l.add("Hello");
l.add("World!");
J'ai créé un programme simple d'écrire un fichier source de Java pour effectuer 1000 initialisation à l'aide de deux méthodes:
Test 1:
class Test1 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
List<String> l0 = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
List<String> l1 = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
/* snip */
List<String> l999 = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
System.out.println(System.currentTimeMillis() - st);
}
}
Test 2:
class Test2 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
List<String> l0 = new ArrayList<String>();
l0.add("Hello");
l0.add("World!");
List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World!");
/* snip */
List<String> l999 = new ArrayList<String>();
l999.add("Hello");
l999.add("World!");
System.out.println(System.currentTimeMillis() - st);
}
}
Veuillez noter que le temps nécessaire à l'initialisation de la 1000 ArrayList
s et le 1000 anonyme classes internes s'étendant ArrayList
est vérifiée à l'aide de l' System.currentTimeMillis
, de sorte que la minuterie n'a pas une très haute résolution. Sur mon système Windows, la résolution est d'environ 15 à 16 millisecondes.
Les résultats pour les 10 pistes des deux épreuves sont les suivantes:
Test1 Times (ms) Test2 Times (ms)
---------------- ----------------
187 0
203 0
203 0
188 0
188 0
187 0
203 0
188 0
188 0
203 0
Comme on peut le voir, le double croisillon initialisation d'un notable du temps d'exécution d'environ 190 ms.
Pendant ce temps, l' ArrayList
initialisation de temps d'exécution est sorti à 0 ms. Bien sûr, la résolution du timer doit être pris en compte, mais il est susceptible d'être sous 15 ms secondes.
Donc, il semble y avoir une différence notable dans le temps d'exécution des deux méthodes. Il semble en effet qu'il existe une surcharge dans les deux méthodes d'initialisation.
Et oui, il y avait 1000 .class
fichiers générés par la compilation de l' Test1
double accolade de l'initialisation du programme de test.
Enfin, je vous remercie pour la lecture de ce très longue réponse!