2009-03-03 137 views
3

我碰到的是成立一個這樣的類跑:靜態變量和方法

public class MyClass { 

    private static boolean started = false; 

    private MyClass(){ 
    } 

    public static void doSomething(){ 
    if(started){ 
     return; 
    } 
    started = true; 
    //code below that is only supposed to run 
    //run if not started 
    } 
} 

我與靜態方法的理解是,你不應該使用類變量,除非他們是常數,不改變。相反,你應該使用參數。我的問題是爲什麼當通過執行MyClass.doSomething()多次調用時,這不會中斷。在我看來,它不應該工作,但確實如此。它只會通過if語句一次。

所以有人可以向我解釋爲什麼這不會中斷嗎?

回答

11

方法doSomething()和變量started都是靜態的,所以只有一個變量副本,可從doSomething()訪問。第一次doSomething()被調用時,started是錯誤的,所以它將started設置爲true,然後執行...以及某事。第二次和後來的時間,started是真的,所以它沒有做任何事情就返回。

+0

那麼是說你保證只有一個這個類的拷貝會被初始化並且在整個應用程序運行期間被使用?我擔心的是,我不確定是否每次都使用同一個實例,並且變量值不一致。 – 2009-03-03 12:34:47

+0

正確答案+1。另外,這裏有一個地方可以獲得關於靜態變量的更多信息。可能對你來說是一件好事,bigbrother82:http://en.wikipedia.org/wiki/Static_variable – Welbog 2009-03-03 12:35:26

1

在靜態方法中,您可以調用或訪問同一個類中的靜態成員。

不考慮多線程場景, 第一次調用doSomething會使布爾靜態變量爲true,因此,第二次調用將執行if塊的代碼,它只是簡單地退出該方法。

0

上面的代碼工作得很好(除非它運行在多線程環境中)。你爲什麼認爲它應該打破?

0

我與靜態方法的理解是,你不應該使用類變量,除非他們是常數,不改變

我想只有靜態成員可以訪問。它不必是恆定的!

我的問題是爲什麼當通過執行MyClass.doSomething()多次調用時,這不會中斷。在我看來,它不應該工作,但確實如此。它只會通過if語句一次

根據現有的邏輯。只有第一個呼叫運行//code to be run部分

6

沒有理由不使用靜態變量。我並不是說這是特別好的做法,但它會起作用。

發生的事情是:

  1. 首先調用。該類被初始化,開始是錯誤的。
  2. doSomething被調用。如果失敗並且代碼繞過它。開始設置爲true,並運行其他代碼。
  3. doSomething被再次調用。如果通過並執行停止。

的有一點要注意的是,有沒有同步在這裏,所以如果DoSomething的()被調用單獨的線程上令人難以置信的接近,每個線程可以讀取開始爲假,則繞過if語句和做的工作,即有一個競爭條件。

2

這不是特別好的代碼 - 通常設計應該使用狀態改變的對象實例,但是沒有任何違法的。

我對靜態方法的理解是你不應該在它們中使用類變量,除非它們是常量,並且不會改變。

您似乎已從設計指南推斷爲語言特徵。閱讀網上提供的許多Java教程之一,瞭解該語言實際允許的內容。你可以用可以在靜態方法中自由地使用非最終靜態字段,但它會導致過程而不是面向對象的代碼。

而應該使用參數。

很難看出如何使用started參數 - 如果調用者知道進程已經啓動,他們爲什麼要調用該方法?

1

你靜態方法正在與靜態類變量交談,所以它應該沒問題。 你可以把它看作全局代碼和全局變量,它是在類的名字空間中。

如果您試圖訪問一個非靜態成員變量:從靜態方法中

private int foo = 0; 

,編譯器會和應該抱怨。

started is false - initial state. 
MyClass.doSomething() - statered is now true 
MyClass.doSomething() - started is STILL true 

MyClass foo = new MyClass(); 
foo.started -> it's STILL true, because it's static 
foo.doSomething() - not sure you can do this in Java, but if you can, it's be STILL TRUE! 

現在,在上面的代碼中存在與線程安全有關的問題,但除此之外,它似乎按照設計工作。

6

給出的代碼不是線程安全的。最簡單的方式,以使此代碼線程安全會做這樣的事情

public class MyClass { 

    private static AtomicBoolean started = new AtomicBoolean(false); 

    private MyClass(){ 
    } 

    public static void doSomething(){ 
    boolean oldValue = started.getAndSet(true); 
    if (oldValue) 
     return; 
    } 

    //code below that is only supposed to run 
    //run if not started 
    } 
} 

爲的AtomicBoolean getAndSet同步這應該是線程安全的。

不可否認,如果你不使用線程,這不是一個問題(請注意,webapp可以使用相當多的線程處理各種請求,而你不知道這一點)。

1

只需記住拇指規則「靜態變量是類級別變量和所有非靜態變量實例變量」。那麼你就不會有任何困惑!

即 對於靜態變量,代碼中對變量的所有引用指向相同的內存位置。對於非靜態變量,只要創建了該類的新實例(因此在代碼中對該變量所做的每個引用都指向分配用於調用類實例的不同內存位置),就會完成新的內存分配。