Java 面試題問與答:編譯時與運行時

在開發和設計的時候,我們需要考慮編譯時運行時以及構建時這三個概念。理解這幾個概念可以更好地幫助你去了解一些基本的原理。下面是初學者晉級中級水平需要知道的一些問題。

Q.下面的代碼片段中,行A和行B所標識的代碼有什麼區別呢?

public class ConstantFolding {
 
    static final  int number1 = 5;
 
    static final  int number2 = 6;
 
    static int number3 = 5;
 
    static int number4= 6;
 
    public static void main(String[ ] args) {
 
          int product1 = number1 * number2;         //line A
 
          int product2 = number3 * number4;         //line B
 
    }
 
}

A.在行A的代碼中,product的值是在編譯期計算的,行B則是在運行時計算的。如果你使用Java反編譯器(例如,jd-gui)來反編譯ConstantFolding.class文件的話,那麼你就會從下面的結果裏得到答案。

public class ConstantFolding
{
  static final int number1 = 5;
  static final int number2 = 6;
  static int number3 = 5;
  static int number4 = 6;
 
  public static void main(String[ ] args)
  {
      int product1 = 30;
      int product2 = number3 * number4;
  }
}

常量摺疊是一種Java編譯器使用的優化技術。由於final變量的值不會改變,因此就可以對它們優化。Java反編譯器和javap命令都是查看編譯後的代碼(例如,字節碼)的利器。

 

Q.你能想出除了代碼優化外,在什麼情況下,查看編譯過的代碼是很有幫助的?

A.Java裏的泛型是在編譯時構造的,可以通過查看編譯後的class文件來理解泛型,也可以通過查看它來解決泛型相關的問題。

方法重載:這個是發生在編譯時的。方法重載也被稱爲編譯時多態,因爲編譯器可以根據參數的類型來選擇使用哪個方法。
public class {
     public static void evaluate(String param1);  // method #1
     public static void evaluate(int param1);   // method #2
}

如果編譯器要編譯下面的語句的話:
evaluate(“My Test Argument passed to param1”);

它會根據傳入的參數是字符串常量,生成調用#1方法的字節碼.

方法覆蓋:這個是在運行時發生的。方法覆蓋被稱爲運行時多態,因爲在編譯期編譯器不知道並且沒法知道該去調用哪個方法。JVM會在代碼運行的時候做出決定。

public class A {
   public int compute(int input) {          //method #3
        return 3 * input;
   }       
}
 
public class B extends A {
   @Override
   public int compute(int input) {          //method #4
        return 4 * input;
   }       
}
子類B中的compute(..)方法重寫了父類的compute(..)方法。如果編譯器遇到下面的代碼:
public int evaluate(A reference, int arg2)  {
     int result = reference.compute(arg2);
}

編譯器是沒法知道傳入的參數reference的類型是A還是B。因此,只能夠在運行時,根據賦給輸入變量“reference”的對象的類型(例如,A或者B的實例)來決定調用方法#3還是方法#4.

泛型(又稱類型檢驗):這個是發生在編譯期的。編譯器負責檢查程序中類型的正確性,然後把使用了泛型的代碼翻譯或者重寫成可以執行在當前JVM上的非泛型代碼。這個技術被稱爲“類型擦除“。換句話來說,編譯器會擦除所有在尖括號裏的類型信息,來保證和版本1.4.0或者更早版本的JRE的兼容性。

List<String> myList = new ArrayList<String>(10);

編譯後成爲了:

List myList = new ArrayList(10);

註解(Annotation):你可以使用運行時或者編譯時的註解。
public class B extends A {
   @Override
    public int compute(int input){      //method #4
        return 4 * input;
    }       
}

@Override是一個簡單的編譯時註解,它可以用來捕獲類似於在子類中把toString()寫成tostring()這樣的錯誤。在Java 5中,用戶自定義的註解可以用註解處理工具(Anotation Process Tool ——APT)在編譯時進行處理。到了Java 6,這個功能已經是編譯器的一部分了。


本文轉載自:http://www.importnew.com/1796.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章