Java源代码中的“机械生成”的源文件

10

我在查看Java源代码时发现了一些不寻常的文件,大多与java.nio包中的ByteBuffer有关,这些文件的源代码非常混乱,并标有“此文件是机械生成的:请勿编辑!”。

这些文件还包含大量的空白行(甚至在javadoc中间也有!?),可能是为了防止行号发生变化。我也看到过一些Java反编译器,比如procyon-decompiler,它们有一个选项可以保留行号,但我怀疑这并不是原因,因为在最后一个括号之前添加空白行并没有改变任何内容。

以下是其中几个文件(我找不到它们的在线链接,也没有将它们粘贴到Pastebin上,因为我不想侵犯任何版权,但你可以在JDK安装文件夹的根目录下的src.zip文件夹中找到它们):

  • java.nio.ByteBuffer
  • java.nio.DirectByteBufferR
  • java.nio.Bits
  • java.nio.BufferOverflowException

我很想知道:

  • 哪个工具生成了这些文件?
  • 为什么这个工具保持行号不变?是为了更容易地进行调试(堆栈跟踪)吗?
  • 为什么会使用一个工具来生成它们,而其他所有类都是由人编写的?
  • 为什么该工具会在括号内随机放置空白行,在最后一个大括号之前或者甚至在javadoc中间也有?

我怀疑你不会得到答案,因为那段代码似乎已经存在很长时间了-看看这篇2006年的博客文章,当时Java仍然是Sun公司所有。 - APC
2
这些文件似乎是由某个预处理器从模板文件在构建过程中生成的:http://hg.openjdk.java.net/jdk9/dev/jdk/file/3b298c230549/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template - Andreas Fester
据我所知,C预处理器由于在#if或#else之后跳过而插入空行。在这里,我的想法很清楚:如果某个编译器在输出中标记了错误,您将在原始输入中找到它的原因。 - laune
1个回答

8
我可能无法回答所有问题,但有一些背景知识:
http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/make/java/nio/Makefile的 Makefile 中,它们通过一些预处理程序从同一个模板文件生成不同的Java源文件:
...
$(BUF_GEN)/CharBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH)
    $(prep-target)
    @$(RM) $@.temp
    TYPE=char SRC=$< DST=$@.temp $(GEN_BUFFER_CMD)
    $(MV) $@.temp $@
$(BUF_GEN)/ShortBuffer.java: $(X_BUF_TEMPLATE) $(GEN_BUFFER_SH)
    $(prep-target)
    @$(RM) $@.temp
    TYPE=short SRC=$< DST=$@.temp $(GEN_BUFFER_CMD)
    $(MV) $@.temp $@
...

$(X_BUF_TEMPLATE) 指的是 X-Buffer.java.template,这是用于创建像 CharBufferShortBuffer 等类型缓冲区的源代码。

注意:URL 可能会在将来更改。同时对于 Java 8,由于其已修改了构建系统,我尚未找到相应的 Makefiles,敬请谅解。

生成这些文件的工具是什么?

GEN_BUFFER_SH / GEN_BUFFER_CMD 最终指的是 genBuffer.sh,因此创建这些文件的脚本是 http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/make/java/nio/genBuffer.sh

为什么要使用工具来生成它们,而所有其他类都是由人编写的?

我没有针对这个特定案例的权威答案,但通常您会使用代码生成工具:

  • 如果您需要创建许多类/方法,这些类/方法仅在某些细节上有所不同,但这些细节足够微妙,以至于您无法使用已建立的机制(例如泛型或方法参数)(可能是此处的情况,因为缓冲区是为无法与泛型一起使用的基本类型生成的)
  • 如果您需要从更简单的表示中创建复杂的算法(例如从语法生成解析器)。

为什么该工具保留相同的行号?是为了使调试(堆栈跟踪)更容易吗?

我猜测:是的,它是为了保留堆栈跟踪中的行号,以便它们与模板文件匹配。其他类似的工具,如 C 预处理器也是类似的。


1
是的,这些类是为原始类型(short、char等)多样化而设计的。这是一个罕见的情况。有一些调查正在进行中,以便在未来的Java版本中将原始类型包装起来,这样你就可以使用Buffer<int>了。 - Joop Eggen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接