Bottom line is, yes, it's doable. One can change the name of an inner class, so it is shorter than the original name assigned by javac
.
I was searching through The Java Language Specification and The Java Virtual Machine Specification to find where it talks about using the $
character to denote an inner class, and was not able to find a reference to it. The reason is, it doesn't really matter.
Case and point:
class A {
class B {
class C {}
}
A() {
new B().new C();
}
public static void main(String[] s){
new A();
}
}
Here, we have nested inner classes. When compiled, we get the following files:
A.class
A$B.class
A$B$C.class
Here's a quick experiment:
- Open the
A.class
file, and change the reference to A$B$C
and change it to ABCDE
.
- Rename the
A$B$C.class
to ABCDE.class
.
- Open the
ABCDE.class
, and change the reference to ABCDE
.
- Run
java A
, see if it runs.
Note: The reason the A$B$C
was changed to ABCDE
is because the change in the length of the identifier seems to mangle the class
file format, and will cause an error. Technical explanation will be at the end of this post.
Result? It works.
The reason is in the class
file. Here's a disassembly of the original A.class
, and only the relevant parts:
Compiled from "A.java"
class A extends java.lang.Object
SourceFile: "A.java"
InnerClass:
#10= #3 of #7; //B=class A$B of class A
#22= #2 of #3; //C=class A$B$C of class A$B
// ... snip ... //
const #2 = class #21; // A$B$C
// ... snip ... //
const #21 = Asciz A$B$C;
// ... snip ...//
Turns out, the name of the inner classes are just names in the constant pool.
If the name for the A$B$C
class in the constant pool of A.class
is changed to ABCDE
, and if the A$B$C
class' file name and name in the class
file is changed, then the Java virtual machine will happy execute with the newly named inner class.
What does this mean?
One does not need to use the MyClass$1$1$1 ... $1
for the class name, but anything else that would suite one's need, therefore, it would be possible to have more combinations in a shorter file name.
How would someone go and do this? That I'll leave as an exercise to the reader.
Note on the use of ABCDE
as the new class name
In this post, the name of the nested inner class, A$B$C
was changed to ABCDE
to keep the length of the class name the same, in order to prevent a ClassFormatError
from being thrown. The reason for this is that the CONSTANT_Utf8_info
structure of the constant pool has a length
property which denotes the length of the string. I wasn't able to change the length as I was editing the class
file in a text editor.
In order to shorten the string in the constant pool, I would presume that one would have to alter the value of the length
field to reflect the length of the string itself.
Update
Yes, it is possible to edit the class
file's constant pool to shorten the name of the inner class.
I was able to change the ABCDE
class to Z
class.
Here's a portion of the disassembly of the A.class
:
Compiled from "A.java"
class A extends java.lang.Object
SourceFile: "A.java"
InnerClass:
#10= #3 of #7; //B=class A$B of class A
#22= #2 of #3; //C=class Z of class A$B
// ... snip ...//
const #2 = class #21; // Z
// ... snip ...//
const #21 = Asciz Z;
// ... snip ...//
As can be seen, the inner class is now referred to by Z
, rather than A$B$C
.
The change was performed by looking for the string A$B$C
in the A.class
and A$B$C.class
files, and replacing it with Z
, and changing the character before the string from the value 0x05
to 0x01
, denoting that the length of the string is now 1
rather than 5
.
With those changes, along with renaming the file to Z.class
, the program ran as if nothing ever happened.
So, yes, it is possible to shorten the name of the inner class as well.