链接方法与在 Java 中创建临时变量是否会影响内存分配?
Does chaining methods vs making temporary variables in Java impact memory allocation?
在Java中,如果我在一个对象上执行多个方法,我可以将它们链接起来,或者我可以创建一个临时变量,就像这样
链接
System.out.println( str.substring(0,4).substring(0,2));
温度变量
String tmp = str.substring(0,4);
tmp = tmp.substring(0,2);
System.out.println(tmp);
显然,在此示例中差异可以忽略不计,但当您对数千个 strings/some 其他对象执行此操作时可能会产生影响。
我的问题是,就不进行额外的对象分配或填充堆(从而使 GC 更快地被调用)而言,这些更多 "efficient" 之一吗?
我试图在几个字符串的循环中比较两者的字节码,但它看起来很相似,最后几行没有。我不理解所有的字节码调用,所以我不确定这些是否与分配新对象有关。
Compiled from "TestNoTmp.java"
public class TestNoTmp {
public TestNoTmp();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2 // class java/lang/String
4: dup
5: iconst_0
6: ldc #3 // String These
8: aastore
9: dup
10: iconst_1
11: ldc #4 // String Are__
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String Some_
18: aastore
19: dup
20: iconst_3
21: ldc #6 // String Strings
23: aastore
24: astore_1
25: aload_1
26: astore_2
27: aload_2
28: arraylength
29: istore_3
30: iconst_0
31: istore 4
33: iload 4
35: iload_3
36: if_icmpge 69
39: aload_2
40: iload 4
42: aaload
43: astore 5
45: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
48: aload 5
50: iconst_0
51: iconst_4
52: invokevirtual #8 // Method java/lang/String.substring:(II)Ljava/lang/String;
55: iconst_0
56: iconst_2
57: invokevirtual #8 // Method java/lang/String.substring:(II)Ljava/lang/String;
60: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
63: iinc 4, 1
66: goto 33
69: return
}
public class TestTmp {
public TestTmp();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2 // class java/lang/String
4: dup
5: iconst_0
6: ldc #3 // String These
8: aastore
9: dup
10: iconst_1
11: ldc #4 // String Are__
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String Some_
18: aastore
19: dup
20: iconst_3
21: ldc #6 // String Strings
23: aastore
24: astore_1
25: aload_1
26: astore_2
27: aload_2
28: arraylength
29: istore_3
30: iconst_0
31: istore 4
33: iload 4
35: iload_3
36: if_icmpge 77
39: aload_2
40: iload 4
42: aaload
43: astore 5
45: aload 5
47: iconst_0
48: iconst_4
49: invokevirtual #7 // Method java/lang/String.substring:(II)Ljava/lang/String;
52: astore 6
54: aload 6
56: iconst_0
57: iconst_2
58: invokevirtual #7 // Method java/lang/String.substring:(II)Ljava/lang/String;
61: astore 6
63: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
66: aload 6
68: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
71: iinc 4, 1
74: goto 33
77: return
}
在您的示例中,您使用的是不可变的字符串。在您的代码中:
str.substring(0,4).substring(0,2)
第一次调用 substring 必须生成一个新的 String 对象,因为 str 不能被修改。类似地,第二次调用该新 String 对象上的 substring 将创建另一个新 String 对象。
字节码的不同只是编译器调用方法顺序的结果。在 TestTmp 情况下,所有字符串操作都发生在调用 PrintStream 之前。对于 TestNoTmp,String 调用发生在 PrintStream 调用中,当您查看代码时,这是非常合乎逻辑的。
为了回答您的问题,这对对象分配和 GC 影响没有影响。
在Java中,如果我在一个对象上执行多个方法,我可以将它们链接起来,或者我可以创建一个临时变量,就像这样
链接
System.out.println( str.substring(0,4).substring(0,2));
温度变量
String tmp = str.substring(0,4);
tmp = tmp.substring(0,2);
System.out.println(tmp);
显然,在此示例中差异可以忽略不计,但当您对数千个 strings/some 其他对象执行此操作时可能会产生影响。
我的问题是,就不进行额外的对象分配或填充堆(从而使 GC 更快地被调用)而言,这些更多 "efficient" 之一吗?
我试图在几个字符串的循环中比较两者的字节码,但它看起来很相似,最后几行没有。我不理解所有的字节码调用,所以我不确定这些是否与分配新对象有关。
Compiled from "TestNoTmp.java"
public class TestNoTmp {
public TestNoTmp();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2 // class java/lang/String
4: dup
5: iconst_0
6: ldc #3 // String These
8: aastore
9: dup
10: iconst_1
11: ldc #4 // String Are__
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String Some_
18: aastore
19: dup
20: iconst_3
21: ldc #6 // String Strings
23: aastore
24: astore_1
25: aload_1
26: astore_2
27: aload_2
28: arraylength
29: istore_3
30: iconst_0
31: istore 4
33: iload 4
35: iload_3
36: if_icmpge 69
39: aload_2
40: iload 4
42: aaload
43: astore 5
45: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
48: aload 5
50: iconst_0
51: iconst_4
52: invokevirtual #8 // Method java/lang/String.substring:(II)Ljava/lang/String;
55: iconst_0
56: iconst_2
57: invokevirtual #8 // Method java/lang/String.substring:(II)Ljava/lang/String;
60: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
63: iinc 4, 1
66: goto 33
69: return
}
public class TestTmp {
public TestTmp();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_4
1: anewarray #2 // class java/lang/String
4: dup
5: iconst_0
6: ldc #3 // String These
8: aastore
9: dup
10: iconst_1
11: ldc #4 // String Are__
13: aastore
14: dup
15: iconst_2
16: ldc #5 // String Some_
18: aastore
19: dup
20: iconst_3
21: ldc #6 // String Strings
23: aastore
24: astore_1
25: aload_1
26: astore_2
27: aload_2
28: arraylength
29: istore_3
30: iconst_0
31: istore 4
33: iload 4
35: iload_3
36: if_icmpge 77
39: aload_2
40: iload 4
42: aaload
43: astore 5
45: aload 5
47: iconst_0
48: iconst_4
49: invokevirtual #7 // Method java/lang/String.substring:(II)Ljava/lang/String;
52: astore 6
54: aload 6
56: iconst_0
57: iconst_2
58: invokevirtual #7 // Method java/lang/String.substring:(II)Ljava/lang/String;
61: astore 6
63: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
66: aload 6
68: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
71: iinc 4, 1
74: goto 33
77: return
}
在您的示例中,您使用的是不可变的字符串。在您的代码中:
str.substring(0,4).substring(0,2)
第一次调用 substring 必须生成一个新的 String 对象,因为 str 不能被修改。类似地,第二次调用该新 String 对象上的 substring 将创建另一个新 String 对象。
字节码的不同只是编译器调用方法顺序的结果。在 TestTmp 情况下,所有字符串操作都发生在调用 PrintStream 之前。对于 TestNoTmp,String 调用发生在 PrintStream 调用中,当您查看代码时,这是非常合乎逻辑的。
为了回答您的问题,这对对象分配和 GC 影响没有影响。