Android中Java代码编译器的优化
假设我定义了这样一个字符串:
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”
或者这只会在应用程序的运行时发生
# 1 楼答案
不允许Java编译器对此进行优化
问题在于,对常量对象的方法调用没有定义为常量表达式;请参阅JLSsection 15.28,了解在常量表达式中可以执行的操作列表。因此,
s.charAt(0)
不是一个常量表达式,即使s
是一个常量表达式,“我们知道”它的值将始终是'T'
。因为它不是一个常量表达式,所以必须在运行时对其求值如果这样做的目的是防止字符串
"ToInterBe"
出现在类常量池中,那么您已经成功了。但这不会让一个好的逆向工程慢上几分钟(顺便说一句,这个表达式可能没有达到您预期的效果。第一个
+
子表达式是一个加法(不是字符串串联),因为两个操作数都不是字符串。这个加法的结果将是一个int
,所以整个表达式的计算结果将是"195InterBe"
。。。我想。)# 2 楼答案
Java编译器不会这样做,因为它会在技术上改变程序,因为所涉及的方法可能在运行时产生副作用。但是,即使它会预计算字符串,它仍然需要将原始字符串放入类文件中,因为它可以通过refection访问,可能与注释或其他原因有关
我想你要找的工具是ProGuard。如果在所有静态可判定代码被预计算之后,没有代码再引用字符串,那么这实际上可以删除字符串