国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java中鮮為人知的缺點(上)

2019-11-18 13:28:19
字體:
來源:轉載
供稿:網友

  java是當今使用最廣泛的編程語言之一。自1995年發布以來,一直被用戶高度評價為“消除了C++缺點的優秀編程語言”。不過,隨著它的廣泛使用,其缺點也在逐步地表現出來。
  
  Java的缺點公認有如下三點:(1)存在非對象的數據類型;(2)不能夠用一種描述方法來表達各種類(Class);(3)無法繼續2個以上的類的裝配。雖然也有人認為編程語言應該是一個什么樣子會因人而異,不應該算成缺點。不過,上述三點卻可以導致編程人員使用混亂,降低源碼的可讀性及程序的可維護性。
  
  存在非對象的數據類型
   Java中鮮為人知的缺點(上)(圖一)


  表1●Java的原始類型(PRimitive)。原始類型包括表示真假的布爾型(Boolean)、字符型和數值型等(點擊放大)
  第一缺點是指雖說Java是面向對象的編程語言,但卻存在非對象的數據類型。
  
  “面向對象”的定義雖然有很多種,但無論何種定義,其最基本的概念都是利用包含數據和步驟的“對象”來表達系統。即便在Java領域,也會使用名為類的模型生成對象,并通過調用它的方法組織程序。
  
  但是,其中卻混雜著非對象的內容。原始類型又被稱為基本數據類型(表1)。用于處理文字的char(字符型)、表示真假的boolean(布爾型)、int以及float等數值型就屬于這種數據類型。
  
  原始類型的內存治理方法不同
   Java中鮮為人知的缺點(上)(圖二)
  圖1●Java的內存治理方法。Java內存區包括保存本地變量的內存堆棧區(stack)和保存對象的數據的內存堆區(heap)。堆棧區中存放的是用于引用(reference)對象時所需的信息(點擊放大)
  原始類型和對象型的內存治理方法不同。Java虛擬機所治理的內存區包括內存堆棧區和內存堆區(圖1)。內存堆棧區用于存放本地變量的數據。按堆出的順序保存本地變量的數據。一旦脫離變量的有效范圍,該數據馬上就被釋放。
  
  而內存堆區則用于存放對象本身。生成對象型的變量后,首先在內存堆棧區中為其預備存放位置。然后利用new運算符在這個位置生成新的對象后,對象及其數據就被存放到內存堆區。接著,內存堆區中的對象位置就會作為對象型的變量數據而被寫入內存堆棧區。由于這些是引用對象時所用的信息,因此對象型變量被稱為“引用型”。
  
  而實際數據本身被寫入內存堆棧區的是原始類型。采用這種內存治理方法的類型稱為“數值型”。
  
  引用型變量改變以后,就會引用保存內存堆區中的實際的對象數據,重新改寫數據。比如,在方法的引數(arguments)中描述對象型變量時傳遞給方法的就是存放在這個位置中的信息。所以在方法內追加的變更還會被反映到調用的原始對象上。另一方面,數值型變量傳遞的是它的值。即便在方法內部進行了變更,也不會反映到原始變量中。
  
  無法使用對象所具有的功能
  
  LIST 1●將數值數據保存在Java的矢量類中的程序。生成Integer類,然后封裝(Wrap)數值(點擊放大)
   Java中鮮為人知的缺點(上)(圖三)
點擊查看大圖

  LIST 1●將數值數據保存在Java的矢量類中的程序。生成Integer類,然后封裝(Wrap)數值(點擊放大)
  由于原始類型與對象型的內存治理方法不同,因此就無法生成統一兩種數據的類庫。比如,假如只是對象型數據就能夠構筑包含任意數據的類庫。
  
  可變長的數組類就是其中的一個例子。它是作為名為java.util.Vector的類而生成的。可以將任意的對象追加到數組中,還可以提取或刪除。能夠以此為引數指定任意的對象。但是,由于原始類型數據不是對象,因此無法直接引入。
  
  因此在Java中還存在相當于原始類型的類。比如int型變量就可以使用java..lang.Integer類。重新生成Integer類,然后保存數據,就可以追加到Vector矢量類中(LIST 1)。
  
  但是稍微想一想就會明白,這種方法并不是很靈活的做法。由于加入了多余的代碼,因此看起來感覺比較亂。而且還會浪費內存空間。原來的值暫且不說,還必須確保新建對象所需的內存。不僅存在表面上的問題,還存在實質上的問題。就是說無法保證數據的同一性。作為對象型保存的值與作為原始類型而保存的值完全不同。即便改變了原始類型的值,也不會反映到原來的int型數據。
  
  C#利用Boxing(裝箱)解決的只是一部分
  
  這一問題并非是Java特有的。比如,作為與Java類似的語言為用戶熟知的C#也存在相同的問題。C#利用稱為Boxing的方法部分地解決了這個問題。但是所解決的也只是可以不寫多余代碼的部分。內存問題和同一性問題仍然存在。
  
  即便C#,int、double和char等數據類型也無法作為對象進行處理。這些數據類型與Java的原始類型相同,也是數值型變量。
  
  C#可以將其值代入到對象中。LIST 2中顯示了具體的代碼。已經將int型的值代入了對象型變量。此時先進行裝箱,之后就開始靜靜地把基本數據類型的數據轉換成對象型數據。在內存堆區中確保相應的內存,然后將數值型數據保存這里(圖2)。對象型變量引用的就是這些數據。
   Java中鮮為人知的缺點(上)(圖四)
點擊查看大圖

  LIST 2●執行裝箱的C#代碼。將數值直接代入對象中。運行代碼后,輸出0和1。也就是說變量a和o沒有同一性(點擊放大)
   Java中鮮為人知的缺點(上)(圖五)
  圖2●C#中的裝箱法。對存放于內存堆棧區中的int型結構體(strUCts)裝箱時,就會靜靜地在內存堆區中生成對象。因此就無法確保與初始值的匹配性。(點擊放大)
  筆者利用裝箱法,用C#試著寫了一段與在Java的Vector矢量類中保存數值類似的代碼(LIST 3)。雖然ArrayList類要引數中提取對象型變量,但這里由于通過直接int型變量,因此代碼非常整潔。
  
  不過,并沒有解決多余的內存消耗和數值的同一性問題。因為只是單純地實現了自動向對象的轉換(圖3)。
   Java中鮮為人知的缺點(上)(圖六)
  LIST 3●與LIST 1起相同作用的C#代碼。由于具有裝箱法,因此可以直接向ArrayList中追加數值
  Java中鮮為人知的缺點(上)(圖七)
點擊查看大圖

  圖3●利用Java和C#,將int型變量轉換成對象的方法。盡管內部處理基本相同,但C#的特點是隱式轉換
  假如考慮到實用,也算得上是優點
  
  從上述所講來看,就會生出這樣的疑問:為什么最新的Java和C#語言還存在著這樣的問題呢?實際上這是因為對其性能的重視。
  
  由于原始數據型數據在編程時使用得最多,因此利用能夠對其進行快速處理的原始類型,性能就會提高。而對象型數據在生成對象,以及使用位置信息去引用內存堆區中的數據時則會產生一定的開銷。另一個問題是內存堆區。假如全部是對象型,比如,只要執行簡單的for循環語句,就會在內存堆區中生成大量的對象。由于內存堆區的消耗速度就會急劇上升,并且頻繁地進行資源回收處理,因此性能就會降低。
  
  Java和C#是考慮到性能問題才生成原始數據型數據的。因此并不能說是“純粹的”面向對象語言。也許可以說是考慮到實用性的穩妥做法吧。(記者:大森 敏行、八木 玲子)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 镇坪县| 辉县市| 苍梧县| 陕西省| 揭东县| 青海省| 本溪市| 达拉特旗| 阿城市| 鸡西市| 刚察县| 建湖县| 航空| 通许县| 涿州市| 类乌齐县| 新邵县| 新闻| 远安县| 澄迈县| 凤冈县| 牙克石市| 阳泉市| 定陶县| 绥化市| 东乌珠穆沁旗| 岗巴县| 乐昌市| 灵丘县| 桃江县| 托克逊县| 安宁市| 定陶县| 金秀| 肥乡县| 鄂托克旗| 富顺县| 台北县| 土默特左旗| 博湖县| 新乐市|