final String str1 = "length: 10";
final String str2 = "length: "+pig.length();我现在可以确定str1==str2为false;
我知道String池的特性
但想知道连接操作符“+”的定义,他是否是new了一个新的字符串?还是什么?
望达人指点!
final String str2 = "length: "+pig.length();我现在可以确定str1==str2为false;
我知道String池的特性
但想知道连接操作符“+”的定义,他是否是new了一个新的字符串?还是什么?
望达人指点!
解决方案 »
- JAVA的问题,eclipse
- JAVA
- byte转换的问题
- jreechart的折线图中,如果线太靠上,点上显示的数值被盖住了,显示不出来,哪位高手帮忙解决一下
- 电子邮件收发系统的界面设计中遇到的困惑(类似outlook)
- tom2005(快乐着) ( ) 大侠请来接分!!!!!!!!!1(真的好谢谢你!)
- java类包的一个基础问题
- 求助 HashMap put方法 报错NullPointerException
- 请问各位大虾:在JAVA中如何调用Windows的API?
- 想找JAVA方面的工作,大家支持一下啊!(散分拉!)
- 简单问题:str.replaceAll("[\n\r]", "<br>");
- 关于snmp4j中接收trap问题
eg: "length1"+"length2"+ 操作符 是把 new 一个新的字符串即length2
然后把 length1和length2连接起来,放入一个新的空间里,str2指向他个人理解,有错改正,,哈哈学习!!!!!
就是“+”new了一个新的String对象,然后将操作数两个String常量拷贝到new 的String中
对不对啊》?
我也不知道!
呵呵
-》
final String str2 = "length: "+str1.length();
String str1 = "haha";
String str2 = "ha"+"ha";
System.out.println(str1==str2);
返回true;
说明 + 操作符并没有生成新的对象,问题在str1.length()这里大家都说说吧!
final String str2 = "length: " + i.toString();的简写形式。
String a = "haha";
String c = "ha";
String b = c+"ha";
System.out.println(a);
System.out.println(b);
System.out.print(a == b);
这样打出来也是false
我的理解是 + 不会产生新对象。所以" "+" "的时候不会有问题。但是 " " + T 的时候,如果T是基本类型(这里是str.length的返回值),就会先自动装箱为一个对象,然后调用这个对象的toString方法。这个时候就有新的对象产生了,所以就会出现楼主遇到的情况。
final String str2 = "length: "+pig.length(); 这里的关键是pig.length();
它调用length()方法之后,返回的是int类型的,在调用toString()方法,这时候应该创建一个新的对象,在堆里创建,所以你得到的结果为false,如下代码String str2 = "length: "+new Integer(pig.length()).toString();
String str2 = "length: "+10;
10是int类型的啊,但是这样的话
str1==str2为true所以我觉得 初始化必须是字面常量才可以,否则都会在堆中new一个新的对象
TIJ中明确说明,string的相加会被编译器优化为使用StringBuilder。
JAVA池中存储的STRING是在编译时就产生的!
所以"HAHA"=="HA"+"HA"(编译时能获得这"两"个STRING,并认为它们是一致的),但是C+"HA",在编译时是不会识别的,只有在运行时才能知道C+"HA"到底是什么,所以C+"HA"得到的STRING,已经不是在JAVA池中的STRING,C+"HA"!="HAHA"也就正常了
1
2StringBuffer 是线程安全的
3StringBuilder 不保证线程安全(在1.5中引入的),一般情况下比StringBuffer快
4
5一个String对象的长度是固定的,不能改变它的内容,或者是附加新的字符至String对象中。您也许会使用+来串联字符串以达到附加新字符或字符串的目的,但+会产生一个新的String实例。如果程序对这种附加字符串的需求很频繁,并不建议使用+来进行字符串的串联。在面向对象程序设计中,最好是能重复运用已生成的对象,对象的生成需要内存空间与时间,不断地产生String实例是一个没有效率的行为。
6J2SE 5.0提供java.lang.StringBuilder类,使用这个类所产生的对象默认会有16个字符的长度,您也可以自行指定初始长度。如果附加的字符超出可容纳的长度,则StringBuilder对象会自动增加长度以容纳被附加的字符。如果有频繁作字符串附加的需求,使用StringBuilder会让程序的效率大大提高。通过下面的简单测试程序就可以知道效能差距有多大。
7ü 范例6.5 AppendStringTest.java
8public class AppendStringTest {
9 public static void main(String[] args) {
10 String text = "";
11
12 long beginTime = System.currentTimeMillis();
13 for(int i = 0; i < 10000; i++)
14 text = text + i;
15 long endTime = System.currentTimeMillis();
16 System.out.println("执行时间:" + (endTime - beginTime));
17
18 StringBuilder builder = new StringBuilder("");
19 beginTime = System.currentTimeMillis();
20 for(int i = 0; i < 10000; i++)
21 builder.append(String.valueOf(i));
22 endTime = System.currentTimeMillis();
23 System.out.println("执行时间:" + (endTime - beginTime));
24 }
25}
26
27在范例6.5中首先使用+来串联字符串,使用System.currentTimeMillis()取得for循环执行前、后的系统时间,这样就可以得知for循环执行了多久。以下是我的计算机上的测试数据:
28
29执行时间:4641
30执行时间:16
31可以看到执行的时间差距很大,这说明了使用+串联字符串所带来的负担。如果有经常作附加字符串的需求,建议使用StringBuilder。事实上就范例6.5来说,第二个for循环执行时间还可以更短,因为append()也可以接受基本数据类型,所以不必特地使用String.valueOf()方法从int取得String。改为以下的方式,执行时间可以大幅缩短:
32for(int i = 0; i < 10000; i++)
33 builder.append(i);
34使用StringBuilder最后若要输出字符串结果,可以用toString()方法。可以使用length()方法得知目前对象中的字符长度,而capacity()可返回该对象目前可容纳的字符容量。另外,StringBuilder还有像insert()方法可以将字符插入指定的位置,如果该位置以后有字符,则将所有的字符往后移;deleteChar()方法可以删除指定位置的字符,而reserve()方法可以反转字符串。详细的使用可以查询java.lang.StringBuilder的API文件说明。
35StringBuilder是J2SE 5.0才新增的类,在J2SE 5.0之前的版本若有相同的需求,则使用java.lang.StringBuffer。事实上,StringBuilder被设计为与StringBuffer具有相同的操作接口。在单机非多线程(Multithread)的情况下使用StringBuilder会有较好的效率,因为StringBuilder没有处理同步(Synchronized)问题。StringBuffer则会处理同步问题,如果StringBuilder会在多线程下被操作,则要改用StringBuffer,让对象自行管理同步问题。
这个我一直没有想通,太感谢ssqmnlin 了。
想知道连接操作符“+”的定义,他是否是new了一个新的字符串?
紫竹的是正解!答:我的看法不是这样,我认为是基于concat(...)方法实现的。。
理由:
我记得James Gosling在他的第四版书中讲得很清楚:
串的“+”与串的方法concat(...)是完全等价的。即:
如下两行是完全等价的:
newStr = oldStr.concat(" not");
newStr = oldStr + " not";而: public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}并不是基于StringBuilder或StringBuffer的。
Java 语言提供对字符串串联符号("+")和其他对象到字符串的转换的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中所有类继承。有关字符串串联和转换的更多信息,请参阅 Gosling、Joy 和 Steele 合著的《The Java Language Specification》。 可是在合著的《The Java Language Specification》中我看到的是与str.concat(...)等价。有点乱。
不过还是按API文档中的一段话理解吧
String s = "Hello world!";许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个String,内容是“Hello world!”。这样模糊的回答通常是概念不清的根源。如果要准确的回答,一半的人大概会回答错误。
这个语句声明的是一个指向对象的引用,名为“s”,可以指向类型为String的任何对象,目前指向"Hello world!"这个String类型的对象。这就是真正发生的事情。我们并没有声明一个String对象,我们只是声明了一个只能指向String对象的引用变量。所以,如果在刚才那句语句后面,如果再运行一句:String string = s;我们是声明了另外一个只能指向String对象的引用,名为string,并没有第二个对象产生,string还是指向原来那个对象,也就是,和s指向同一个对象。
你如果用+那肯定要在内存中创建一个新对象了
但如果其中一个或2个都是变量那最好用StringBuffer 我之前都是这么做的
关于上面所说的2个的原因和JAVA的内部机制有关 网上有很多解释自己可以去查一下
javap -c Test 查看虚拟机指令实验一:纯字符串
public class Test {
public static void main(String args[]) {
String str = "a";
}
} // 将字符串 a 存入常数池
0: ldc #2; //String a
// 将引用存放到 1 号局部变量中
2: astore_1
3: return实验二:纯字符串相加
public class Test {
public static void main(String args[]) {
String str = "a" + "b";
}
} // 将字符串 ab 压入常数池
0: ldc #2; //String ab
2: astore_1
3: return实验二可以很明显地看出,编译器在编译时产生的字节码已经将 "a" + "b" 优化成了 "ab",
同理多个字符串的相加也会被优化处理,需要注意的是字符串常量相加。实验三:字符串与自动提升常量相加
public class Test {
public static void main(String args[]) {
String str = "a" + (1 + 2);
}
} // 将字符串 a3 压入常数池
0: ldc #2; //String a3
2: astore_1
3: return通过虚拟机指令可以看出,1 + 2 自动提升后的常量与字符串常量,虚拟机也会对其进行优化。实验二、实验三结论:常量间的相加并不会引起效率问题实验四:字符串与变量相加
public class Test {
public static void main(String args[]) {
String s = "b";
String str = "a" + s;
}
} // 将字符串 b 压入常数池
0: ldc #2; //String b
// 将引用存放到 1 号局部变量中
2: astore_1
// 检查到非常量的相加,这时创建 StringBuilder 对象
3: new #3; //class java/lang/StringBuilder
// 从栈中复制出数据,即把字符串 b 复制出来
6: dup
// 调用 StringBuilder 的初始构造
7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
// 将字符串 a 压入常数池
10: ldc #5; //String a
// 调用 StringBuilder 的 append 方法,把字符串 a 添加进去
12: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// 从 1 号局部变量中加载数据引用
15: aload_1
// 调用 StringBuilder 的 append 方法,把字符串 b 添加进去
16: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
// 调用 StringBuilder 的 toString 方法
19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
// 将 toString 的结果保存至 2 号局部变量
22: astore_2
23: return实验四可以看出,非常量字会串相加时,由于相加的变量中存放的是字符串的地址引用,
因为在编译时无法确切地知道其他具体的值,也就没有办法对其进行优化处理,这时为了
达到连接的效果,其内部采用了 StringBuilder 的机制进行处理(JDK 5 中新增的,我
这里没有 JDK 1.4,估计在 JDK 1.4 下采用的是 StringBuffer),将他们都 append
进去,最后用 toString 输出。若 s 为其他类型时,比如:int 类型,也是采用同种方式进行处理。同理,根据实验二的结果,在 String str = "a" + "b" + s; 时,先会优化成 "ab" 再与
s 根据实验四的方式进行处理,这时 StringBuilder 仅调用了两次 append 方法。如果是 String str = "a" + s + "b"; 这种形式的就没办法优化了,StringBuilder 得调
用三次 append 方法。实验四的结论表明,字符串与变量相加时在内部产生了 StringBuilder 对象并采取了一定
的操作。如果只有一句 String str = "a" + s; 这样子的,其效率与
String str = new StringBuilder().append("a").append(s).toString();
是一样的。一般所说的 String 采用连接运算符(+)效率低下主要产生在以下的情况中:public class Test {
public static void main(String args[]) {
String s = null;
for(int i = 0; i < 100; i++) {
s += "a";
}
}
}每做一次 + 就产生个 StringBuilder 对象,然后 append 后就扔掉。下次循环再到达时重
新产生个 StringBuilder 对象,然后 append 字符串,如此循环直至结束。如果我们直接采用 StringBuilder 对象进行 append 的话,我们可以节省 N - 1 次创建和
销毁对象的时间。
到底产不产生新对象阿????
产生StringBuilder()对象??
你们干吗不把toString方法也javap出来啊?
String str2 = "ha"+"ha";
System.out.println(str1==str2);
String str1 = "haha"; //这里在编译期时就放到了池子里
String str2 = "ha"+"ha"; // 这里会先拼成"haha" 然后去池子里找,如果找到了,就用,如果找不到,就new(分配内存)个新的,放入池中。
这里能找到,所以下面这句为True
System.out.println(str1==str2); //true 除了名字不一样外,其他都一样(内存地址)所以返回true
String s1 = "ha" //这里同理也会到池里找,没有new一个新的放到池里,这里会放一个ha到池里。
String s2 = "ha" //这里找,有,用池里的,同时s1,s2引用相同地址,除了名字不一样外,其他都一样final String str1 = "length: 10"; // 没有,放到池里。
以上都在编译期做的事情,常量,会放到池子里。
final String str2 = "length: "+str1.length(); //这里不是在编译期做的事情,是存在Heap中的。
str1 和 str2 引用不同的地址,new一个"length: "+str1.length()放到Heap中,并用str2指向新地址。