java内部类文件名太长
我正在将某种语言的程序翻译为嵌套的 java 类。 在某些时候,嵌套的级别变得如此之深,以至于我得到:
compiling Test.javaTest.java:5179: error whilewriting : Test$2...$1.class (File name too long)
where ... is a long string 。
我使用的是 ext3 文件系统,因此文件名长度仅限于 256 个字符。 另外,我想暂时继续使用这种翻译方法(到内部类),因为我更感兴趣的是测试执行闭包转换的语言,这将解决问题。 有没有一种快速而肮脏的方法来绕过这个? (也许使用不同的文件系统或告诉 javac 生成不同的文件名?)
I'm translating programs of some language to nested java classes. At some point, the level of nesting becomes so deep that I get:
compiling Test.javaTest.java:5179: error while writing : Test$2...$1.class (File name too long)
where ... is a long string.
I'm using an ext3 filesystem, so i'm limited to 256 character long filenames. Also, I would like to keep on with this translation method (to inner classes) for the moment because I'm more interested in testing the language that in performing closure conversion, which would solve the problem. Is there a quick'n dirty way to bypass this? (using a different filesystem or telling javac to generate different filenames maybe?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
底线是,是的,这是可行的。 人们可以更改内部类的名称,因此它比
javac
分配的原始名称短。我正在搜索 Java 语言规范 和 < a href="http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html" rel="nofollow noreferrer">Java 虚拟机规范 查找它的位置讨论使用
$
字符来表示内部类,但无法找到对其的引用。 原因是,这并不重要。案例和要点:
在这里,我们有嵌套的内部类。 编译后,我们得到以下文件:
这是一个快速实验:
A.class
文件,将引用更改为A$B$C
并将其更改为 <代码>ABCDE。A$B$C.class
重命名为ABCDE.class
。ABCDE.class
,并将引用更改为ABCDE
。java A
,看是否运行。注意:
A$B$C
更改为ABCDE
的原因是标识符长度的变化似乎破坏了class< /code> 文件格式,并且会导致错误。 技术解释将在本文末尾。
结果? 有用。
原因就在
class
文件中。 这是原始A.class
的反汇编,仅显示相关部分:原来,内部类的名称只是常量池中的名称。
如果
A.class
常量池中的A$B$C
类的名称更改为ABCDE
,并且如果A$B$C
class'文件名和class
文件中的名称被更改,那么Java虚拟机将很乐意执行新命名的内部类。这是什么意思?
不需要使用
MyClass$1$1$1 ... $1
作为类名,但可以使用任何其他适合自己需要的名称,因此,可以在更短的文件中包含更多组合姓名。有人会怎么做呢? 我将把它作为练习留给读者。
关于使用
ABCDE
作为新类名的注意事项在这篇文章中,嵌套内部类的名称
A$B$C
是更改为ABCDE
以保持类名的长度相同,以防止抛出ClassFormatError
。 原因是常量池的CONSTANT_Utf8_info
结构有一个length
属性,表示字符串的长度。 当我在文本编辑器中编辑class
文件时,我无法更改长度。为了缩短常量池中的字符串,我认为必须更改
length
字段的值以反映字符串本身的长度。更新
是的,可以编辑
class
文件的常量池来缩短内部类的名称。我能够将 ABCDE 类更改为 Z 类。
以下是
A.class
的反汇编部分:可以看出,内部类现在由
Z
引用,而不是A$B$ C。
通过在
A.class
和A$B$C.class
文件中查找字符串A$B$C
来执行更改,并将其替换为Z
,并将字符串前的字符从值0x05
更改为0x01
,表示现在字符串的长度为1
而不是5
。通过这些更改,并将文件重命名为
Z.class
,程序运行起来就像什么也没发生过一样。所以,是的,也可以缩短内部类的名称。
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:
Here, we have nested inner classes. When compiled, we get the following files:
Here's a quick experiment:
A.class
file, and change the reference toA$B$C
and change it toABCDE
.A$B$C.class
toABCDE.class
.ABCDE.class
, and change the reference toABCDE
.java A
, see if it runs.Note: The reason the
A$B$C
was changed toABCDE
is because the change in the length of the identifier seems to mangle theclass
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 originalA.class
, and only the relevant parts: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 ofA.class
is changed toABCDE
, and if theA$B$C
class' file name and name in theclass
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 nameIn this post, the name of the nested inner class,
A$B$C
was changed toABCDE
to keep the length of the class name the same, in order to prevent aClassFormatError
from being thrown. The reason for this is that theCONSTANT_Utf8_info
structure of the constant pool has alength
property which denotes the length of the string. I wasn't able to change the length as I was editing theclass
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 toZ
class.Here's a portion of the disassembly of the
A.class
:As can be seen, the inner class is now referred to by
Z
, rather thanA$B$C
.The change was performed by looking for the string
A$B$C
in theA.class
andA$B$C.class
files, and replacing it withZ
, and changing the character before the string from the value0x05
to0x01
, denoting that the length of the string is now1
rather than5
.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.
一种可能的解决方案是在另一个操作系统上进行编译,然后使用混淆器,例如 yGuard 。 默认情况下,混淆器会将类名更改为最小名称(例如 A、B、C...),从而大大缩短类名(以及文件名)。
不过,根据您想要测试的内容,可能对您没有用。
1 possible solution is to compile on another operating system, then use an Obfuscater such as yGuard. An obfuscater by default will change the class names to a minimal name (eg A, B, C...) thereby shortening the class name (and therefore file name) considerably.
Might be no use to you depending on exactly what you want to test, though.
您可以从 java 内部编译 java,将输出发送到您自己实现的文件管理器。
使用 javax.tools.JavaCompiler, JavaFileManager 为您提供编译后的文件输出,您可以直接将其写入 jar 吗?
You can compile java from within java, sending the output to a file manager you implement yourself.
Use javax.tools.JavaCompiler, with a JavaFileManager that supplies you with the compiled output, which you could perhaps write directly to a jar?
文件系统比较,看起来 ResierFS 可能是唯一支持更长文件名的系统之一。 我会对这种方法保持警惕,因为所有工具(javac、java、ant、ls、rm、cp 等)可能会对文件名长度做出假设,因为大多数文件系统都是 255 并且您将被绑定到一个 FS (如果它消失了怎么办?)如果这纯粹是学术性的,请重新格式化(或使用虚拟化)。
您可能只需要重新评估您的算法以避免将类嵌套得太深。 可以使用多个文件吗? 我知道您不想这样做,但这可能是唯一选项
Comparison of File Systems, looks like ResierFS may be one of the only to support longer filenames. I'd be wary of this method as the all of the tools (javac, java, ant, ls, rm, cp, etc) might make assumptions about filename length since most filesystems are 255 and you'll be tied to one FS (what if it goes away?) If this is purely academic that reformat away (or use virtualization).
You may just need to reevalutate your algorithm to avoid nesting classes so deep. Can you use multiple files? I know you don't want to do it, but this may be the only option