2013-08-29 28 views
2

我有這個問題,以及更多的查詢,因爲我實際上得到它的工作,但我不明白爲什麼,我目前正在學習java和閱讀cengage第7版,這是練習之一。字段在方法內不工作

所以我有這樣的方法:

public static void calculatePrice(){ 
     Scanner userInput = new Scanner(System.in); 
     int orderNumber; 
     double totalBill = 0; 

     orderNumber = userInput.nextInt(); 
     switch(orderNumber){ 
     case 1: 
      totalBill = totalBill + American; 
      displayMenu(); 
      calculatePrice(); 
      break; 
     case 2: 
      totalBill = totalBill + Espresso; 
      displayMenu(); 
      calculatePrice(); 
      break; 
     case 3: 
      totalBill = totalBill + Latte; 
      displayMenu(); 
      calculatePrice(); 
      break; 
     case 0: 
      System.out.println("Your total bill will be $"+ totalBill); 
      break; 
     } 
    } 

本章還教我約的決定,我決定在這種情況下使用的開關。我有另一種方法詢問用戶的問題。

我用這種方法的問題是字段:

double totalBill = 0; 

這不工作,我不知道爲什麼,程序編譯,但它始終將返回0的固定價格,無論我的邏輯之內案例情景。

然而,當我從方法去除場,並把它的頂部,使它類寬:

private static double totalBill = 0; 

它正常工作,這是爲什麼?在方法中使用它似乎更聰明,因爲沒有其他方法需要使用它。

+0

這是關於範圍。 –

+0

對,我需要回到那一章。我認爲只要它在同一個街區就可以。不過謝謝!我至少可以回頭重讀:D – Gibbo

回答

3
//Note that you declare this method static: as such it will have no access to object 
//member fields, only to class fields: these are member fields declared 'static' 
public static void calculatePrice(){ 
    Scanner userInput = new Scanner(System.in);//Note this has little to do with actually calculating price. 
    int orderNumber; 
    double totalBill = 0;//You a declaring a new variable that will disappear once it goes out of the scope of this method 

    orderNumber = userInput.nextInt(); 
    switch(orderNumber){ 
    case 1: 
     totalBill = totalBill + American; 
     displayMenu(); 
     calculatePrice();//Recursive call! 
     break; 
//... eliding for brevity 
    case 0: 
     System.out.println("Your total bill will be $"+ totalBill); 
     break; 
    } 
} //this is the point where all method variables go out of scope, because this 'stack frame' is unloaded. Any subsequent call to this method will not 'remember' any state that was not saved elsewhere. 

因此,請注意您正在進行遞歸調用。這意味着你的重新輸入你的功能。你的'totalBill'變量被新實例化,掩蓋了其他所有'totalBill'變量。這些變量仍然存在......只是在較低的堆棧幀上無法訪問。把棧幀看作一個新的表格,在這個表格上運行你的函數。當你調用一個新的函數時,一個新的表格被放置在頂部......但你只能看到頂部的表格。所有其他表都在它下面。

通過聲明變量static,這意味着您將其設置在一邊,以便此類型的所有對象中的所有函數都可以訪問相同的內存空間。 static變量可用於該類的所有對象;因此它們通常被稱爲「類字段」,而非靜態成員變量則被稱爲「對象字段」。你的類簽名應,在一個精心設計的世界是這樣的:

public class RegisterOrder { 
    public double totalBill;//Available to only ONE instance (object) of this class. 

    public void calculatePrice() {//note no 'static' modifier! 
    //some code 
    } 
} 

這可能不會與您目前正在呼喚你calculatePrice功能的工作方式,因爲當前的方法是static。你必須要改變,要:

RegisterOrder order = new RegisterOrder(); 
order.calculatePrice(); 

注意,那就是,你的遞歸調用意味着,如果你爲了很多很多的訂單程序將會崩潰。把它看成堆疊太高的表。在現代系統中,這是很難做到的(大量的內存),但良好的設計要求這裏的循環:

public function getOrder() { 
    //instantiate variables 

    orderNumber = userInput.nextInt(); 
    while (orderNumber != 0) { 
    switch(orderNumber){ 
     case 1: 
     totalBill = totalBill + American; 
     break; 
     case 2: 
     totalBill = totalBill + Expresso; 
     break; 
     case 3: 
     totalBill = totalBill + Latte; 
     break; 
     default: 
     //Error handling is important! 
     break; 
    } 
    displayMenu(); 
    orderNumber = userInput.nextInt(); 
    } 
    System.out.println("Your total bill will be $"+ totalBill); 
} 

注意,在這個版本中,你不能再呼叫您的輸入功能。還要注意,在此函數中聲明的'totalBill'變量不會被另一個對此函數的調用卸載或屏蔽。在真正乾淨的代碼中,你可以將你的輸入獲取方法與賬單計算方法分開,但是步驟很簡單。 :)

+1

+1用於捕獲遞歸調用,並附帶相關說明。 – rgettman

+1

介意。吹。這有助於很多,謝謝!我不在使用循環或異常處理的章節中:D我知道如何使用while和for循環,我只是假設你可以在沒有使用它們的情況下完成任務,因爲本書還沒有教授它們:) – Gibbo

5

您的totalBill變量是在本地聲明的,因此每次調用此方法時都將其初始化爲0。然後它會超出範圍,直到下一次它被調用時,它再次被初始化爲0

private static double totalBill = 0;以外的方法中,現在它是一個static類變量,無論調用多少次calculatePrice都會保留其值。範圍是整個類,而不僅僅是方法,並且在調用方法時不會重新初始化。

+0

謝謝!這真的慢跑我的記憶,並使總體感,感謝您的幫助:) – Gibbo

+1

你的迴應是微妙的錯誤:在OP的實現中,'calculatePrice()'方法調用自己。因此,實際發生的情況是'totalBill'變量被屏蔽,不會超出範圍。當然,這種情況下的行爲是一樣的。 –

-1

靜態變量綁定到類而不是對象。在第一種情況下,您必須爲對象設置變量。