Descompilación el archivo .class de los siguientes fines de cada bucle produce resultados interesantes.
Fuente - Main.java:
public class Main {
public static void main(String[] args) {
String[] names = new String[3];
int var3 = 3;
for (String name : names) {
System.out.println(name);
}
}
}
Resultado - Main.class:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Main {
public Main() {
}
public static void main(String[] args) {
String[] names = new String[3];
int var3 = true;
String[] var3 = names;
int var4 = names.length;
for(int var5 = 0; var5 < var4; ++var5) {
String name = var3[var5];
System.out.println(name);
}
}
}
El archivo se decompiled con IntelliJ IDEA.
- Por lo que fue
true
asignado a la no utilizadaint
? - ¿Por qué el
var3
redeclarada variable?
¿Es esto un error en nombre de la decompilador?
En el nivel de código de bytes, no hay declaraciones formales de las variables locales, al menos no de la manera conocida a partir del código fuente. Un método tiene una declaración del número máximo de variables locales existentes, al mismo tiempo o “slots” para reservar para ellos. Una variable local entra en la vida cuando se asigna un valor real a la misma (por el índice de “ranura”) y existe al menos en la última lectura de ese valor.
Con estas operaciones, es imposible reconocer cuando extremos de alcance de una variable o si dos variables con alcances disjuntos comparten una ranura (en comparación con múltiples asignaciones a la misma variable). Bueno, si tienen tipos completamente incompatibles, sus asignaciones dar una pista.
Para ayudar a la depuración, existe un atributo código opcional que proporciona consejos acerca de las variables locales declaradas y su alcance, pero esto no es necesario que sea completa y no afectará a la forma en la JVM ejecutará el código de bytes. Pero aquí, parece que el atributo estaba presente y ha sido utilizado por el decompilador.
Cuando puedo compilar el código de ejemplo, con javac -g
, consigo
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=7, args_size=1
0: iconst_3
1: anewarray #2 // class java/lang/String
4: astore_1
5: iconst_3
6: istore_2
7: aload_1
8: astore_3
9: aload_3
10: arraylength
11: istore 4
13: iconst_0
14: istore 5
16: iload 5
18: iload 4
20: if_icmpge 43
23: aload_3
24: iload 5
26: aaload
27: astore 6
29: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
32: aload 6
34: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
37: iinc 5, 1
40: goto 16
43: return
LocalVariableTable:
Start Length Slot Name Signature
29 8 6 name Ljava/lang/String;
0 44 0 args [Ljava/lang/String;
5 39 1 names [Ljava/lang/String;
7 37 2 var3 I
Las variables declaradas args
(el parámetro método), names
, var3
, y name
fueron asignados a los índices variables 0
, 1
, 2
, y 6
, en ese orden.
Hay variables sintéticas sin una declaración,
- en el índice
3
para contener una referencia a la matriz el bucle se iterar sobre - en el índice
4
para mantener la longitud de la matriz - en el índice
5
para mantener laint
variable de índice que logrará incrementado en el bucle
Parece, la decompilador tiene una simple estrategia para hacer frente a las variables que no aparecen en el LocalVariableTable
. Se genera un nombre que consiste en el prefijo "var"
y el índice dentro del marco de pila. Por lo tanto, genera los nombres var3
, var4
y var5
para las variables de síntesis descrito anteriormente y no le importaba que se produjo un enfrentamiento nombre entre estos nombres generados y los nombres declarados explícitamente, es decir var3
.
Ahora, no está claro por qué el decompilador genera una asignación de true
una int
variable, pero es muy útil saber que no hay dedicados boolean
instrucciones de procesamiento en el código de bytes de Java, sino más bien boolean
los valores se procesan del mismo modo que int
los valores. Se requiere información meta apropiada, como declaraciones de variables, para entender que los valores deben conseguir interpretado como boolean
valores. Tal vez, el nombre choque descrita anteriormente dirigió el decompilador confundir los tipos de variables después, tener en cuenta, finalmente, el tipo de valor de no ser una int
y caer de nuevo a tratarlo como boolean
a continuación. Pero eso es sólo una conjetura; podría haber un fallo del todo ajeno también.