public AbstractStringBuilder append(String str) {
// 如果 str 为 null ,则在字符数组中添加 'n''u''l''l'
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}```
字符串参数为 null 时调用了 appendNull(); 方法
```java
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
// 这里将内部字符数组赋值给局部变量
final char[] value = this.value;
// 然后通过局部变量向内部数组添加字符
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
// 这里的 count 也是先赋值给局部变量,为什么不直接使用 count 呢?
count = c;
return this;
}```
我的疑问是 appendNull 方法中为什么要创建一个 final char[] value 这样一个局部变量来操作内部数组而不是直接使用 this.value ?这么做的用意是什么?
1
GuuJiang 2022-06-14 12:22:12 +08:00 via iPhone 1
不这样的话下面的每一行代码都要写成 this.value[c++],对应的 opcode 要多一次 get_field 操作
|
2
chendy 2022-06-14 12:23:29 +08:00 1
压榨性能
可以省下后续用 this 找 value 的开销 |
3
zhao1014 OP 还是有点不理解,写成这样的话也不用 this 调用了啊
```java private AbstractStringBuilder appendNull() { ensureCapacityInternal(c + 4); value[count++] = 'n'; value[count++] = 'u'; value[count++] = 'l'; value[count++] = 'l'; return this; } |
4
zhao1014 OP 使用实例变量调用跟使用局部变量调用的区别在哪呢?不太明白
|
5
zhao1014 OP 除了多线程的问题以外想不到区别了:(
|
6
TWorldIsNButThis 2022-06-14 13:30:10 +08:00 via iPhone 1
直接找 count 是在堆上找
你在栈上声明一遍下面用的地方就是从栈上直接拿 |
7
mxalbert1996 2022-06-14 13:40:11 +08:00 via Android 1
|
8
skinny 2022-06-14 13:42:04 +08:00
可以少打几十个字符而已,JVM 不至于这么蠢这么简单的代码都不会优化。
|
9
kiroter 2022-06-14 13:43:04 +08:00
习惯问题,查看引用的时候会少很多。get 什么编译器应该会优化的
|
10
liyunyang 2022-06-14 13:53:28 +08:00 1
final char[] value 定义后在堆上会有固定的 value 指向(无法修改引用地址)
下次再进来的时候可以直接用 |
11
maokabc 2022-06-14 14:00:43 +08:00 via Android 2
用 javap 看字节码就可以发现区别,就是 gefield 指令比 aload 、iload 这类指令开销大,更别说 getfield 之前还有一条 aload_0 指令先得到 this 。
|
13
huyangq 2022-06-14 17:09:46 +08:00
11 楼正解
|
15
aguesuka 2022-06-15 11:20:30 +08:00 1
你们要笑死我了, 就是个代码风格的问题, 来换个 jdk, 就不一样了.
AbstractStringBuilder 完全不 care 性能, 因为它不是 public 的, 两个实现 StringBuilder/StringBuffer 上面有 IntrinsicCandidate 的注解. The @IntrinsicCandidate annotation is specific to the HotSpot Virtual Machine. private AbstractStringBuilder appendNull() { ensureCapacityInternal(count + 4); int count = this.count; byte[] val = this.value; if (isLatin1()) { val[count++] = 'n'; val[count++] = 'u'; val[count++] = 'l'; val[count++] = 'l'; } else { count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } this.count = count; return this; } |