熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

Java進階:提高代碼質量及字節碼如何防止內存錯誤[2]

2013-11-23 19:37:55  來源: Java核心技術 

  分析字節碼提升代碼質量

  Java字節碼的內存和安全保護無論我們是否注意都是存在地那麼我們為什麼還費心查看字節碼呢?在很多情況下知道編譯器如何將你的代碼轉換為字節碼可以幫助你寫出更高效的代碼而且在某些情況下可以防止不易發覺的錯誤考慮下面的例子

  //返回 str+str 的串連
  String concat(String str String str) {
   return str + str;
  }
  //將 str 附加到 str
  void concat(StringBuffer str String str) {
   strappend(str);
  }

  猜猜每個方法需要多少個方法調用現在編譯這些方法並且運行javap你會得到類似下面的輸出

  Method javalangString concat(javalangString javalangString)
   new #
   dup
   invokespecial #
   aload_
   invokevirtual #
   aload_
   invokevirtual #
   invokevirtual #
   areturn
  Method void concat(javalangStringBuffer javalangString)
   aload_
   aload_
   invokevirtual #
   pop
   return

  concat方法執行了個方法調用s: new invokespecial和三個invokevirtuals這比concat方法執行了更多的工作後者只執行了一個invokevirtual調用大多Java程序員已經得到過警告因為String是不可變的而使用StringBuffer進行字符串連接效率更高使用javap分析這個使得這點變得很生動如果你不能肯定兩個語言構造在性能上是否相等你應該使用javap分析字節碼然而對justintime (JIT)編譯器要小心因為JIT編譯器將字節碼重新編譯為本機代碼而能執行一些javap不能揭示的附加優化除非你有你的虛擬機的源代碼否則你應該補充你的字節碼的基准性能分析

  最後的一個范例展示了檢查字節碼如何幫助防止程序中的錯誤像下面那樣創建兩個類確保它們在獨立的文件中

  public class ChangeALot {
   public static final boolean debug=false;
   public static boolean log=false;
  }

  public class EternallyConstant {
   public static void main(String [] args) {
    Systemoutprintln(EternallyConstant beginning execution);
    if (ChangeALotdebug)
    Systemoutprintln(Debug mode is on);
    if (ChangeALotlog)
    Systemoutprintln(Logging mode is on);
   }
  }

  如果你運行EternallyConstant你會得到信息

  EternallyConstant beginning execution

  現在試著編輯ChangeALot修改debug和log變量的值為true(兩個都為true)只重新編譯ChangeALot再次運行EternallyConstant你將看到下面的輸出

  EternallyConstant beginning execution

  Logging mode is on

  debug變量怎麼了?即使你將debug設置為true信息Debug mode is on並沒有出現答案在字節碼中對 EternallyConstant運行javap你會看到

  Method void main(javalangString[])
   getstatic #
   ldc #
   invokevirtual #
   getstatic #
   ifeq
   getstatic #
   ldc #
   invokevirtual #
   return

  驚奇吧!在log成員上有一個ifeq檢查而代碼根本沒有檢查debug成員因為debug成員被標記為final類型編譯器知道debug成員在運行時永遠不會改變因此它通過移除if聲明進行優化這確實是一個非常有用的優化因為它允許你在程序中嵌入調試代碼而在將它設置為false時不用付出運行時的代價不幸的是這個優化能夠導致主要的編譯時混亂如果你改變一個final成員你必須記住重新編譯任何可能引用該成員的類這是因為這個reference可能已經經過優化了Java開發環境不能總是發現這個微妙的相關性一些能導致非常奇怪的錯誤因此古老的C++格言對於java環境仍然有效When in doubt rebuild all(有疑問重新編譯所有的代碼)

  知道一些字節碼的知識對於使用java編程的程序員都是有價值的javap工具使得查看字節碼很容易有時候使用javap檢查你的代碼以期提高性能和捕獲特殊的不易察覺的錯誤時是沒有用的

[]  []  


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