2016-08-23 93 views
3

在下面的例子:是否有每個循環中創建的新變量?

for(int i=0; i<10; i++) { 
    int k; 
} 
  1. 這是真的,循環體(即,語句「INT K」)將被重複執行10次?

  2. 如果是這樣的話,是否意味着每次都會有創造了一個新的變量k? (因爲這種「類型後跟一個變量名」格式定義爲在JAVA創建一個新的變量雖然變量名保持相同)

+6

沒有變量「創建」。在棧上只有一個int大小的空間是保留的;而且同樣的空間被反覆使用。 –

+5

在這個_特定的例子中,如果你實際編譯並運行它,可能沒有任何'k'變量,因爲編譯器會優化它,因爲它沒有被使用。 –

+1

無論其他人在下面說什麼,Java語言都不會指定如何或何時分配變量。 1)你不能說身體是否被執行了0次,或者10次,因爲它不執行任何操作。 JVM可以自由地忽略所有的循環,如果它喜歡。如果你有例如印刷的東西,那麼是的,它會執行10次。 2)只有*一個*變量'k'。您無需關心何時或如何「創建」。你需要知道的是a)它被綁定到循環體,並且不能被外部訪問,b)在每次迭代中該值將「重置」。 – aioobe

回答

2

否,該變量的存儲器的方法中存在,而不是在循環。您只能在循環內訪問k的事實僅由編譯器完成。

如果你要改變這樣的代碼:

public class X 
{ 
    public static void main(final String[] argv) 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      int k = i * 2; 

      System.out.println(k); 
     } 
    } 
} 

然後運行javap的-c X查看字節碼,你會看到:

 0: iconst_0 
     1: istore_1   // i = 0 
     2: iload_1 
     3: bipush  10 
     5: if_icmpge  25 // i < 10 
     8: iload_1 
     9: iconst_2 
     10: imul 
     11: istore_2   // k = i * 2 < this is the key (see below) 
     12: getstatic  
     15: iload_2   // this gets k (see below) 
     16: invokevirtual #3     
     19: iinc   1, 1 // i++ 
     22: goto   2 
     25: return 

istore_2存儲計算的結果爲在堆棧中的第二個點。 iload_2獲取堆棧中第二個點的值。 (您可以看到指令說明here

堆棧一直存在,將其視爲一個方法可以訪問某個部分的數組。

+1

局部變量存儲在當前*框*中,該框在輸入方法時創建。它在任何時候都不存在。 – EJP

+0

看字節碼來解釋Java語言的語義有點落後。這一點突出表明,您必須*更改Java代碼以支持您的解釋。如果你保持在問題中發佈的Java代碼完整,那麼字節代碼將顯示變量沒有被分配*。該方法的最大本地數是相同的或不帶'int k;'。 – aioobe

1

確實循環體(也就是語句「int k」)會被重複執行10次嗎?

它你的意思正是依靠。正在使用的有關將啓動堆棧插槽k,但它被分配在方法入口,而不是循環條目。

如果是這種情況,那麼這是否意味着每次都會創建一個新的變量k? (因爲這種「類型後跟一個變量名」格式定義爲在JAVA創建一個新的變量雖然變量名保持相同)。

變量是由編譯器創建的。它佔用的地址空間在方法輸入時創建,參見上文。

相反在註釋某些權利要求中,這是完全由Java Virtual Machine Specification §2.6指定:

一個新幀的每個被調用的方法時創建。框架在其方法調用完成時被銷燬,無論該框架是正常還是突然(它引發未捕獲的異常)。幀是從創建幀的線程的Java虛擬機堆棧(第2.5.2節)分配的。每個幀具有其自己的局部變量的陣列(§2.6.1),它自己的操作數堆棧(§2.6.2),以及運行時常量池的引用(2.5.5節)的類的當前方法的。

+0

EJP,這是一個關於Java語言的問題。因此,唯一的權威來源是Java語言規範。澄清我的意思:這個問題顯然不能通過查看CIL規範來解決。即使我實現了Java - > CIL編譯器,這個事實也不會改變!從Java到JVM字節碼(或CIL)的翻譯可能會使得一個論點成爲事實,或者是偶然的,而不是通用的。指向JVM規範來解釋Java語言的語義是*反向推理*。 – aioobe

0

由於聲明int k只聲明變量(分配一個int塊)並且沒有定義它,所以不會每次都創建一個新變量。

此外,局部變量的範圍應儘可能小。因此,聲明變量的唯一好方法是在while循環中。

如果你想節省時鐘週期,當你初始化一個變量例如int k = 3;,爲了節省額外的時鐘時間,你可以在while循環之外聲明,從而增加變量的範圍。在這種情況下,變量不會每次都被初始化。

+0

'我提出這個問題只是爲了讓自己明確,一致地表達JAVA語言本身,而不是出於任何實際的原因。正如前面的答案,如果我們檢查字節代碼,我們可以知道沒有新的變量或空間分配,但是這種格式/表達式(我的意思是,在最後9個循環中,「int k」語句實際上什麼都不做)從邏輯上來說,像我這樣的新手會感到困惑。' – istrueright

-1

是的,變量k創建了10次。

但是這並不意味着任何性能,因爲Java編譯器會知道這10個變量的使用不會重疊。因此,它可能重複使用相同的存儲器(或寄存器)。

所以不要害怕創建很多變量,沒關係。更害怕用new創建對象。但即使如此,編譯器還是會優化其中的一部分。

+0

不,該變量由編譯器創建一次,並且在輸入方法時創建一次它佔用的幀插槽。 – EJP

相關問題