假设我定义了这样的字符串:
private final static String s = "To Be or not to be, that is the question";
在其中一个(静态)方法中,我调用了一个接收字符串作为参数的方法:
methodThatReceivesString(s.charAt(0) + s.charAt(1) + "Inter" + s.charAt(3) + s.charAt(4))
(这个想法是methodThatReceivesString()
将被传递值"ToInterBe")
我的问题是:Java编译器是否会优化代码,使编译的二进制文件(.jar.dex)已经包含"ToInterBe"?
还是仅在应用程序的运行时发生?
Java 编译器不会这样做,因为它会在技术上更改程序,因为所涉及的方法可能会在运行时产生副作用。但是,即使它会预先计算字符串,它仍然需要将原始字符串放入类文件中,因为它可以通过引用访问,可能与注释或其他原因相关。
我认为您正在寻找的工具是ProGuard。如果在预先计算了所有静态可判定的代码之后,如果没有代码引用它,这实际上可以删除字符串。
不允许 Java 编译器对此进行优化。
问题在于,对常量对象的方法调用未定义为常量表达式;有关可以在常量表达式中执行的操作的列表,请参阅 JLS 第 15.28 节。 因此,即使s.charAt(0)
是一个常量表达式,s
也不是常量表达式,并且"我们知道"它的值将始终是'T'
的。 由于它不是常量表达式,因此必须在运行时对其进行计算。
如果您这样做的目的是防止字符串"ToInterBe"
出现在类常量池中,那么您已经成功了。 但这不会让一个好的逆向工程师减慢超过几分钟的速度。
(顺便说一下,该表达式可能不会达到您的预期。 第一个+
子表达式是加法(不是字符串连接),因为两个操作数都不是 String。 该加法的结果将是一个int
,因此整个表达式的计算结果将为"195InterBe"
...我想。