如何使用 Java 程序修改已编译.jar中的类文件中的字符串?



我正在尝试编写客户端构建器,这意味着我有一个客户端.jar我需要更改位于jar/client/Main.classString。字符串IP_SERVER =(我要更改的值)是唯一应该编辑的内容。也许有一种方法可以用java构建和编译的类替换该类,但是idk。客户端构建器是一个带有 Gui 的 Java 程序(但 gui 不是问题),用于创建原始客户端的副本.jar只是具有更改的值(例如 Ip 字符串)。我需要这个而不是参数或其他导致客户端的东西.jar当他们不知道服务器 IP 时应该能够提供给其他人。所以像开始参数之类的东西不是那么有用:/

我已经尝试将文件复制到 Jar 中,但这不是我真正需要的。那么我如何使用Java程序来做到这一点呢?

虽然动机值得怀疑,但有一些方法可以修改字节码。jar文件是一个美化的zip文件,你必须解压缩。然后,您必须编辑类文件。如果您不更改内部字符串(或其他结构)的大小,则可以通过简单的查找/替换来摆脱。

如果要进行更广泛的修改,可以使用库来修改类字节码。最终的方法是:

  1. 解开罐子的拉链
  2. 反编译类文件
  3. 对 Java 代码进行文本修改
  4. 重新编译修改后的Java代码(可能要带上整个jdk)
  5. 替换类文件
  6. 拉链到新罐子
  7. 更换旧罐

基本上,答案是:那么不要让该字符串"仅代码"。

相反,使其可从外部进行配置,例如通过检查 - 是否有一个 JVM 属性告诉您不同的 IP 地址 - 是否有一个环境变量告诉您不同的 IP 地址

不要浪费时间通过以某种方式操作编译的类文件来寻找肮脏的解决方法。相反:编写可以在需要时轻松配置的代码,而无需接触源代码(或者更糟的是,编译的工件)。

并给出您的评论:JAR 文件可以包含资源,例如:属性文件。是的,您可以在 JAR文件中有一个文本属性文件,该文件在运行时被读取。所以是的,理论上你可以将这些信息"烘焙"到你的 JAR。但同样,这将是相当糟糕的做法。JAR 是一个二进制文件,您真的希望两个客户使用同一版本的工具吗?将使用两个不同的JAR文件?!再次:这是配置信息,配置应该存在于 JAR之外

最后:您的要求相互矛盾。要么你想生成一个 jar 文件...或不。如果要交付单个 JAR 文件,那么除了获取"其他"JAR 文件之外别无他法,请添加您的 main 方法。然后,该字符串来自何处真的无关紧要。但是你不能指望分发另一个JAR文件的内容......如果不合并它,当您还打算只分发您创建的一些额外 JAR 时。

要在GhostCat的答案和Phil博士的答案之间添加某种组合,您可以拥有一个包含服务器IP的文本文件,该服务器IP在类初始化时仅由Java类读取。文本文件将是一个资源(即它捆绑在你的JAR文件中)。

public class Main {
public static final String IP_SERVER;
static {
try (InputStream is = Main.class.getResourceAsStream("path/to/resource/file.txt")) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
IP_SERVER = reader.readLine();
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}

上面的代码假定您的文本文件将在第一行包含 IP 信息(并忽略任何其他行)。您可能希望使用显式字符集(用于对文本文件进行编码的字符集)创建InputStreamReader,而不是依赖于默认字符集(有关更多详细信息,请参阅InputStreamReader的文档)。

要修改文本文件,您可以使用与菲尔博士的答案中描述的方法类似的方法。这里唯一的区别是你正在修改一个文本文件,这意味着你不需要重新编译任何源文件。

您可以使用属性文件代替文本文件(即*.properties)。然后,您将使用Properties类来访问它(再次作为资源)。

将该文件与原始包一起包含在项目中。编译时,将首先检测到您的类而不是该客户端.jar。为此,在编译路径中,类文件应位于第一个而不是该客户端.jar。

最新更新