更改已编译类中的字符串常量

我需要在已部署的Java程序中更改字符串常量,即编译的-文件中的值。它可以重新启动,但不容易重新编译(尽管如果这个问题没有答案,这是一个不方便的选择)。这可能吗?.class

更新:我刚刚用十六进制编辑器查看了文件,看起来我可以很容易地更改那里的字符串。这是否有效,即不会使文件的某种签名无效?旧字符串和新字符串都是字母数字,如果需要,长度可以相同。

更新2:我修复了它。因为我需要更改的特定类非常小,并且在项目的新版本中没有更改,所以我可以编译它并从那里获取新类。出于教育目的,仍然对不涉及编译的答案感兴趣。


答案 1

如果你有这个类的来源,那么我的方法是:

  • 获取 JAR 文件
  • 获取单个类的源代码
  • 在类路径上使用 JAR 编译源代码(这样,您就不必编译其他任何内容;JAR 已经包含二进制文件并没有什么坏处)。您可以使用最新的Java版本;只需使用 和 降级编译器即可。-source-target
  • 将 JAR 中的类文件替换为新的 using 或 Ant 任务jar u

Ant 任务示例:

        <jar destfile="${jar}"
            compress="true" update="true" duplicate="preserve" index="true"
            manifest="tmp/META-INF/MANIFEST.MF"
        >
            <fileset dir="build/classes">
                <filter />
            </fileset>
            <zipfileset src="${origJar}">
                <exclude name="META-INF/*"/>
            </zipfileset>
        </jar>

在这里,我还更新了清单。首先放置新类,然后添加原始 JAR 中的所有文件。 将确保新代码不会被覆盖。duplicate="preserve"

如果代码未签名,则当新字符串与旧字符串具有完全相同的长度时,您也可以尝试替换字节。Java 对代码执行一些检查,但.class文件中没有校验和

您必须保留长度;否则类装入器会感到困惑。


答案 2

在常量池中修改字符串(技术上是 Utf8 项)时,唯一需要的额外数据是长度字段(数据前面的 2 个字节大字节序)。没有其他需要修改的校验和或偏移。

有两个警告:

  • 该字符串可以在其他地方使用。例如,“Code”用于方法代码属性,因此更改它会破坏文件。
  • 该字符串以修改后的 Utf8 格式存储。因此,基本平面外的空字节和 Unicode 字符的编码方式不同。长度字段是字节数,而不是字符数,限制为 65535。

如果您打算经常这样做,最好获得一个类文件编辑器工具,但是十六进制编辑器对于快速更改很有用。


推荐