2013-10-03 94 views
4

我有問題了解處理非靜態變量的方式。我選擇了使用數組,以便輕鬆地檢索其內存地址。java如何處理非靜態變量?

考慮下面的代碼:

public class tryClass 
{ 
    int[] v = {0}; // vector v is non-static (and NOT local to any method) 
    tryClass obj; 
    public void met() 
    { 
     obj = new tryClass(); 
     obj.v[0] = 30; 
     v[0]=3; 
    } 
    public static void main (String[] args) 
    { 
     tryClass obj = new tryClass(); // is this the SAME object as in met() ? 
     int[] v = new int[1]; 
     obj.v[0] = 40; 
     obj.met(); 
    } 
} 

爲了知道在每一步如何矢量v的處理我填寫的代碼有一些println指令和我的輸出中如下:

In main(), BEFORE running met() 
    obj.v[0] = 40 
    obj.v = [[email protected] 

INSIDE method met() 
    obj.v[0] = 30 
    v[0]  = 3 
    obj.v = [[email protected] 
    v  = [[email protected] 

In main(), AFTER running met() 
    obj.v[0] = 3 
    obj.v = [[email protected] 

我很困惑許多事情,其中​​第一個是爲什麼在靜態方法main()中調用時參考obj.vv在非靜態內部相同hod met()。另外,當沒有對象調用v時(當然是在非靜態上下文中),究竟是什麼?

我是Java的新手,我真的有無限的問題,我希望一個答案可以完全解決它們...在此先感謝您的幫助。

爲了完整起見,全碼是

public class tryClass 
{ 
    int[] v = {0}; 
    tryClass obj; 
    public void met() 
    { 
     obj = new tryClass(); 
     obj.v[0] = 30; 
     v[0]=3; 
     System.out.println("\nINSIDE method met()"); 
     System.out.println("\tobj.v[0] = "+obj.v[0]); 
     System.out.println("\tv[0]  = "+v[0]); 
     System.out.println("\tobj.v = "+obj.v); 
     System.out.println("\tv  = "+v); 
    } 
    public static void main (String[] args) 
    { 
     tryClass obj = new tryClass(); 
     int[] v = new int[1]; 
     obj.v[0] = 40; 
     System.out.println("In main(), BEFORE running met()"); 
     System.out.println("\tobj.v[0] = "+obj.v[0]); 
     System.out.println("\tobj.v = "+obj.v); 
     obj.met(); 
     System.out.println("\nIn main(), AFTER running met()"); 
     System.out.println("\tobj.v[0] = "+obj.v[0]); 
     System.out.println("\tobj.v = "+obj.v); 
    } 
} 
+1

您已經創建了instanceof tryClass。因此,無論您是使用Main方法還是使用類方法打印,您都會從該「實例」obj中打印「數組」參考,因此也會引用相同的參考 – Optional

+0

瞭解靜態方法和類以及使用靜態和實例時字段範圍的工作方式領域。這裏有一個提示:嘗試將你的(靜態)「main」方法放在一個單獨的類中(稱爲Start或某個東西),並讓你的「tryClass」免於使用。這樣可以看出爲什麼(靜態)方法本地字段與(非靜態)實例字段無關:(http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html我也認爲給出一些你熟悉的其他語言的細節可能會幫助那些會回答你的人。 –

+1

請注意,正如@ShivanDragon所說的,非靜態變量更適合稱爲實例字段(同樣適用於方法)。 – LexLythius

回答

1

爲什麼obj.v的參考,在靜態方法調用主當()中的相同的v的內部非靜態方法滿足()?

答:因爲您沒有將其重新分配給內存中的其他對象。它仍然指向內存中的同一個「數組」對象,即使您在內部更改了數組的內容。

看你的代碼,以我的意見:

public class tryClass 
{ 
    // here, non-static variable v will be instantiated 
    // as an array with a length of one, holding the value 0 in it's one slot; 
    // it will be instantiated when an instance of tryClass is created. 
    int[] v = {0}; 

    // here, this tryClass has another tryClass named "obj" in it as one of its fields. 
    tryClass obj; 

    public void met() 
    { 
     // here, the tryClass's tryClass obj is instantiated 
     // and this second tryClass's "v" is instantiated 
     // and then it's one slot is set to 30. 
     obj = new tryClass(); 
     obj.v[0] = 30; 

     // now, the first tryClass's "v" is set to 3. 
     v[0]=3; 
    } 

    public static void main (String[] args) 
    { 
     // creating a new tryClass. This is NOT the same object as in met. 
     // But it CONTAINS the same object in met. 
     // You could call it by going obj.obj. 
     tryClass obj = new tryClass(); // is this the SAME object as in met() ? Answer: No. 

     // this does nothing, it just creates another int[] v 
     // that exists only inside the main() method. It is not 
     // the same as obj.v! 
     int[] v = new int[1]; 

     // changing the contents of obj.v, but not reassigning obj.v itself. 
     obj.v[0] = 40; 

     // calling met, which will change obj.v's contents again, but not reassign it. 
     obj.met(); 
    } 
} 

數組是可變的,這意味着,即使它保留在內存中的同一個對象,它的內容可以改變。

+0

非常感謝你,你的一步一步的指導真的很感激。但是當你說'//這裏時,你的意思是什麼,這個tryClass的另一個名爲「obj」的tryClass是它的一個字段。 – AndreasT

+0

我想我現在明白了:我創建了兩個對象'obj',第一個在'main()'方法中,第二個在'met()'中。調用'obj.met()'會導致第二個'obj'成爲第一個「子對象」,我應該通過'obj.obj'訪問它。我是否正確地得到了你,並且是第一個「obj」和第二個「obj」正確的順序? – AndreasT

+0

@AndreasT是的,這是正確的,我認爲你是理解它。 「子對象」是思考它的一種方式,但在面向對象編程中,可以用HAS-A來考慮。 tryClass HAS-A tryClass。 –

1

您還應該打印出obj引用的值,當不在靜態上下文中時,也應該打印this的值。這將顯示,要打印的v引用的值不同的實例tryClass ...

public class tryClass 
{ 
    int[] v = {0}; 
    tryClass obj; 
    public void met() 
    { 
     obj = new tryClass(); 
     obj.v[0] = 30; 
     v[0]=3; 
     System.out.println("\nINSIDE method met()"); 
     System.out.println("\tthis  = "+this); //add this 
     System.out.println("\tobj  = "+obj); //add this 
     System.out.println("\tobj.v[0] = "+obj.v[0]); 
     System.out.println("\tv[0]  = "+v[0]); 
     System.out.println("\tobj.v = "+obj.v); 
     System.out.println("\tv  = "+v); 
    } 
    public static void main (String[] args) 
    { 
     tryClass obj = new tryClass(); 
     int[] v = new int[1]; 
     obj.v[0] = 40; 
     System.out.println("In main(), BEFORE running met()"); 
     System.out.println("\tobj  = "+obj); //and this 
     System.out.println("\tobj.v[0] = "+obj.v[0]); 
     System.out.println("\tobj.v = "+obj.v); 
     obj.met(); 
     System.out.println("\nIn main(), AFTER running met()"); 
     System.out.println("\tobj  = "+obj); //and also this 
     System.out.println("\tobj.v[0] = "+obj.v[0]); 
     System.out.println("\tobj.v = "+obj.v); 
    } 
} 

你也可以創建一個類的構造太:

public tryClass() { 
    System.out.println("Creating new instance of tryClass!"); 
} 

看看發生了什麼...

(或者,作爲一種學習體驗,你可以在你的IDE中查看調試器,這將會派上用場......)

+0

謝謝你,你添加的代碼真的很有用! – AndreasT

1

當您執行靜態主要方法時,首先要做的是創建一個tryClass實例,並打印一個名爲v的數組元素的值,該元素是該實例的一個屬性。 (obj.v [0])。然後你調用該實例的met方法,因此該方法體中的非靜態引用引用該實例的屬性(在main方法上創建的那個)。