使用较新的编译器,我发现自己试图编写更容易阅读的代码,但如果我希望在幕后进行的优化实际上并没有完成,那么可能需要更多的内存。以下面的代码为例,非常简单的情况
while (scanner.hasNextLine() && !result)
{
String line = scanner.nextLine();
result = line.indexOf(searchString) >= 0;
}假设(使用Eclipse Juno,Java 7)生成的字节码与
while (scanner.hasNextLine() && !result)
{
result = scanner.nextLine().indexOf(searchString) >= 0;
}前者虽然只有2行代码,但减少了第二行的长度,使它看起来更美观。但是它是否也会导致创建一个不安全的字符串对象呢?希望不是..。
发布于 2012-11-09 22:03:54
您无法转义正在创建的String。将其赋给局部变量在这里是无关紧要的,实际上在字节码级别,这一事实甚至不会被注意到:在该级别,无论有没有显式变量,对结果的引用都必须放在堆栈上,以便传递到链中的下一个方法调用中。
创建不必要的String实例的想法可能源于另一种语言的本能,例如C:赋值String s = ...只将引用复制到唯一的string实例。这是因为所有Java对象都驻留在堆中,所以您总是需要显式地复制一个对象才能真正涉及到另一个实例。例如,如果您编写了String line = new String(scanner.nextLine()),那么确实会创建一个不必要的String实例。
总而言之,您的代码的任何版本都不涉及优化,因此仅根据样式偏好进行选择。
发布于 2012-11-09 22:05:11
一些一般原则:
<代码>F211
在您的特定情况下:变量声明在优化方面不会改变任何东西,因为在这两种情况下,字符串都是由nextLine()初始化并放在堆栈上的,将其赋给一个变量(该变量在字节码中消失,除非它是实例变量,因为它的用处仅限于您的眼睛)不会改变任何东西。
发布于 2012-11-09 22:21:08
为什么不问一下Java Class File反汇编程序--每个JDK中都包含的javap程序?
具有以下源代码:
public class Foo {
static void m1(Scanner scanner, String searchString, boolean result) {
while (scanner.hasNextLine() && !result) {
String line = scanner.nextLine();
result = line.indexOf(searchString) >= 0;
}
}
static void m2(Scanner scanner, String searchString, boolean result) {
while (scanner.hasNextLine() && !result) {
result = scanner.nextLine().indexOf(searchString) >= 0;
}
}
}运行反汇编程序时:
javap -c Foo.class您将获得以下字节码:
static void m1(java.util.Scanner, java.lang.String, boolean);
Code:
0: goto 22
3: aload_0
4: invokevirtual #33 // Method java/util/Scanner.nextLine:()Ljava/lang/String;
7: astore_3
8: aload_3
9: aload_1
10: invokevirtual #39 // Method java/lang/String.indexOf:(Ljava/lang/String;)I
13: iflt 20
16: iconst_1
17: goto 21
20: iconst_0
21: istore_2
22: aload_0
23: invokevirtual #45 // Method java/util/Scanner.hasNextLine:()Z
26: ifeq 33
29: iload_2
30: ifeq 3
33: return
static void m2(java.util.Scanner, java.lang.String, boolean);
Code:
0: goto 20
3: aload_0
4: invokevirtual #33 // Method java/util/Scanner.nextLine:()Ljava/lang/String;
7: aload_1
8: invokevirtual #39 // Method java/lang/String.indexOf:(Ljava/lang/String;)I
11: iflt 18
14: iconst_1
15: goto 19
18: iconst_0
19: istore_2
20: aload_0
21: invokevirtual #45 // Method java/util/Scanner.hasNextLine:()Z
24: ifeq 31
27: iload_2
28: ifeq 3
31: return如果您比较这两个方法的字节码,您会发现唯一的区别是m1包含这两条额外的指令:
7: astore_3
8: aload_3这只是将对堆栈顶部对象的引用存储到一个局部变量中,没有其他内容。
编辑:
反汇编程序还可以显示方法的局部变量的数量:
javap -l Foo.class以下哪项输出:
static void m1(java.util.Scanner, java.lang.String, boolean);
LocalVariableTable:
Start Length Slot Name Signature
0 34 0 scanner Ljava/util/Scanner;
0 34 1 searchString Ljava/lang/String;
0 34 2 result Z
8 14 3 line Ljava/lang/String;
static void m2(java.util.Scanner, java.lang.String, boolean);
LocalVariableTable:
Start Length Slot Name Signature
0 32 0 scanner Ljava/util/Scanner;
0 32 1 searchString Ljava/lang/String;
0 32 2 result Z
}这基本上证实了上面看到的唯一区别- m1方法只分配了一个局部变量- String line。它不会创建更多的对象,它只会创建一个对一个对象的引用,这个对象是以的方式分配的。
https://stackoverflow.com/questions/13309493
复制相似问题