以下内容摘自《java编程思想》第十三章。

1. 不可变 String

String 对象是不可变对象,String 类中每一个看起来会修改 String 值的方法,实际上都是创建了一个全新的 String 对象,以包含修改后字符串的内容,而最初的 String 对象丝毫未动。看如下的代码:

import static java.lang.System.*;

public class Immutable{
public static String upcase(String s){
return s.toUpperCase();
} /*
结果为:howdy HOWDY howdy
*/
public static void main(String[] args){
String q = "howdy";
out.println(q);
String qq = upcase(q);
out.println(qq);
out.println(q);
}
}

2. 重载 "+" 与StringBuilder

String 是不可变的,这会带来一定的效率问题。首先看一下这段代码:

public class Concatenation{
String mango = "mango";
String s = "abc"+mango+"def"+47;
System.out.println(s);
// 结果 abcmangodef47
}

可以想象一下,这段代码可能是这样工作的:String 可能有一个 append 方法,它会生成一个新的 String 类,以包含 “abc” 与 mango 连接后的字符串。然后,该对象再与 “def” 相连,生成另一个 String 对象,以此类推。

这种工作方式当然行得通,但是为了生成最终的 String,此方式会产生大量的需要垃圾回收的中间对象,这样运行性能实在是糟糕。那么上面的代码是否真的是这样工作的呢?书中利用了 JDK 内置的工具 javap -c Concatenation 反编译上面的代码,发现,在上面的 "+" 操作中,编译器自作主张的使用了 StringBuilder 类,因为它更高效。每一次 "+" 操作,都调用了 StringBuilder.append 方法,最后使用 toString 方法返回字符串。

上面对于 "+" 操作符工作流程的解释说明编译器会自动地优化性能,但是,它也不能做到完美,比如在循环中,经过循环一次, + 操作符就会产生一个 StringBuilder,所以,在循环中如果要对字符串进行操作,建议使用 StringBuilder 对象。

StringBuilder 是 java SE5 引入的,在这之前 java 用的是 StringBuffer,后者是线程安全的,因此开销也会更大些,所以,在 java SE5/6 中,字符串操作应该会更快一点。

3. 无意识的递归

java 中每个类从根本上都是继承自 Object,标准容器类自然也不例外。因此容器类有 toString 方法,并覆写了该方法。例如 ArrayList.toString() 会遍历容器中所有的对象,并调用对象的 toString 方法。如果我们想要在 toString 方法中打印出对象的内存地址,也许会考虑使用 this 关键字。

import java.util.ArrayList;
import java.util.List; public class InfiniteRecursion {
public String toString(){
return "InfiiniteRecursion address"+this;
} public static void main(String[] args){
List<InfiniteRecursion> v = new ArrayList<InfiniteRecursion>();
for(int i=0;i<10;i++){
v.add(new InfiniteRecursion());
}
System.out.println(v);
}
}

但是上面的代码运行会出现 java.lang.StackOverflowError,这是为什么呢?原因出现在 toString 方法中,编译器看到字符串 "InfiiniteRecursion address" 后面跟着一个 "+" ,而再后面的对象不是 String,于是编译器试着将 this 转换为 String 对象,怎么转换呢?这是通过调用 toString 方法,于是就发生了递归调用。如果在上面的例子中想要打印出对象的内存地址,应该调用 super.toString 方法。

以上是我对书中的一些总结,有什么好的看书建议欢迎提出来一起交流分享。

最新文章

  1. php止刷新页面重复提交
  2. JAVA作业)01
  3. myeclipse中disable maven nature
  4. Win10/UWP新特性系列—使用打印机
  5. Dinic问题
  6. [ios][opengles]GLKit如何搭一个app的框架
  7. Go语言的类型转化
  8. PHP命名空间(Namespace)
  9. Cache和Buffer的区别
  10. [转]主键冲突的话就更新否则插入 (ON DUPLICATE KEY UPDATE )
  11. FireMonkey消息机制
  12. leetcode回文子串拆分-最小拆分次数
  13. devstack安装使用openstack常见问题与解决的方法
  14. cmd中控制某个命令执行多少次
  15. 谈谈Java中的代理模式
  16. python的异步IO模块
  17. ZOJ 1109 Language of FatMouse 【Trie树】
  18. Maven常见jar包依赖
  19. sudo操作
  20. 0. 资料官网【从零开始学Spring Boot】

热门文章

  1. 数据结构中有关顺序表的问题:为何判断插入位置是否合法时if语句中用length+1,而移动元素的for语句中只用length?
  2. P1866 编号
  3. JS 原型与原型链终极详解(二)
  4. vue的自定义指令。directive
  5. web自动化 -- js操作(滑动屏幕、修改页面)
  6. 台账建立和sqlite数据库的数据导入和导入问题
  7. 使用 Azure Blob Stoage 实现一个静态文件服务器
  8. 枚举-称硬币POJ1013
  9. hashlib加密算法
  10. Python os.unlink() 方法