Java Records实际上是通过相似的类声明来节省内存还是它们更像语法糖? [英] Do Java Records actually save memory over a similar class declaration or are they more like syntactic sugar?
问题描述
我希望Java 14记录实际上比类似的数据类使用更少的内存.
它们还是使用相同的内存?
要添加到@lugiorgi >和我可以分析字节码的类似显着差异在于toString
,equals
和hashcode
的实现.
一方面,现有的类中覆盖了Object
类API的
public class City {
private final Integer id;
private final String name;
// all-args, toString, getters, equals, and hashcode
}
产生如下的字节码
public java.lang.String toString();
Code:
0: aload_0
1: getfield #7 // Field id:Ljava/lang/Integer;
4: aload_0
5: getfield #13 // Field name:Ljava/lang/String;
8: invokedynamic #17, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/Integer;Ljava/lang/String;)Ljava/lang/String;
13: areturn
public boolean equals(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: if_acmpne 7
5: iconst_1
6: ireturn
7: aload_1
8: ifnull 22
11: aload_0
12: invokevirtual #21 // Method java/lang/Object.getClass:()Ljava/lang/Class;
15: aload_1
16: invokevirtual #21 // Method java/lang/Object.getClass:()Ljava/lang/Class;
19: if_acmpeq 24
22: iconst_0
23: ireturn
24: aload_1
25: checkcast #8 // class edu/forty/bits/records/equals/City
28: astore_2
29: aload_0
30: getfield #7 // Field id:Ljava/lang/Integer;
33: aload_2
34: getfield #7 // Field id:Ljava/lang/Integer;
37: invokevirtual #25 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
40: ifne 45
43: iconst_0
44: ireturn
45: aload_0
46: getfield #13 // Field name:Ljava/lang/String;
49: aload_2
50: getfield #13 // Field name:Ljava/lang/String;
53: invokevirtual #31 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ireturn
public int hashCode();
Code:
0: aload_0
1: getfield #7 // Field id:Ljava/lang/Integer;
4: invokevirtual #34 // Method java/lang/Integer.hashCode:()I
7: istore_1
8: bipush 31
10: iload_1
11: imul
12: aload_0
13: getfield #13 // Field name:Ljava/lang/String;
16: invokevirtual #38 // Method java/lang/String.hashCode:()I
19: iadd
20: istore_1
21: iload_1
22: ireturn
另一方面,相同的记录表示形式
record CityRecord(Integer id, String name) {}
产生的字节码少
public java.lang.String toString();
Code:
0: aload_0
1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(Ledu/forty/bits/records/equals/CityRecord;)Ljava/lang/String;
6: areturn
public final int hashCode();
Code:
0: aload_0
1: invokedynamic #23, 0 // InvokeDynamic #0:hashCode:(Ledu/forty/bits/records/equals/CityRecord;)I
6: ireturn
public final boolean equals(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: invokedynamic #27, 0 // InvokeDynamic #0:equals:(Ledu/forty/bits/records/equals/CityRecord;Ljava/lang/Object;)Z
7: ireturn
注意:就生成的访问器和构造函数字节代码而言,我可以观察到,它们对于表示形式都是相似的,因此也从此处的数据中排除.
I’m hoping that Java 14 records actually use less memory than a similar data class.
Do they or is the memory using the same?
To add to the basic analysis performed by @lugiorgi and a similar noticeable difference that I could come up with analyzing the byte code, is in the implementation of toString
, equals
and hashcode
.
On one hand, the existing class with overridden Object
class APIs looking like
public class City {
private final Integer id;
private final String name;
// all-args, toString, getters, equals, and hashcode
}
produces the byte code as following
public java.lang.String toString();
Code:
0: aload_0
1: getfield #7 // Field id:Ljava/lang/Integer;
4: aload_0
5: getfield #13 // Field name:Ljava/lang/String;
8: invokedynamic #17, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/Integer;Ljava/lang/String;)Ljava/lang/String;
13: areturn
public boolean equals(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: if_acmpne 7
5: iconst_1
6: ireturn
7: aload_1
8: ifnull 22
11: aload_0
12: invokevirtual #21 // Method java/lang/Object.getClass:()Ljava/lang/Class;
15: aload_1
16: invokevirtual #21 // Method java/lang/Object.getClass:()Ljava/lang/Class;
19: if_acmpeq 24
22: iconst_0
23: ireturn
24: aload_1
25: checkcast #8 // class edu/forty/bits/records/equals/City
28: astore_2
29: aload_0
30: getfield #7 // Field id:Ljava/lang/Integer;
33: aload_2
34: getfield #7 // Field id:Ljava/lang/Integer;
37: invokevirtual #25 // Method java/lang/Integer.equals:(Ljava/lang/Object;)Z
40: ifne 45
43: iconst_0
44: ireturn
45: aload_0
46: getfield #13 // Field name:Ljava/lang/String;
49: aload_2
50: getfield #13 // Field name:Ljava/lang/String;
53: invokevirtual #31 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ireturn
public int hashCode();
Code:
0: aload_0
1: getfield #7 // Field id:Ljava/lang/Integer;
4: invokevirtual #34 // Method java/lang/Integer.hashCode:()I
7: istore_1
8: bipush 31
10: iload_1
11: imul
12: aload_0
13: getfield #13 // Field name:Ljava/lang/String;
16: invokevirtual #38 // Method java/lang/String.hashCode:()I
19: iadd
20: istore_1
21: iload_1
22: ireturn
On the other hand the record representation for the same
record CityRecord(Integer id, String name) {}
produces the bytecode as less as
public java.lang.String toString();
Code:
0: aload_0
1: invokedynamic #19, 0 // InvokeDynamic #0:toString:(Ledu/forty/bits/records/equals/CityRecord;)Ljava/lang/String;
6: areturn
public final int hashCode();
Code:
0: aload_0
1: invokedynamic #23, 0 // InvokeDynamic #0:hashCode:(Ledu/forty/bits/records/equals/CityRecord;)I
6: ireturn
public final boolean equals(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: invokedynamic #27, 0 // InvokeDynamic #0:equals:(Ledu/forty/bits/records/equals/CityRecord;Ljava/lang/Object;)Z
7: ireturn
Note: To what I could observe on the accessors and constructor byte code generated, they are alike for both the representation and hence excluded from the data here as well.
这篇关于Java Records实际上是通过相似的类声明来节省内存还是它们更像语法糖?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!