请教一个装箱拆箱的问题

wapigzhu 2013-03-05 10:46:32
下面两段代码

String a = "abc";
Integer b = 1;
String c = null;
long begin = System.nanoTime();
for(int i = 0; i < 1000; i ++){
c = a + b;
}
System.out.println(System.nanoTime() - begin);



String a = "abc";
int b = 1;
String c = null;
long begin = System.nanoTime();
for(int i = 0; i < 1000; i ++){
c = a + b;
}
System.out.println(System.nanoTime() - begin);

第二段要比第一段快30%的样子,为什么?
我理解的是a+b的时候要把b自动装箱成Integer,然后toString,
按理说比第一段要慢,就算是编译的时候已经优化过了,
也不应该比第一段快才是?
...全文
249 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
wapigzhu 2013-03-05
  • 打赏
  • 举报
回复
引用 12 楼 kiritor 的回复:
口说无凭,佐证 http://blog.sina.com.cn/s/blog_4b50130d0100u3vh.html 优化的: http://pnuts.cc/2010/01/int-to-string/comment-page-1/?replytocom=753
我的结论就是你后面这个帖子说的啊, append(int)比append(Object)的效率高, 所以int b = 1的要比Integer b = 1的那段要快
LCore 2013-03-05
  • 打赏
  • 举报
回复
我咋突然觉得我有点理解错了哇
wapigzhu 2013-03-05
  • 打赏
  • 举报
回复
引用 11 楼 kiritor 的回复:
引用 10 楼 dracularking 的回复:引用 7 楼 wapigzhu 的回复:谢谢楼上各位的回答~刚才试了下, 把两个.class文件分别用javap查看 关键的区别应该在第一段的+操作是(Integer) 33: invokevirtual #40; //Method java/lang/StringBuilder.append:(Ljava/l……
你确定?

public static void main(String[] args) {
		Integer b = 1;
	    long begin = System.nanoTime();
	    System.out.println("" + b);
	    System.out.println(System.nanoTime() - begin);
	    
	    int c = 1;
	    begin = System.nanoTime();
	    System.out.println(""+c);
	    System.out.println(System.nanoTime() - begin);
	}
这个代码执行结果是 1 202202 1 41332
LCore 2013-03-05
  • 打赏
  • 举报
回复
引用 10 楼 dracularking 的回复:
引用 7 楼 wapigzhu 的回复:谢谢楼上各位的回答~刚才试了下, 把两个.class文件分别用javap查看 关键的区别应该在第一段的+操作是(Integer) 33: invokevirtual #40; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/St……
应该是Integer转String的代价要小些吧 Integer的toString()方法做了相关优化 Integer b = 1; long begin = System.nanoTime(); System.out.println(b); System.out.println(System.nanoTime() - begin); int b = 1; long begin = System.nanoTime(); System.out.println(""+b); System.out.println(System.nanoTime() - begin); 时间也是前一段代码执行的时间短一些啊
dracularking 2013-03-05
  • 打赏
  • 举报
回复
引用 7 楼 wapigzhu 的回复:
谢谢楼上各位的回答~刚才试了下, 把两个.class文件分别用javap查看 关键的区别应该在第一段的+操作是(Integer) 33: invokevirtual #40; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 第二段的是(……
应该就是这个原因,int转为String代价更小一些
wapigzhu 2013-03-05
  • 打赏
  • 举报
回复
再算一下,上面的图是100000000次循环下的 Integer用的时间是20013-划掉的3195=16818 int用的时间14188-划掉的2294=11894 差值是4924 Integer的append-int的append=6255 - 1894=4361 88%的时间差都是这个方法造成的.. 看来大概是这么个问题吧..
wapigzhu 2013-03-05
  • 打赏
  • 举报
回复

这个是把数字加大后visualvm的图,划掉的是System.in.read(),无视掉..
看起来主要区别就是append这个方法差很多..
wapigzhu 2013-03-05
  • 打赏
  • 举报
回复
谢谢楼上各位的回答~刚才试了下, 把两个.class文件分别用javap查看 关键的区别应该在第一段的+操作是(Integer) 33: invokevirtual #40; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; 第二段的是(int) 30: invokevirtual #35; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 看了下源代码,append(Object)是需要把字符串的内容arraycopy一次, append(int)只是把自己内部的char[]传到Integer的一个static方法里面,简单的拼在后面 也许是这个原因?
  • 打赏
  • 举报
回复
这个运行时间应该每次都不同才对。不存在严格的第一段比第二段快慢之分。
安特矮油 2013-03-05
  • 打赏
  • 举报
回复
个人感觉:1.Integer b = 1;是有个装箱的步骤。2.基本数据类型在于String相加的时候应该是会调用String.valueOf(i);而Integer会执行toString方法,方法的入栈出栈也存在的一定的差异。当然这些只是猜测。 当循环增加到100000000次后与10000次的平均循环时间比其实有降低。
jjxiaoxuan 2013-03-05
  • 打赏
  • 举报
回复
你的第二段代码, b是个基本数据类型。当在与字符串进行拼接的时候是直接来的,不需要在转化,也就是你说的拆箱。 而你的第一段代码,b是个引用数据类型,每次执行拼接的时候都要,进行拆箱,你说那个慢? 就好像每一次循环第一次比第二次 多做了点事,所以就慢的罗
七神之光 2013-03-05
  • 打赏
  • 举报
回复
第二段应该不会快啊,你这个循环有可能直接被编译器优化掉了
	volatile int i  ;
	public void haha(){
		String a = "abc";
		Integer b = 1;
		String c = null;
		long begin = System.nanoTime();
		for( i = 0 ; i < 1000; i ++){
			c = a + b;
		}
		System.out.println(System.nanoTime() - begin);
		System.out.println(c);
	}
残月照我心 2013-03-05
  • 打赏
  • 举报
回复
顶,坐等高手
LCore 2013-03-05
  • 打赏
  • 举报
回复
我觉得照成此问题的并不是装箱与解箱的问题. 而是String类中“+”的问题。 前一种方法c=a+b;相当于c=a+b.toString(); 照成了for循环中一直在new String类型的对象 而后一种方法则涉及到了String类中的“+”运算符的问题: Java只是不支持自定义运算符重载,这个String类的+就是运算符重载, 也是Java中仅有的一个运算符重载,它是通过编译器实现的, 在语法解析阶段就已经确定了 具体来说后一种方法 c=a+b;相当于c= new StringBuilder().append(a).append(b).toString(); 如果仅仅比较Integer().toString与1+“”的效率的话 前者的效率应该高些。 原因在于Integer().toString方法在java中实现了很多的优化
public class Test1 {
public static void main(String[] args) {

    Integer b = 1;
   
    long begin = System.nanoTime();
    System.out.println(b);
    System.out.println(System.nanoTime() - begin);
}
}
public class Test2 {
public static void main(String[] args) {
	
    int b = 1;
   
    long begin = System.nanoTime();
   System.out.println(""+b);
    System.out.println(System.nanoTime() - begin);
}
}

62,614

社区成员

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

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