关于String类型的对象初始化问题

mqslll594212 2012-08-20 09:11:12
众所周知,String是一个特殊的引用类型,那么再给它初始化的时候我通常使用这两种方式:
1.直接赋值:String s = "1234567890";
2.new对象: String s = new String("1234567890");

请问这两种方式哪一种效率更高或者有其他的好处?怎么用程序去验证这其中的差距呢??其实我最初是想用计时器去算运行的秒数,但是不知道可不可行。

笔者追加了一个程序去验证它们俩的用时,却得到了一个不想要的结果:
import java.util.Calendar;

public class String类型效率比较1 {

public static void main(String[] args) {
Calendar rightNow1 = Calendar.getInstance();
System.out.println(rightNow1.getTimeInMillis());


for(int i=1;i<=2000;i++){
String s1="12345678901";
System.out.println(s1);
}

Calendar rightNow2 = Calendar.getInstance();
System.out.println(rightNow2.getTimeInMillis());


for(int i=1;i<=2000;i++){
String s2=new String("12345678902");
System.out.println(s2);
}

Calendar c2=Calendar.getInstance();
System.out.println(c2.getTimeInMillis());
}

}

其中new String()得到的对象创建过程竟然比直接给String变量赋值过程用时短的多,为什么呢??
...全文
503 27 打赏 收藏 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
CCAV521 2012-08-23
  • 打赏
  • 举报
回复
不管是给String类型赋值 还是new String 都是先在常量池里寻找 如果常量池里有则不再创建直接引用
  • 打赏
  • 举报
回复
为什么 CSDN 的讨论这种问题会这么起劲?
dayo_tang 2012-08-22
  • 打赏
  • 举报
回复
我再发表下个人见解,如有异议,欢迎指教!
方式一:

String s1="123"; 只开辟了一块内存保存“123”,变量s1指向那块物理地址。


方式二:
String s2=new String("123");

步骤。
1.跟上面的一步是一样的。
2.new 对象时有开辟了一块内存,同时把“123”也复制过来。最终变量s2指向是第二块内存的物理地址。
YECHWNG 2012-08-22
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]
楼主的程序中第一次执行语句String s1="12345678901";时,程序会在堆的字符串池中寻找有无“12345678901”,如有那么将其引用给s1,由于是第一次执行,所以肯定没有,那就要现在堆中创建“12345678901”对象,然后将其引用给s1,当执行到String s2=new String("12345678902");时还是查询堆中有无“12345678901”,由于上面已经……
[/Quote]
实际应用中肯定是第一种效率高的
无敌波哥8 2012-08-21
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 的回复:]

什么是FGC()呢?我没查到呢,能再详细点吗?多谢!引用 18 楼 的回复:
我在附加一句吧,拿3楼的例子来说,大量的new,会产生大量的无用的对象,众所周知,java是自己清理垃圾的,当年轻代的空间不足,或者年老带不足,会引发GC活着FGC,而GC和FGC都是需要时间的,尤其是FGC会耗费大量的时间。所以不能疯狂的new。如果经常使用一个字符串,那就定义成常量,每次都是使用同一份。就如这样……
[/Quote]

我全是上面推荐的那本书上看的。很多虚拟机例如HOT SPOT把整个堆空间分成年轻代和年老带,看名字就很好理解,年轻代就是存一些新创建的对象,而年老带就是放一些实用了很久了但是还在用的对象。当年轻代的快满时会进行GC 也叫YoungGC,这个处理会把年轻代里面一些没有用的对象给清理掉。然后年轻代里的一部分对象满足一定条件的时候会移动到年老代,这样年老代也会不断增大,当增大到一定程度就会触发FGC,这个耗费时间相比YGC会大好几十倍。因为会同时清理年轻代和年老代,把没用的对象给清理掉。

mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
什么是FGC()呢?我没查到呢,能再详细点吗?多谢![Quote=引用 18 楼 的回复:]
我在附加一句吧,拿3楼的例子来说,大量的new,会产生大量的无用的对象,众所周知,java是自己清理垃圾的,当年轻代的空间不足,或者年老带不足,会引发GC活着FGC,而GC和FGC都是需要时间的,尤其是FGC会耗费大量的时间。所以不能疯狂的new。如果经常使用一个字符串,那就定义成常量,每次都是使用同一份。就如这样String s = "1234567890";或者定义一个static final……
[/Quote]
无敌波哥8 2012-08-21
  • 打赏
  • 举报
回复
强烈建议楼主 看看 jvm的书籍,他对java内存管理有比较详细的介绍,对你理解这个问题,非常有帮助。
http://www.amazon.cn/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3Java%E8%99%9A%E6%8B%9F%E6%9C%BA-JVM%E9%AB%98%E7%BA%A7%E7%89%B9%E6%80%A7%E4%B8%8E%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5-%E5%91%A8%E5%BF%97%E6%98%8E/dp/B0058FLC22/ref=sr_1_1?ie=UTF8&qid=1345562786&sr=8-1
我不是推销的,但是觉得这本书真的非常不错,讲的也通俗易懂,如果楼主想搞java的话时必备的,我这几天在第二遍翻这本书。确实不错的
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
嗯,看了这么多品论,我也查了很多,放心了![Quote=引用 16 楼 的回复:]
1.直接赋值:String s = "1234567890";
2.new对象: String s = new String("1234567890");

如果你需要大量的使用s,那么请使用第一种方式。因为第一种方式中"1234567890" 该字符串在方法区的常量池里面,每次取s都是取得这个常量,你可以通过String s1 = "1234567890";String s2 = "123……
[/Quote]
无敌波哥8 2012-08-21
  • 打赏
  • 举报
回复
我在附加一句吧,拿3楼的例子来说,大量的new,会产生大量的无用的对象,众所周知,java是自己清理垃圾的,当年轻代的空间不足,或者年老带不足,会引发GC活着FGC,而GC和FGC都是需要时间的,尤其是FGC会耗费大量的时间。所以不能疯狂的new。如果经常使用一个字符串,那就定义成常量,每次都是使用同一份。就如这样String s = "1234567890";或者定义一个static final String。
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
那你还是支持我的结论?还是认为终归是new的方式会多出一步去创建堆中的对象?[Quote=引用 15 楼 的回复:]
其实这原理,大多数人都说到了。但有些人的结果出人意料。这还有几个原因:
1.电脑的配置性能
2.添加了System.out.println();方法会影响结果。


------------------------------------------------
public static void main(String[] args) {
// TODO Auto-generat……
[/Quote]
无敌波哥8 2012-08-21
  • 打赏
  • 举报
回复
1.直接赋值:String s = "1234567890";
2.new对象: String s = new String("1234567890");

如果你需要大量的使用s,那么请使用第一种方式。因为第一种方式中"1234567890" 该字符串在方法区的常量池里面,每次取s都是取得这个常量,你可以通过String s1 = "1234567890";String s2 = "1234567890";s1==s2来看看结果,结果是true。

而第二种方式,他产生的"1234567890"字符串 是在堆中生成,并且每new一次,都会分配一块新的内存来保存该字符串。虽然占用的内存不多,但是大量的话就不太好。

所以从效率方面看,大量使用同一个字符串的话肯定是第一种方法好,因为他用的是同一个常量池里面的字符串。
dayo_tang 2012-08-21
  • 打赏
  • 举报
回复
其实这原理,大多数人都说到了。但有些人的结果出人意料。这还有几个原因:
1.电脑的配置性能
2.添加了System.out.println();方法会影响结果。


------------------------------------------------
public static void main(String[] args) {
// TODO Auto-generated method stub

long time1=System.currentTimeMillis();
for(int i=1;i<1000000;i++){
String a=new String("123456");
}
long time2=System.currentTimeMillis();
System.out.println(time2-time1);

for(int i=1;i<1000000;i++){
String a= "123456";
}
System.out.println(System.currentTimeMillis()-time2);
}
---------------------------------------
运行结果:
39
1
lost_guy_in_scut 2012-08-21
  • 打赏
  • 举报
回复
因为String str = "abc";他是先找常量池有没abc的引用,有的话就直接将str指向该地址。
楼主说看到时间会比较短,我这里实在看不出来,我循环了100000000,楼主可以看下执行结果的区别

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

/**
* @ClassName: Test1
* @Description: TODO(这里用一句话描述这个类的作用)
* @author chenjw
* @date 2012-7-16 下午5:38:28
*/

public class Test1 {
public static void main(String args[]) throws IOException{
long start = System.currentTimeMillis();
String str;
for(int i=0;i<100000000;i++){
str = new String("abc");
}
long end = System.currentTimeMillis();
System.out.println("new String,it takes " + (end - start));

start = System.currentTimeMillis();
String str1 ;
for(int i=0;i<100000000;i++){
str1 = "abc";
}
end = System.currentTimeMillis();
System.out.println("it takes " + (end - start));

start = System.currentTimeMillis();
String str2 ;
for(int i=0;i<100000000;i++){
str2 = "abc";
}
end = System.currentTimeMillis();
System.out.println("it takes " + (end - start));
}
}

运行结果:
new String,it takes 1201
it takes 35
it takes 35
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
其实我觉得还是直接赋值更高效一些,起码更节省空间,如果是不同值的话是不是差距会更明显一些?[Quote=引用 3 楼 的回复:]
因为String str = "abc";他是先找常量池有没abc的引用,有的话就直接将str指向该地址。
楼主说看到时间会比较短,我这里实在看不出来,我循环了100000000,楼主可以看下执行结果的区别

Java code

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter……
[/Quote]
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
难道String s="123"也要先在堆里new一个对象??[Quote=引用 4 楼 的回复:]
楼主的程序中第一次执行语句String s1="12345678901";时,程序会在堆的字符串池中寻找有无“12345678901”,如有那么将其引用给s1,由于是第一次执行,所以肯定没有,那就要现在堆中创建“12345678901”对象,然后将其引用给s1,当执行到String s2=new String("12345678902");时还是查询堆中有无“12345678901”,由于上面已经……
[/Quote]
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
呵呵 你都看到了 自己写的代码,new的话用了1201ms,直接赋值用了35ms,不要小看这微弱的差距哦。那你知道我那个程序是什么原因吗?前后颠倒了顺序,话费的时间不一样![Quote=引用 3 楼 的回复:]
因为String str = "abc";他是先找常量池有没abc的引用,有的话就直接将str指向该地址。
楼主说看到时间会比较短,我这里实在看不出来,我循环了100000000,楼主可以看下执行结果的区别

Java code

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter……
[/Quote]
果子狸G 2012-08-21
  • 打赏
  • 举报
回复
看时机 new会在堆里创建引用; 频繁会创建太多引用
赋值会在池中创建新的字符串;频繁赋值建议用StringBuffer
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
能详细点说嘛?[Quote=引用 8 楼 的回复:]
你确定是2个不是3个?

引用 7 楼 的回复:
String s1 = new String("12345678901")
其实创建了俩对象。
[/Quote]
mqslll594212 2012-08-21
  • 打赏
  • 举报
回复
能说的再详细吗?第一个是new的String对象,第二个是字符串常量池中的12345678901对象吗?[Quote=引用 7 楼 的回复:]
String s1 = new String("12345678901")
其实创建了俩对象。
[/Quote]
昕儒 2012-08-21
  • 打赏
  • 举报
回复
你确定是2个不是3个?
[Quote=引用 7 楼 的回复:]
String s1 = new String("12345678901")
其实创建了俩对象。
[/Quote]
加载更多回复(6)

62,620

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧