int[]是元素类型为原始类型的数组。原始类型(不包括String)中肯定不含有对对象实例的引用。如果把所有对象实例看做一幅有向图的节点,把它们之间的引用关系看作边,那么int[]肯定是叶节点(有入边没有出边)或者是孤立的节点(入边和出边都没有)。元素为对象类型的数组中则可能包含对别的对象实例的节点。
[quote="bohemia"]第二个问题:
StringBuffer比String效率高.是因为生成对象的个数不一样.
比如:
[code]"aaa"+"bbb"[/code]
会生成三个String对象.
但
[code]sb.append("aaa").append("bbb")[/code]
只有2个String生成,所以效率会高.
个人见解.[/quote]
确实跟创建对象的个数有关系,不过不应该只看String对象的个数。
首先用常量写的"aaa"和"bbb"在Java源文件被编译为Java class文件后会出现在常量池中。这些字符串会随着它们所在的class文件的类被加载而被创建为String实例,保存在运行时的字符串池里。再说
[code]"aaa"+"bbb"[/code]
不会在这个表达式执行时“生成”3个String对象,而是因为连接运算的两个参数都是字面量,而在Java源码编译为Java class文件时被合并为一个"aaabbb"常量。
其次,从Java 5开始String的连接运算a+b会变为
[code]StringBuilder sb = new StringBuilder();
sb.append(a);
sb.append(b);
String result = sb.toString();[/code]
其实至少创建了一个StringBuilder对象,一个char[](StringBuilder的成员),一个String对象(结果)和又一个char[](String的成员)。
Java 5以前String的连接运算用的是StringBuffer来做的,跟上面的讲解类似。
现在的Java编译器已经比较聪明,看到同一个表达式内连续出现连接运算时,会使用同一个StringBuilder来处理:
[code]a + b + c + d[/code]
会变为
[code]StringBuilder sb = new StringBuilder();
sb.append(a);
sb.append(b);
sb.append(c);
sb.append(d);
String result = sb.toString();[/code]
要举例说明String的连接运算比StringBuilder/StringBuffer低效,可以在循环里做连接运算:
[code]String a = "a";
for (int i = 0; i < 10; i++) {
a = a + "b";
}[/code]
这个等价于
[code]String a = "a";
StringBuilder sb = null;
for (int i = 0; i < 10; i++) {
sb = new StringBuilder();
sb.append(a);
sb.append("b");
}
a = sb.toString();[/code]
与直接使用StringBuilder的例子相比
[code]String a = "a";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append("b");
}
a = sb.toString();[/code]
很明显用String的加号的方式创建了更多的StringBuilder对象。但创建StringBuilder对象本身开销并不大,开销大的是其成员的char[]的创建和扩大。直接使用StringBuilder时,连接运算到char[]装不下的时候,会重新分配一个更大的char[],把老数组的内容复制过去。用String的加号时,每次循环都要创建一个新的char[],复制的次数比直接用StringBuilder多很多,因而速度慢。