Reputation: 453
OpenJDK 1.8.0_191
I compiled and decompiled a piece of code below using Fernflower.
public class Decompile {
public static void main(String[] args) {
final int VAL = 20;
System.out.println(VAL);
}
}
The output is:
public class Decompile {
public static void main(String[] args) {
boolean VAL = true;
System.out.println(20);
}
}
I'm confused, how did VAL
become a boolean?
UPDATE:
In Intellij IDEA decompiled code looks like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Decompile {
public Decompile() {
}
public static void main(String[] args) {
int VAL = true;
System.out.println(20);
}
}
Upvotes: 1
Views: 2318
Reputation: 39451
The underlying issue is that Java bytecode has no notion of booleans, byte, chars, or shorts (except in type signatures). All local variables with those types are instead compiled to ints. Boolean true and false are compiled to 1
and 0
respectively.
What this means is that the decompiler has to guess whether a given local variable was supposed to be a boolean or an integer type. In this case, the value 20
is stored in the variable, which will never be stored in a variable of boolean type in Java code, so it should be easy for the decompiler to guess that it is an integer type based on the context. But it appears that Fernflower's boolean guesser is not that sophisticated.
For what it's worth, this is an inherently hard problem. Especially when you consider that non-Java bytecode doesn't have to follow the same patterns that Java does. It is perfectly valid for bytecode to use the same variable in both integer and boolean contexts. The Krakatau decompiler has a pretty sophisticated inference step for guessing whether variables should be booleans or not, but it will still get things wrong in situations like this.
Upvotes: 1
Reputation: 7325
It works like that as compiler
do some optimization
during the generation of the byte code
. As VAL = 20; is final and not changing, so it can put the 20
in place of VAL
without impacting
the functionality in the second statement. Now the decompiler
has only byte code
and when it goes to read the Byte code it found 20
as inline in the second line
. Byte code generated by the code as below:
0: bipush 20
2: istore_1
3: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 20
8: invokevirtual #26 // Method java/io/PrintStream.println:(I)V
Upvotes: 0
Reputation: 21134
The bytecode is
L0
LINENUMBER 5 L0
BIPUSH 20
ISTORE 1
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
BIPUSH 20
INVOKEVIRTUAL java/io/PrintStream.println (I)V
As you can see the BIPUSH
pushes 20
onto the stack, then ISTORE
takes the value and store it into the local variable.
It's a Fernflower
problem.
For your interest the output for bytecode version 55
is
int VAL = true;
System.out.println(20);
You can see decompilers can be wrong :)
Upvotes: 2