I try to find the reason for a strange effect with .class files. It seems like for interfaces the names of variables passed into a function are not listed, but in implementation classes they are. I stumbled across this effect while de-compiling some of my own class files with JD-Gui.
I checked this with these two files:
Person.java
public interface Person {
public abstract void setName( String name );
public void setAge( int age );
}
PersonImpl.java
public class PersonImpl implements Person {
@Override
public void setName(String name) {
System.out.println("This is my name: " + name);
}
@Override
public void setAge(int age) {
System.out.println("This is my age: " + age);
}
}
JD-Gui returns this when decompiling:
Using javap -verbose x.class
I get similar results: the printed method signatures differ from interface to implementing class. One misses variable names like I specified them in my source, the other has them.
I tried to answer my question studying the Java Virtual Machine Specification but have to admit I failed finding my way through this document.
Is there a reason why this was designed that way ?
Edit:
Because of all the good answers I received I added some lines to my interface and implementation class in order to back the statements from the answer:s
Person.java
default public void yawn(int count) {
for (int i = 1; i <= count; i++)
System.out.println("uaaaaah ....");
}
JD-Gui is able to determine the name of the parameter:
JavaP is able to list it in the LocalVariableTable:
When I add an abstract method to the implementing class and make the whole class abstract (which I need to because it contains one abstract method) ...
PersonImpl.java
public abstract void setPlanet( String planet );
... then JD-Gui fails to decompile this class file. But fortunately javap still is able to dump the file. All methods that are not abstract keep their LocalVariableTable. And the abstract method has a signature but neither Code, nor Lines or even a LocalVariableTable (this was expected)
There is actually nothing within the class file itself that stores the name of the method parameter. If you look at section 4.3.3, you'll see the following definitions for
MethodDescriptor
:You can see this if you print out the bytecode for
Person.class
andPersonImpl.class
usingjavap -c
:You can see that the signature for the method says nothing about the name of the parameter; only its type.
What I suspect is happening is that JD-Gui is probably using some sort of heuristic based on JavaBeans conventions to derive the name of the parameter. Since the name of the method issetName
, it assumes that the name of the parameter isname
. Try changing the name of the parameter to something other thanname
and see what JD-Gui prints out.Debug information, like local variables, will show up if you compile using
-g
or-g:vars
; it does not show up by default. These show up in theLocalVariableTable
attribute. From section 4.7.13:Notice the optional part; this is why you don't see it by default. Now if you look at section 4.7.3 for the
Code
attribute:Since interface method-definitions are effectively abstract (unless you use default methods), you won't see a
LocalVariableTable
entry for them. I used the latest version of JD-Gui againstPersonImpl.class
that was not compiled with-g
, and found that it did not displayname
andage
. Instead it displayedparamString
andparamInt
just like you saw forPerson.class
. However, if you do compile it with the-g
flag, you will seename
andage
.