Android中的Java代码编译器优化

时间:2022-08-11 02:19:56

Assuming I have defined a string like this:

假设我已经定义了这样的字符串:

private final static String s = "To Be or not to be, that is the question";

And in one of the (static) methods I call a method that receives a String as a parameter:

在其中一个(静态)方法中,我调用一个接收String作为参数的方法:

methodThatReceivesString(s.charAt(0) + s.charAt(1) + "Inter" + s.charAt(3) + s.charAt(4))

(the idea is that methodThatReceivesString() will be passed the value "ToInterBe")

(想法是methodThatReceivesString()将传递值“ToInterBe”)

My question is: Will the Java compiler optimize the code such that the compiled binary file (.jar .dex) already contain "ToInterBe"?

我的问题是:Java编译器是否会优化代码,使得编译的二进制文件(.jar .dex)已经包含“ToInterBe”?

Or will this occur only at the application's run time?

或者这只会在应用程序的运行时发生?

2 个解决方案

#1


1  

A Java compiler is not permitted to optimize this.

不允许Java编译器对其进行优化。

The issue is that method calls on constant objects are not defined to be constant expressions; see JLS section 15.28 for a list of the things that you can do in a constant expression. Thus, s.charAt(0) is not a constant expression even though s is a constant expression, and "we know" that its value will always be 'T'. Since it is not a constant expression, it has to be evaluated at runtime.

问题是对常量对象的方法调用未定义为常量表达式;请参阅JLS第15.28节,了解可以在常量表达式中执行的操作的列表。因此,即使s是常量表达式,s.charAt(0)也不是常量表达式,并且“我们知道”它的值将始终为“T”。由于它不是常量表达式,因此必须在运行时进行评估。

If your aim in doing this is to prevent the string "ToInterBe" from appearing in the classes constant pool, then you've succeeded. But that's not going to slow down a good reverse engineer by more than a couple of minutes.

如果你这样做的目的是防止字符串“ToInterBe”出现在类常量池中,那么你就成功了。但这不会让一个好的逆向工程师减速超过几分钟。


(By the way, that expression probably doesn't do what you expect. The first + subexpression is an addition (not a string concatenation) because neither of the operands is a String. The result of that addition will be an int, so the entire expression will evaluate to "195InterBe" ... I think.)

(顺便说一下,那个表达式可能不会达到预期的效果。第一个+子表达式是一个加法(不是字符串连接),因为这两个操作数都不是一个String。这个加法的结果将是一个int,所以整个表达式将评估为“195InterBe”......我想。)

#2


2  

The Java compiler won't do this as it would technically change the program, since the methods involved could have side effects at runtime. But even if it would precompute the string it would still need to put the original string into the class file since it could be accessed by refection, could be relevant for a annotation or for other reasons.

Java编译器不会这样做,因为它在技术上会改变程序,因为所涉及的方法在运行时可能会产生副作用。但即使它预先计算字符串,它仍然需要将原始字符串放入类文件,因为它可以通过反射访问,可能与注释或其他原因相关。

I think the tool you are looking for is ProGuard. This can among many other things actually remove the string if no code refers to it anymore after all statically decidable code was precomputed.

我认为您正在寻找的工具是ProGuard。在所有静态可判定代码被预先计算之后,如果没有代码再引用它,这可以在许多其他事情中实际删除字符串。

#1


1  

A Java compiler is not permitted to optimize this.

不允许Java编译器对其进行优化。

The issue is that method calls on constant objects are not defined to be constant expressions; see JLS section 15.28 for a list of the things that you can do in a constant expression. Thus, s.charAt(0) is not a constant expression even though s is a constant expression, and "we know" that its value will always be 'T'. Since it is not a constant expression, it has to be evaluated at runtime.

问题是对常量对象的方法调用未定义为常量表达式;请参阅JLS第15.28节,了解可以在常量表达式中执行的操作的列表。因此,即使s是常量表达式,s.charAt(0)也不是常量表达式,并且“我们知道”它的值将始终为“T”。由于它不是常量表达式,因此必须在运行时进行评估。

If your aim in doing this is to prevent the string "ToInterBe" from appearing in the classes constant pool, then you've succeeded. But that's not going to slow down a good reverse engineer by more than a couple of minutes.

如果你这样做的目的是防止字符串“ToInterBe”出现在类常量池中,那么你就成功了。但这不会让一个好的逆向工程师减速超过几分钟。


(By the way, that expression probably doesn't do what you expect. The first + subexpression is an addition (not a string concatenation) because neither of the operands is a String. The result of that addition will be an int, so the entire expression will evaluate to "195InterBe" ... I think.)

(顺便说一下,那个表达式可能不会达到预期的效果。第一个+子表达式是一个加法(不是字符串连接),因为这两个操作数都不是一个String。这个加法的结果将是一个int,所以整个表达式将评估为“195InterBe”......我想。)

#2


2  

The Java compiler won't do this as it would technically change the program, since the methods involved could have side effects at runtime. But even if it would precompute the string it would still need to put the original string into the class file since it could be accessed by refection, could be relevant for a annotation or for other reasons.

Java编译器不会这样做,因为它在技术上会改变程序,因为所涉及的方法在运行时可能会产生副作用。但即使它预先计算字符串,它仍然需要将原始字符串放入类文件,因为它可以通过反射访问,可能与注释或其他原因相关。

I think the tool you are looking for is ProGuard. This can among many other things actually remove the string if no code refers to it anymore after all statically decidable code was precomputed.

我认为您正在寻找的工具是ProGuard。在所有静态可判定代码被预先计算之后,如果没有代码再引用它,这可以在许多其他事情中实际删除字符串。