2013-09-28 45 views
1

https://stackoverflow.com/a/572550/1165790Java是否支持函數內部的靜態變量來保持調用之間的值?

我想在Java中使用此功能,因爲我的設計是很少調用的函數(但是當它被調用時,它開始遞歸鏈),因此,我不想讓每次實例化類時,都會變量實例字段以浪費內存。

我也不想創建一個額外的參數,因爲我不想負擔外部調用的函數與實現細節。

我嘗試了static關鍵字,但Java說它是非法修飾符。有沒有直接的選擇?如果不是,建議使用哪種解決方法?

我希望它具有函數作用域,而不是類作用域。

+0

您可以發佈迄今爲止已嘗試的內容嗎?你可以試試這樣的: –

+0

Java有靜態變量,只是它們的名字範圍是類而不是方法。 (但是我懷疑你並沒有完全理解Java存在範圍的細微之處。) –

+0

將單實例變量聲明爲靜態應該完全符合你的需要。看到你的代碼會有所幫助。 –

回答

9

我希望它有功能範圍,而不是類範圍。

然後你運氣不好。 Java提供了static(類範圍),實例和局部變量。沒有Java等價於C的函數範圍static變量。


如果變量真的需要是靜態的,那麼你唯一的選擇是讓類範圍。這就是你所擁有的一切。另一方面,如果這是某個遞歸方法調用中使用的工作變量,那麼使其成爲靜態將意味着您的算法不可重入。例如,如果您嘗試在多個線程上運行它,它將分崩離析,因爲這些線程將嘗試使用相同的靜態...並相互干擾。在我看來,正確的解決方案將要麼使用方法參數傳遞此狀態。 (你也可以使用所謂的「線程本地」變量,但它們有一些顯着的缺點......如果你擔心200字節存儲量的開銷!)

+0

如果類被實例化了100次,並且我有一個變量的實例字段,那麼每個實例化的對象都不會爲變量分配內存(不管該方法是否被調用)? –

+0

所討論的變量是一個int類型,所以如果只有一個客戶端實際調用該方法,那麼我們就浪費了2個字節* 99。我喜歡使用另一個帶有附加參數的私有函數的解決方法。 –

5

你打算如何在不浪費內存的情況下保持呼叫間的價值?而消耗的內存可以忽略不計。

如果您需要存儲狀態,存儲狀態:只需使用靜態字段。請確保您同步訪問靜態字段,以迎合分別從不同的線程同時調用的方法:


注意在多線程應用程序時使用靜態變量建議。最簡單的方法是將​​關鍵字添加到static方法,並將該方法作爲使用該字段的唯一代碼。鑑於該方法不經常被調用,這種方法將是完全可以接受的。

+0

<1%的實例化類的用戶將使用該方法。我不想每次都爲這個狀態分配內存。我希望它具有函數範圍,而不是類範圍。 –

+1

每次實例化類時都不分配 - 所有實例之間共享一個靜態成員字段。 Java對象是作爲引用存儲的,所以如果你在第一次使用方法時只分配實際的對象,那麼在不使用方法的情況下,只有64位內存會被浪費(=整個程序運行時沒有方法被調用一次)。 64b的內存比你存儲代碼的任何駭人的解決方法所需的內存少得多。 –

+0

@IdanArye大多數64位JVM使用32位引用。 –

2

靜態變量是類級別的變量。如果您在方法之外定義它,它將按照您希望的方式運行。

參見文檔:

Understanding instance and Class Members

從Java中這個問題的答案代碼...

public class MyClass { 
    static int sa = 10; 

    public static void foo() { 
     int a = 10; 

     a += 5; 
     sa += 5; 

     System.out.println("a = " + a + " sa = " + sa); 
    } 

    public static void main(String[] args) { 
     for (int i = 0; i < 10; i++) { 
      foo(); 
     } 
    } 
} 

Output: 
$ java MyClass 
a = 15 sa = 15 
a = 15 sa = 20 
a = 15 sa = 25 
a = 15 sa = 30 
a = 15 sa = 35 
a = 15 sa = 40 
a = 15 sa = 45 
a = 15 sa = 50 
a = 15 sa = 55 
a = 15 sa = 60 

SA只存在於內存中一次,班裏的所有實例訪問它。

1

我同意波希米亞這是不可能的內存將是一個問題。此外,重複的問題:How do I create a static local variable in Java?

爲了迴應您對該方法添加額外參數以及公開實現細節的疑慮,希望補充說明有一種方法可以在不公開附加參數的情況下實現此目的。添加一個單獨的私有函數,並讓公共函數封裝遞歸簽名。我已經多次在函數式語言中看到過這個,但它當然也是Java中的一個選項。

你可以這樣做:

public int getResult(int parameter){ 
    return recursiveImplementation(parameter, <initialState>) 
} 

private int recursiveImplementation(int parameter, State state){ 
    //implement recursive logic 
} 

雖然這可能不會與你的內存關心對付,因爲我不認爲Java編譯器考慮尾遞歸優化。

1

在遞歸調用設置堆棧上的變量將是功能(幀)本地:

public class foo { 
    public void visiblefunc(int a, String b) { 
     set up other things; 
     return internalFunc(a, b, other things you don't want to expose);   
    }                    

    private void internalFunc(int a, String b, other things you don't want to expose) { 
     int x; // a different instance in each call to internalFunc()                
     String bar; // a different instance in each call to internalFunc() 
     if(condition) { 
      internalFunc(a, b, other things); 
     } 
    } 

}

+0

是的 - 幾乎正是Alex剛剛在上面發佈的。 –

2

也許你解決了你的問題,但這裏有更多關於Java靜態的細節。可以有靜態類,函數或變量。

class myLoader{ 

static int x; 
void foo(){ 
// do stuff 
} 

} 

class myLoader{ 


    static void foo(){ 

    int x; 

    // do stuff 
    } 

    } 

在第一種情況,它被作爲一個類變量。你不必這樣「浪費記憶」。您可以通過myLoader.x 訪問它。但是,在第二種情況下,該方法本身是靜態的,因此它本身屬於該類。在此方法中不能使用任何非靜態成員。單身設計模式將使用靜態關鍵字僅實例化一次類。 如果您正在使用多線程編程,請確保在您的靜態變量正在同時訪問時不會生成競爭條件。

+0

「如果你正在使用多線程編程,如果你的靜態變量被同時訪問,一定不要產生競爭條件。」......這是否意味着在所有線程中變量x將始終具有相同的值?我的意思是在所有線程中x的值相同? –

1

有時狀態可以通過簡單傳遞來保存。如果僅在內部用於遞歸,則委託給具有附加狀態參數的私有方法:

public void f() { // public API is clean 
    fIntern(0); // delegate to private method 
} 

private void fIntern(int state) { 
    ... 
    // here, you can preserve state between 
    // recursive calls by passing it as argument 
    fIntern(state); 
    ... 
} 
相關問題