
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 不这样的话下面的每一行代码都要写成 this.value[c++],对应的 opcode 要多一次 get_field 操作 |
2 chendy 2022-06-14 12:23:29 +08:00 压榨性能 可以省下后续用 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 直接找 count 是在堆上找 你在栈上声明一遍下面用的地方就是从栈上直接拿 |
7 mxalbert1996 2022-06-14 13:40:11 +08:00 via Android |
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 final char[] value 定义后在堆上会有固定的 value 指向(无法修改引用地址) 下次再进来的时候可以直接用 |
11 maokabc 2022-06-14 14:00:43 +08:00 via Android 用 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 你们要笑死我了, 就是个代码风格的问题, 来换个 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; } |