2011-10-01 72 views
1

看看这个Java代码:这是'长'如何工作(在Java中)?

class PerformanceTest2{ 

    public static void main(String args[]){ 

     Long sum = 0L; 

     for(int i=0;i<Integer.MAX_VALUE;i++) 
      sum += i; 

     System.out.println("Sum = " + sum); 
    } 
} 

据观察,它需要更长的时间以来和这个代码是“长” &不是“长”。因此,在每次迭代中发生的事情是:

sum = new Long(sum.longValue() + i); (for sum+=i;) 

因此,每次都会创建一个新对象。不支持Java类似于C++返回一个参考的功能,这样我们也许能写(可能):

sum.longValue() += i; 

可能不必创建和对象中的循环每一次?我对吗?

回答

7

那么,它不会调用构造函数。它使用:

for (int i = 0; i < Integer.MAX_VALUE; i++) 
{ 
    long tmp = sum.longValue(); // Unboxing 
    tmp += i; 
    sum = Long.valueOf(tmp); // Boxing 
} 

的包装对象是故意一成不变的 - 他们可以很容易地被设计成可变的,但不变性往往是一个非常有用的功能。如果你想编写自己的可变的包装类型,你很欢迎 - 在这一点,你可以有这样的代码:

LongWrapper sum = new LongWrapper(0L); 
for (int i = 0; i < Integer.MAX_VALUE; i++) 
{ 
    sum.add(i); 
} 
System.out.println("Sum = " + sum); 

或者可能:

LongWrapper sum = new LongWrapper(0L); 
for (int i = 0;i < Integer.MAX_VALUE; i++) 
{ 
    sum.setValue(sum.getValue() + i); 
} 
System.out.println("Sum = " + sum); 
+0

总和为'long'的程序在1.660s运行,而这一个(总和为'Long')花费了9.367s。那么这是原因吗?并且Java不是每次都在循环中创建和? – amil

+1

@AmitL:是的,拳击几乎肯定是原因。每次迭代都会调用Long.valueOf方法,但不一定会创建一个新的值。例如,-128和127之间的值保证被高速缓存。 –

+0

示例代码将很快超出“{-128,127}”的范围。我认为可以肯定地说,在几乎每次迭代中,构造函数都会被调用(通过'Long.valueOf()')。至少在最初通过循环时。并且可能在随后的传递中,因为Java似乎不太可能在'Long'的Integer.MAX_VALUE'实例附近的任何地方缓存。 – aroth

0

Java没有C++像引用。此外,原始类型的内置包装类有意使得不可变。这个决定的原因之一是,运行时可能会缓存包装器实例的特定值,并避免必须创建一个新的对象(这需要你调用valueOf而不是通过new分配一个新对象;编译器这样做是为了装箱)。

0

因此,每次都会创建一个新对象。不支持Java类似于C++的返回,这样我们也许能写 (可能)的引用 特点:...

如果使用Long你明确地从Java请求包装类型。包装类型的约定是:它们是不可变的。不变性(如C++中的constability)要求不得将可修改的内部结构赋予外部。但是一个类似C++的参考文件就是这样做的。 (让我们跳过const引用一部分,因为这也将不会帮助你在C++中。)

可能不必创建和对象中的循环每一次?我对吗?

理论上是的,但是如果你想要这样的行为,为什么不从一开始就使用简单的long

+0

所以在给定的程序中,是每次围绕循环创建总和?希望不是。 – amil

+0

当然。你问“长” - 你会得到它。就这么简单。 如果你不想要的话,可以用'long'代替。 –

1

我请你看看我已经在这里设立的测试用例:

http://ideone.com/Hvbs1

你的代码是缓慢的,不是因为你是混合longint类型,但因为你使用Long而不是longLong类型是一个适当的对象,并且不可启动,因此每次为变量指定一个新值时,都会构造一个新对象(可能的例外是新缓存对象已经存在)。这是一个昂贵的操作(相对而言)。

正如您将从示例代码中看到的,更改循环以添加long而不是int不会使其运行速度更快。加速它的方法是将第一个变量改为long而不是Long

0

其他人已经解释了为什么Long需要更长的时间,然后long and how using Long.valueOf`可能会稍快。

请,不要让这是不使用龙的原因。很可能你的整个系统吞吐时间将会受到而不是的影响。

如果有紧密的循环,其中这会影响性能,然后使用原始long那里,手卷包装作为乔恩描述或Apache的百科全书MutableLong

+0

其实我没有看到在这种情况下使用“长”的任何理由。感谢自动装箱,无论如何我们都会得到对象,并且不会有性能开销。 – Voo

+0

如果我理解你的意思,你说你可以使用例如'Set '和'put'''long',并且自动装箱将负责转换。正确的,只知道自动装箱会*也*使用'valueOf'(在javap中检查)进行转换,并具有相同的开销。 –

+0

很明显。但编译器只会在必要时自动复制原语。因此,我们可以在没有任何缺点的情况下获得原语的优势。如果我们这样做,我们会碰到我们在这里看到的性能问题。在使用Long的自动组合之前,它有助于避免额外的函数调用,但是今天呢?没有看到任何优势。 – Voo