Java與C++++的編程思想雖然有一定的共同性,但是在很多方面仍然存在著不同。如兩者在作用域上仍然存在著很大的差異。下面筆者就分析一下這兩門語言在作用域上的差異,這裡所提到的作用域包括變量作用域和對象作用域。
差異一:變量作用域的不同
如下面這段程序代碼是符合C++語言的語法要求的。其可以在C語言下正常運行。但是其在Java語言平台下編譯的時候,就會被告知有錯誤。其格式、關鍵字上面都沒有錯誤。那麼錯誤到底是這麼呢?這就關系到變量的作用域。
float y=3.15
float y=3.15
作用域就決定了其定義的變量名的可見性與生命周期。在C++語言(包括其衍生出來的其他語言)與Java語言中,都是用一定花括號來代表一個作用域的。如上面的代碼,就表示有兩個作用域。外面一對花括號代表一級作用域;裡面一對花括號代表二級作用域,依次類推。通常情況下,一級作用域中定義的變量,對其下級作用率都是有效的。也就是說,其下級作用域可以直接引用上級作用域中定義的變量。但是在二級作用域中,可以更改一級作用率中設置的變量值,不過這個更改只在二級作用域內部有效。如上面這個代碼,在二級作用域中可以再定義一個y變量,重新賦值。注意,其實在二級作用域中定義的變量與一級作用域中定義的變量,雖然名字相同,但是他們不是同一個變量。如果此時在一級作用域外,有其他代碼引用這個y變量的話,則其的值仍然是3.14,而不會是 3.15。也就是說,在二級作用域中定義的變量,只在其內部有效。對於上級作用域是沒有絲毫影響的。也就是說,在作用域中定義的變量只在其作用域內有效。出了其作用域外,其內部設置的變量就全部無效了。
這個作用域的設置其實Java語言與C++語言是類似的。但是在細節上Java語言又多了一條限制。如上表的代碼所示,雖然在上面的代碼中變量 y在兩個不同的作用域中定義,照理來說是兩者是互不干涉,可以共存。但是在Java編譯器中,是不允許有這種情況存在的。把上面這個代碼在Java編譯器中編譯的話,編譯器會通知程序開發人員,說這個變量y已經定義過。然後編譯會以錯誤告終。雖然在C++語言中在不同級別的作用域中定義名字相同的變量是允許的,而在Java語言中則不行,這並不代表在變量的作用域上有所不同。其實從本質上來說,兩者變量的作用域是相同的。只是對於Java語言來說,其又多加了一條限制。在Java語言中,即使作用域不同,其定義的變量名字也不能夠相同。這主要是為了提高Java代碼的可讀性,防止混淆才定義了這條規則。
差異二:對象作用域的差異
Java語言與C++語言一樣,都是面向對象的語言。不過兩者在實現機制上有很大的不同。就拿對象的作用域來說,就有很大的差異。這也導致了兩個面向對象的語言在實現細節上的巨大差異。
首先,Java程序員需要明白的是,Java對象作用域與變量的作用域是不同的。如上面的分析,變量的作用域只在作用域內部有效。如在二級作用域內定義的變量,超出了二級作用域,那麼就無效了。但是對象則不同,其可以存在於作用域之外。如現在在某個作用域內定義了一個name_full對象。當脫離這個作用域的時候,這個對象的引用是消失了。但是剛才創建的這個對象仍然實實在在的保存在內存中。在Java程序的運行過程中,只要通過傳遞或者復制對象引用的手段,那麼在其他作用域內仍然可以訪問這個對象。也就是說,只要我們有這個需要,那麼在某個作用域內創建的對象其會一直存在並可以在作用域外的其他任何一個地方進行訪問。當然前提是要通過復制或者傳遞等手段把對象引用傳遞到其他的作用域中。這就是Java對象與Java變量在作用域上最大的不同。
其次,Java對象與C++語言的作用域有很大的不同。其實C++語言中的對象跟變量的作用域到是很類似的。在C++語言中一旦使用完對象之後,就必須把這個對象銷毀掉。說的確切一點,就是要在作用域內把使用完的對象所占的內存空間釋放掉。否則的話,如果在作用於外部,由於已經失去了對這個對象的引用,為此這個對象就好像成為了太空中的一個人,無法再對其進行任何的操作,只要任其自生自滅。為此對於C++語言來說,程序員很難在脫離作用域外後,確保在需要調用對象時,仍然可以訪問這個對象。這也正是C++語言開發過程中最讓人頭疼的問題。因為需要手工來銷毀對象。萬一對象所占用的內存空間沒有別及時釋放的話,那麼對於應用程序的安全與性能都會產生很大的影響。
在Java程序中,這個作用域外的對象最終有兩個去向。首先,可以通過復制或者傳遞,在作用域外部仍然可以訪問這個對象。其次,就是銷毀對象。不過我們不用通過代碼來銷毀這個以前創建的對象。因為在Java語言中有一種叫做垃圾回收器的處理機制,其可以用來動態監視New關鍵字創建的所有對象,並根據一定的規則來判斷哪些對象不會再被引用。如果其判斷某個對象不再被引用話,則會自動釋放這些對象所占用的內存空間,以供其他新的對象所使用。我們程序開發人員只管創建對象即可,而不用去擔心什麼時候去銷毀對象。為此,這就可以消除C++語言面臨的內存溢出問題。這個內存溢出問題就是因為程序開發人員用完對象後忘記銷毀所造成的。
由於在Java程序開發中,我們開發人員不用關心對象的銷毀問題,為此可以更多的精力放在代碼的優化上。而不像C++語言那樣,要把這個對象銷毀問題當作頭件大事來對待。雖然如此,不過Java程序員也不能夠掉以輕心。特別是當我們在離開某個作用域後還需要訪問這個對象的時候,一定要記得通過復制或者傳遞等手段把對象引用傳遞給其他作用域。否則的話,即使這個對象沒有消亡,還實際存儲在內存中,但是也會因為缺少了引用而無法訪問他們。為此在跨作用域引用對象的時候,這個引用的復制與傳遞千萬不能夠忘了。
如果不幸忘了的話,那麼在作用域外的代碼就無法再訪問這個對象。不過這個對象在一定時候會被垃圾回收器回收了。被釋放了的內存空間就可以被重復使用,從而防止內存溢出的問題發生。
總之,當Java程序員在開發應用程序的時候,這個Java對象與Java變量作用域的差異,以及Java對象與其他語言對象作用域的差異,一定要了然於胸。這有助於Java程序員能夠更好的利用這個Java對象。另外筆者不厭其煩的再強調一遍,默認情況下脫離了某個作用域之後,對象就失去了引用無法訪問。如果要在作用域再訪問這個對象的時候,則需要及時把這個引用復制或者傳遞出來。否則的話,作用域外的代碼是無法再操作這個對象。