熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

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

2013-11-15 11:34:45  來源: JSP教程 

  Java是當今使用最廣泛的編程語言之一年發布以來一直被用戶高度評價為消除了C++缺點的優秀編程語言不過隨著它的廣泛使用其缺點也在逐步地表現出來
  
  Java的缺點公認有如下三點)存在非對象的數據類型)不能夠用一種描述方法來表達各種類(Class))無法繼承個以上的類的裝配雖然也有人認為編程語言應該是一個什麼樣子會因人而異不應該算成缺點不過上述三點卻可以導致編程人員使用混亂降低源碼的可讀性及程序的可維護性
  
  存在非對象的數據類型
   
  表●Java的原始類型(Primitive)原始類型包括表示真假的布爾型(Boolean)字符型和數值型等(點擊放大)
  第一缺點是指雖說Java是面向對象的編程語言但卻存在非對象的數據類型
  
  面向對象的定義雖然有很多種但無論何種定義其最基本的概念都是利用包含數據和步驟的對象來表達系統即便在Java領域也會使用名為類的模型生成對象並通過調用它的方法組織程序
  
  但是其中卻混雜著非對象的內容原始類型又被稱為基本數據類型(表用於處理文字的char(字符型)表示真假的boolean(布爾型)int以及float等數值型就屬於這種數據類型
  
  原始類型的內存管理方法不同
   
  圖●Java的內存管理方法Java內存區包括保存本地變量的內存堆棧區(stack)和保存對象的數據的內存堆區(heap)堆棧區中存放的是用於引用(reference)對象時所需的信息(點擊放大)
  原始類型和對象型的內存管理方法不同Java虛擬機所管理的內存區包括內存堆棧區和內存堆區(圖內存堆棧區用於存放本地變量的數據按堆出的順序保存本地變量的數據一旦脫離變量的有效范圍該數據立刻就被釋放
  
  而內存堆區則用於存放對象本身生成對象型的變量後首先在內存堆棧區中為其准備存放位置然後利用new運算符在這個位置生成新的對象後對象及其數據就被存放到內存堆區接著內存堆區中的對象位置就會作為對象型的變量數據而被寫入內存堆棧區由於這些是引用對象時所用的信息因此對象型變量被稱為引用型
  
  而實際數據本身被寫入內存堆棧區的是原始類型采用這種內存管理方法的類型稱為數值型
  
  引用型變量改變以後就會引用保存內存堆區中的實際的對象數據重新改寫數據比如在方法的引數(arguments)中描述對象型變量時傳遞給方法的就是存放在這個位置中的信息所以在方法內追加的變更還會被反映到調用的原始對象上另一方面數值型變量傳遞的是它的值即便在方法內部進行了變更也不會反映到原始變量中
  
  無法使用對象所具有的功能
  
  LIST ●將數值數據保存在Java的矢量類中的程序生成Integer類然後封裝(Wrap)數值(點擊放大)
   
  LIST ●將數值數據保存在Java的矢量類中的程序生成Integer類然後封裝(Wrap)數值(點擊放大)
  由於原始類型與對象型的內存管理方法不同因此就無法生成統一兩種數據的類庫比如如果只是對象型數據就能夠構築包含任意數據的類庫
  
  可變長的數組類就是其中的一個例子它是作為名為javautilVector的類而生成的可以將任意的對象追加到數組中還可以提取或刪除能夠以此為引數指定任意的對象但是由於原始類型數據不是對象因此無法直接引入
  
  因此在Java中還存在相當於原始類型的類比如int型變量就可以使用javalangInteger類重新生成Integer類然後保存數據就可以追加到Vector矢量類中(LIST
  
  但是稍微想一想就會明白這種方法並不是很靈活的做法由於加入了多余的代碼因此看起來感覺比較亂而且還會浪費內存空間原來的值暫且不說還必須確保新建對象所需的內存不僅存在表面上的問題還存在實質上的問題就是說無法保證數據的同一性作為對象型保存的值與作為原始類型而保存的值完全不同即便改變了原始類型的值也不會反映到原來的int型數據
  
  C#利用Boxing(裝箱)解決的只是一部分
  
  這一問題並非是Java特有的比如作為與Java類似的語言為用戶熟知的C#也存在相同的問題C#利用稱為Boxing的方法部分地解決了這個問題但是所解決的也只是可以不寫多余代碼的部分內存問題和同一性問題仍舊存在
  
  即便C#intdouble和char等數據類型也無法作為對象進行處理這些數據類型與Java的原始類型相同也是數值型變量
  
  C#可以將其值代入到對象中LIST 中顯示了具體的代碼已經將int型的值代入了對象型變量此時先進行裝箱之後就開始悄悄地把基本數據類型的數據轉換成對象型數據在內存堆區中確保相應的內存然後將數值型數據保存這裡(圖對象型變量引用的就是這些數據
   
  LIST ●執行裝箱的C#代碼將數值直接代入對象中運行代碼後輸出也就是說變量a和o沒有同一性(點擊放大)
   
  圖●C#中的裝箱法對存放於內存堆棧區中的int型結構體(structs)裝箱時就會悄悄地在內存堆區中生成對象因此就無法確保與初始值的匹配性(點擊放大)
  筆者利用裝箱法用C#試著寫了一段與在Java的Vector矢量類中保存數值類似的代碼(LIST 雖然ArrayList類要引數中提取對象型變量但這裡由於通過直接int型變量因此代碼非常整潔
  
  不過並沒有解決多余的內存消耗和數值的同一性問題因為只是單純地實現了自動向對象的轉換(圖
   
  LIST ●與LIST 起相同作用的C#代碼由於具有裝箱法因此可以直接向ArrayList中追加數值
  
  圖●利用Java和C#將int型變量轉換成對象的方法盡管內部處理基本相同但C#的特點是隱式轉換
  如果考慮到實用也算得上是優點
  
  從上述所講來看就會生出這樣的疑問為什麼最新的Java和C#語言還存在著這樣的問題呢?實際上這是因為對其性能的重視
  
  由於原始數據型數據在編程時使用得最多因此利用能夠對其進行快速處理的原始類型性能就會提高而對象型數據在生成對象以及使用位置信息去引用內存堆區中的數據時則會產生一定的開銷另一個問題是內存堆區如果全部是對象型比如只要執行簡單的for循環語句就會在內存堆區中生成大量的對象由於內存堆區的消耗速度就會急劇上升並且頻繁地進行資源回收處理因此性能就會降低
  
  Java和C#是考慮到性能問題才生成原始數據型數據的因此並不能說是純粹的面向對象語言也許可以說是考慮到實用性的穩妥做法吧(記者大森 敏行八木 玲子)  

From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19244.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.