- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我目前正在学习用 Java 编程,我对标题中列出的一元增量器有疑问,但我在其他地方找不到。我刚开始玩弄它们,并不能完全决定在 for 循环中使用哪一个,因为前缀(先递增然后求值)和后缀(先求值然后递增)之间的行为差异似乎不适用于 for陈述。所以我都试过了,都成功了。这让我很担心,因为我想按照它们应有的方式使用它们。
所以我的问题是,它们在递增 for 循环时是否真的可以互换,或者是否存在一些模糊的问题,我会在使用一个反之亦然的过程中遇到一些模糊的问题?
我决定给它们计时(如下),++x
肯定比 x++
运行得更快,但我不知道为什么。任何人都可以对此进行扩展吗?
谢谢!
public class PlusPlus
{
public static void main(String[] args)
{
long startTime1, startTime2, endTime1, endTime2;
final double COUNT = 100000000;
//times x++ incrementing
startTime1 = System.currentTimeMillis();
for(int x = 0; x < COUNT; x++);
endTime1 = System.currentTimeMillis();
System.out.println("x++ loop: " + (endTime1 - startTime1) + " milliseconds");
//times ++x incrementing
startTime2 = System.currentTimeMillis();
for(int x = 0; x < COUNT; ++x);
endTime2 = System.currentTimeMillis();
System.out.println("++x loop: " + (endTime2 - startTime2) + " milliseconds");
}
}
最佳答案
就了解性能如何运作而言,您的测试不会有太大收获。由于 JVM 的性质,编写性能测试非常困难,以至于整个框架都是为基准测试而编写的。
要真正了解区别是什么,您应该使用 javap
反编译代码。
我编译了这个类:
public class MyClass {
public static void main(String[] args) {
for (int i = 0; i < 20; i++)
System.out.println(i);
}
}
然后运行 javap -c MyClass
为 main
获取这个:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: bipush 20
5: if_icmpge 21
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
15: iinc 1, 1
18: goto 2
21: return
}
然后我又做了一次,但这次使用了预增量:
for (int i = 0; i < 20; ++i)
我为 javap
得到了这个:
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: bipush 20
5: if_icmpge 21
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
15: iinc 1, 1
18: goto 2
21: return
}
注意到什么了吗?特别是它们完全一样?
这是因为 Java 优化了有关预加载和后加载值的额外指令。它认识到它生成的用于将变量加载到寄存器中的指令(javap
输出中的 iload_#
)是多余的和不必要的,并对其进行了优化。
在编程中,有一个术语叫做过早优化。在这里您可以优化您实际上不需要优化的内容,因为它可能会导致性能问题。你真正做的只是让你的代码更复杂。大多数“优秀”的程序员(如果存在的话)都会避免这种情况,而是专注于编写可维护的代码。如果可维护代码表现不佳,然后对其进行优化。我记得在 SO 上阅读过关于 3 个不同级别的程序员(初级、中级、高级)以及如何(粗略地)判断你属于哪个类别的回复。我看看能不能找到它。
编辑: 我的回答的快速解释:javac
将您的 .java 文件编译成字节码。字节码存储在 .class 文件中。字节码一步一步地告诉 JVM 如何完成某事。例如,iinc 1, 1
告诉它获取变量 1
(在本例中为 i
)并将其递增 1。iload_1
告诉它获取变量 1
并加载它以便可以使用它,通常是在操作或方法调用中。例如,这个:
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
表示“获取 System.out
并加载它,然后加载变量 #1 (i
),现在调用方法 #3。”当我们调用该方法时,首先加载的东西 (System.out
) 是我们的“目标”,意思是对那个人调用该方法。加载的所有其他内容都作为参数传递。在这种情况下,这意味着 i
。所以这三行代表 System.out.println(i)
行。字节码只是告诉 Java 实际做该做什么。
在反编译代码中没有iload_1
的预增量和后增量的事实意味着 Java 优化了它,因为它意识到它实际上不会被使用。在这两种情况下,它只是在没有 iload
的情况下执行 iinc
,这与该线程中的大多数其他答案完全相反。
关于java - Java 中的一元增量符++x 和x++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19016728/
我是一名优秀的程序员,十分优秀!