2013-04-20 41 views
3

我讀過一堂課是創建對象的模型,並且實際上不存在而對象是真實的。但是我們在一個類中創建變量,甚至操縱它們。當班級不真實時,班級內部是如何創建變量的?

  1. 這個類在物理上不存在時怎麼可能?

  2. 什麼時候爲這些變量創建了內存?

  3. 爲這些變量創建的內存在哪裏?

+0

在靜態變量的情況下,請參閱海德的答案。在實例變量的情況下,以及...向new'運算符(關鍵字)問好,這將觸發實際的分配。 – datenwolf 2013-04-20 10:25:34

+1

你讀的是錯的。對於已經在Java中加載的每個類確實有一個Class對象。在C++等其他語言中,類的「現實」在編譯代碼的字節中,除了創建對象的指令外,還可能存在表示靜態變量的「靜態」存儲位置。 – 2013-04-20 11:49:57

回答

3

如果你的意思是靜態類變量,它們quaranteed被initualized和內部類的任何靜態初始化代碼quaranteed要運行,使用前級。到底什麼時候,沒有指定IIRC,不同的JVM可能會在不同的時間這樣做。它們與具有這些語言的語言中的全局變量基本相同。

所以要重申:靜態的東西存在並在第一次使用之前被初始化。 JVM實現會照顧到這一點。

但有一個對象:類對象的實例,它是class Class的子類。


增加:事實上,在Java類存在,所以具體而言,它們可以被序列化,轉移通過網絡到不同的JVM,反序列化在那裏,產生在那裏的類和代碼執行的對象。簡單的例子就是在瀏覽器中運行的香草Java小程序。另一個例子是Jenkins/Hudson CI系統中的從屬節點,其中從屬程序非常小,只包含接收,反序列化和實例化這些類的類和對象的代碼,由它們連接的主服務器發送。

+0

非常感謝你 – user2301829 2013-04-29 13:26:53

3

試着用這種方式思考它。這並不是對Java運行時如何完成這個任務的精確解釋,而是一種思考類/對象二元性的方法,可以幫助您。

當您編寫一個類X時,您將描述代碼和數據。運行時只需要一些東西的副本 - 例如代碼和靜態變量 - 以及其他事物的每個對象一個副本,如實例變量。你在你寫的類文件中描述了這兩件事,儘管它們將被單獨存儲。

將每個類的一次拷貝看作全部存儲在一塊內存中 - 它將被稱爲C中的一個結構。在Java中,第一次在程序中引用類X運行時分配此塊內存並將其與類X關聯。

當程序執行諸如「X x1 = new X()」之類的語句時,運行時會分配另一個包含內存(或結構)的塊,其中包含所有的實例變量,並保持一個單獨的指針,以指向與x1變量相關聯的指針。

現在,當程序執行類似「Arc arc = x1.getArc();」時,運行時使用第一個指針引用方法getArc()中的代碼,第二個指針引用實例變量與x1關聯,並使用這些實例變量執行指示的代碼。

OO編程提供了將數據與操作它的代碼關聯的方式,使我們能夠將程序組織爲組合代碼和數據的「對象」。運行時間爲我們追蹤事物的不同副本。

我認爲說這個類不存在是不準確的,它只是不會以你寫它的形式存在。

0

類在運行時在JVM中物理存在。您閱讀的解釋是試圖勞動點A,而稍後留下其餘細節。學校和書籍一直都在這樣做。

在Oracle JVM類中,從加載它們的那一刻開始就有物理表示。事實上,每個對象都有一個指向該類的指針,許多對象可以指向同一個類。

0

我不會想到一個類或物體作爲物理的東西,這似乎讓我感到困惑。一個類通常被描述爲一個對象的藍圖。對象必須使用new關鍵字實例化(創建),當實例化對象時,對象的類將用作創建基本默認對象的藍圖。然後,即使在運行時,也可以通過引用內存中存儲它的位置並使用對象的類中的方法來操作對象的類中的字段來操作該對象,至少這是它通常應該完成的方式,它的所謂的封裝,在OOP中非常重要,所以如果你對封裝不熟悉,我會建議研究它。

我提到一個對象可以在運行時進行操作,這是對象和類之間的主要區別。類可以使用稱爲反射的東西,但這是另一天的另一個話題。變量或字段有時被描述爲地址,它是對存儲對象的內存位置的引用。對象不被直接訪問,它們通過變量被引用。

JLabel label; 

上述代碼在內存留出的位置來存儲一個JLabel對象時其與new關鍵字實例化。到目前爲止,還沒有創建對象,我們已經聲明瞭一個變量,它是對內存中位置的引用,當創建對象時,它將被存儲。我們不會直接訪問我們的JLabel對象,我們將使用我們創建的'label'變量來引用內存中的實際對象。所以,如果我們創建了兩個JLabel對象和實例化它們,像這樣...

JLabel label; 
label = new JLabel(); 
JLabel anotherLabel = new JLabel("this is another label"); 

我們現在有兩個JLabel的對象。第一個對象首先聲明一個變量來引用該對象,然後在一個單獨的行上實例化它。第二個對象聲明對它的引用並將它全部在一行中實例化。您既可以創建對象,也可以使用這兩種方法有不同的原因。當一個對象被創建時,至少有一個構造函數被調用,第一個對象調用不帶參數的JLabel類中的構造函數;第二個對象使用JLabel類,需要一個String,並創建顯示在傳遞給構造函數的文本對象內部的構造。

現在想象的程序正在運行,我們要改變的第一個對象,因此會顯示一些文本,因爲它目前是空白,因爲我們使用的是不帶任何參數的構造。我們可以使用像這樣的setText(String)方法來操縱對象。

label.setText("now the first label displays text"); 

我們沒有用這種方法改變了JLabel類以任何方式,但我們已經改變了對象,因此現在顯示的文字。我可能會因爲這個答案而失去一大堆聲望點或者其他任何東西,因爲我可能沒有完全正確地解釋每一個細節,但我回答了這個問題,因爲你問了一些對我來說很困難的問題理解了很長時間,可能比大多數更多,因爲我從來沒有參加過編程課。有很多這樣的東西,我不可能在沒有寫書的情況下完全解釋它,所以我沒有進入範圍,訪問修飾符,靜態等東西,但我試圖涵蓋我認爲重要的東西來理解你是什麼問。就像我說的,我沒有接受過正規教育,所以請就我的價值做出回答,但希望我能夠讓它更容易理解。

哦,我忘了你的其他問題。在創建對象的變量時聲明內存中用於存儲對象的位置。此時有一個位置,但內存中的大小仍爲0或爲空,因爲沒有對象。實際存儲對象所需的內存將在對象實例化時填充。