2011-10-01 65 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