考虑以下设置:
// debugger class
public class Debug
{
// setting
public final static boolean DEBUG = false;
void print_checked( String s )
{
if( DEBUG )
System.out.print( s );
}
void print_unchecked( String s )
{
System.out.print( s );
}
}
// worker class
public class Algorithm
{
Debug debugger;
public void heavyWeightAlgorithmImplementation()
{
// method 1
debugger.print_checked( "This method 1" );
// method 2
if( debugger.DEBUG )
debugger.print_unchecked( "Or this method 2" );
}
}
我已阅读here,Java中的final boolean
很可能会被优化出来。但是在我的设置中,if条件在另一个类中,并且当前在print_checked()
中实现。 Java是否也优化了函数调用(方法1),还是必须重写方法2中的所有内容?
编辑#1:再次添加静态
答案 0 :(得分:2)
我已经通过jdk1.7编译了上面的例子,并在jd-gui中打开了* .class文件。
例子:
class Debug
{
// setting
public static final boolean DEBUG = false;
void print_checked( String s )
{
if( DEBUG )
System.out.print( s );
}
void print_unchecked( String s )
{
System.out.print( s );
}
}
public class Main
{
public static void main(String[] argc)
{
Debug debugger = new Debug();
debugger.print_checked(" This method 1");
if (debugger.DEBUG)
debugger.print_unchecked( "Or this method 2");
}
}
JD-GUI:
// Debug.class
import java.io.PrintStream;
class Debug
{
public static final boolean DEBUG = false;
void print_checked(String paramString) {
}
void print_unchecked(String paramString) {
System.out.print(paramString);
}
}
// Main.class
public class Main
{
public static void main(String[] paramArrayOfString)
{
Debug localDebug = new Debug();
localDebug.print_checked(" This method 1");
}
}
你可以看到方法" print_checked"保留在Main.class代码中,但" print_unchecked"被删除了。我不确定,但我认为空方法" print_checked"也可能被Oracle JVM忽略。
答案 1 :(得分:0)
Java随着时间的推移而变化,并且变得更加复杂。所以拿一点盐就可以了。
在javac编译期间,如果编译器可以证明永远不会访问某段代码,那么它将被删除。
在运行时,现代Oracle JVM倾向于以解释模式开始运行字节代码,在这种情况下,它将进行检查,直到JVM认为代码“热”足以进行优化。在这个时候,Hotspot开始了,并且它正朝着这样的观点前进,即假设其他方面的字段将被认为是最终的。此时它将尝试相当积极地预测分支和内联代码。
但是,如果我的记忆回忆起来,运行时不能将非静态字段的最终关键词视为优化的最终关键词,因为有些方法可以在运行时更改这些字段的值。宠物讨厌JVM内部人员。
因此,出于您的选择,我会推荐方法1,因为它减少了需要复制块的位置数。但是,如果可能的话,我会将DEBUG字段设为静态,这样可以更可靠地删除if语句。
答案 2 :(得分:0)
在你的样本中,第一种方法是恕我直言。但是如果你需要一些关于调试的连接操作,那么第二个变量是可取的。
以下是一个例子:
if( debugger.DEBUG )
debugger.print_unchecked( "Or this method 2" + oldValue + "//" + newValue);
在这种情况下,编译器可以避免不必要的字符串连接和调用toString()方法。
这是我的测试:
public class DebuggerTest {
static final int ITER_NUM = 5000000;
public static class Debug
{
// setting
public final static boolean DEBUG = false;
private final List<String> collector = new ArrayList<String>(ITER_NUM);
void print_checked( String s )
{
if( DEBUG )
collector.add(s);
}
void print_unchecked( String s )
{
collector.add(s);
}
}
public static void main(String[] args) {
Debug debug = new Debug();
long time = System.currentTimeMillis();
for (int i = 0; i < ITER_NUM; i++) {
debug.print_checked("Debug message " + i);
}
System.out.println("First: " + (System.currentTimeMillis() - time));
debug = new Debug();
time = System.currentTimeMillis();
for (int i = 0; i < ITER_NUM; i++) {
if (Debug.DEBUG)
debug.print_unchecked("Debug message " + i);
}
System.out.println("Second: " + (System.currentTimeMillis() - time));
}
}
结果:
First: 339
Second: 2