亚洲精品中文字幕无乱码_久久亚洲精品无码AV大片_最新国产免费Av网址_国产精品3级片

java語言

Java 問答面試題

時(shí)間:2024-09-03 10:14:35 java語言 我要投稿
  • 相關(guān)推薦

Java 問答面試題

  引導(dǎo)語:應(yīng)聘Java相關(guān)崗位的工作都會(huì)面對(duì)怎么樣的考題考察自己呢?以下是小編整理的Java 問答面試題,歡迎參考閱讀!

Java 問答面試題

  Q.下面的代碼片段中,行A和行B所標(biāo)識(shí)的代碼有什么區(qū)別呢?

  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的值是在編譯期計(jì)算的,行B則是在運(yùn)行時(shí)計(jì)算的。如果你使用Java反編譯器(例如,jd-gui)來反編譯ConstantFolding.class文件的話,那么你就會(huì)從下面的結(jié)果里得到答案。

  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編譯器使用的優(yōu)化技術(shù)。由于final變量的值不會(huì)改變,因此就可以對(duì)它們優(yōu)化。Java反編譯器和javap命令都是查看編譯后的代碼(例如,字節(jié)碼)的利器。

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

  A.Java里的泛型是在編譯時(shí)構(gòu)造的,可以通過查看編譯后的class文件來理解泛型,也可以通過查看它來解決泛型相關(guān)的問題。

  Q.下面哪些是發(fā)生在編譯時(shí),運(yùn)行時(shí),或者兩者都有?

  A.

  方法重載:這個(gè)是發(fā)生在編譯時(shí)的。方法重載也被稱為編譯時(shí)多態(tài),因?yàn)榫幾g器可以根據(jù)參數(shù)的類型來選擇使用哪個(gè)方法。

  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”);

  它會(huì)根據(jù)傳入的參數(shù)是字符串常量,生成調(diào)用#1方法的字節(jié)碼

  方法覆蓋:這個(gè)是在運(yùn)行時(shí)發(fā)生的。方法重載被稱為運(yùn)行時(shí)多態(tài),因?yàn)樵诰幾g期編譯器不知道并且沒法知道該去調(diào)用哪個(gè)方法。JVM會(huì)在代碼運(yùn)行的時(shí)候做出決定。

  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);

  }

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

  泛型(又稱類型檢驗(yàn)):這個(gè)是發(fā)生在編譯期的。編譯器負(fù)責(zé)檢查程序中類型的正確性,然后把使用了泛型的代碼翻譯或者重寫成可以執(zhí)行在當(dāng)前JVM上的非泛型代碼。這個(gè)技術(shù)被稱為“類型擦除“。換句話來說,編譯器會(huì)擦除所有在尖括號(hào)里的類型信息,來保證和版本1.4.0或者更早版本的JRE的兼容性。

  ListmyList = new ArrayList(10);

  編譯后成為了:

  List myList = new ArrayList(10);

  注解(Annotation):你可以使用運(yùn)行時(shí)或者編譯時(shí)的注解。

  public class B extends A {

  @Override

  public int compute(int input){  //method #4

   return 4 * input;

  }

  }

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

  public class MyTest{

  @Test

  public void testEmptyness( ){

   org.junit.Assert.assertTrue(getList( ).isEmpty( ));

  }

  private List getList( ){

   //implemenation goes here

  }

  }

  @Test是JUnit框架用來在運(yùn)行時(shí)通過反射來決定調(diào)用測試類的哪個(gè)(些)方法的注解。

  @Test (timeout=100)

  public void testTimeout( ) {

  while(true); //infinite loop

  }

  如果運(yùn)行時(shí)間超過100ms的話,上面的測試用例就會(huì)失敗。

  @Test (expected=IndexOutOfBoundsException.class)

  public void testOutOfBounds( ) {

   new ArrayList

  ( ).get(1);

  }

  如果上面的代碼在運(yùn)行時(shí)沒有拋出IndexOutOfBoundsException或者拋出的是其他的異常的話,那么這個(gè)用例就會(huì)失敗。用戶自定義的注解可以在運(yùn)行時(shí)通過Java反射API里新增的AnnotatedElement和”Annotation”元素接口來處理。

  異常(Exception):你可以使用運(yùn)行時(shí)異;蛘呔幾g時(shí)異常。

  運(yùn)行時(shí)異常(RuntimeException)也稱作未檢測的異常(unchecked exception),這表示這種異常不需要編譯器來檢測。RuntimeException是所有可以在運(yùn)行時(shí)拋出的異常的父類。一個(gè)方法除要捕獲異常外,如果它執(zhí)行的時(shí)候可能會(huì)拋出RuntimeException的子類,那么它就不需要用throw語句來聲明拋出的異常。

  例如:NullPointerException,ArrayIndexOutOfBoundsException,等等

  受檢查異常(checked exception)都是編譯器在編譯時(shí)進(jìn)行校驗(yàn)的,通過throws語句或者try{}cathch{} 語句塊來處理檢測異常。編譯器會(huì)分析哪些異常會(huì)在執(zhí)行一個(gè)方法或者構(gòu)造函數(shù)的時(shí)候拋出。

  面向切面的編程(Aspect Oriented Programming-AOP):切面可以在編譯時(shí),運(yùn)行時(shí)或,加載時(shí)或者運(yùn)行時(shí)織入。

  編譯期:編譯期織入是最簡單的方式。如果你擁有應(yīng)用的代碼,你可以使用AOP編譯器(例如,ajc – AspectJ編譯器)對(duì)源碼進(jìn)行編譯,然后輸出織入完成的class文件。AOP編譯的過程包含了waver的調(diào)用。切面的形式可以是源碼的形式也可以是二進(jìn)制的形式。如果切面需要針對(duì)受影響的類進(jìn)行編譯,那么你就需要在編譯期織入了。

  編譯后:這種方式有時(shí)候也被稱為二進(jìn)制織入,它被用來織入已有的class文件和jar文件。和編譯時(shí)織入方式相同,用來織入的切面可以是源碼也可以是二進(jìn)制的形式,并且它們自己也可以被織入切面。

  裝載期:這種織入是一種二進(jìn)制織入,它被延遲到JVM加載class文件和定義類的時(shí)候。為了支持這種織入方式,需要顯式地由運(yùn)行時(shí)環(huán)境或者通過一種“織入代理(weaving agent)“來提供一個(gè)或者多個(gè)“織入類加載器(weaving class loader)”。

  運(yùn)行時(shí):對(duì)已經(jīng)加載到JVM里的類進(jìn)行織入

  繼承 – 發(fā)生在編譯時(shí),因?yàn)樗庆o態(tài)的

  代理或者組合 – 發(fā)生在運(yùn)行時(shí),因?yàn)樗泳哂袆?dòng)態(tài)性和靈活性。

  Q.你有沒有聽說過“組合優(yōu)于繼承”這樣的說法呢?如果聽說過的話,那么你是怎么理解的呢?

  A.繼承是一種多態(tài)工具,而不是一種代碼復(fù)用工具。有些開發(fā)者喜歡用繼承的方式來實(shí)現(xiàn)代碼復(fù)用,即使是在沒有多態(tài)關(guān)系的情況下。是否使用繼承的規(guī)則是繼承只能用在類之間有“父子”關(guān)系的情況下。

  不要僅僅為了代碼復(fù)用而繼承。當(dāng)你使用組合來實(shí)現(xiàn)代碼復(fù)用的時(shí)候,是不會(huì)產(chǎn)生繼承關(guān)系的。過度使用繼承(通過“extends”關(guān)鍵字)的話,如果修改了父類,會(huì)損壞所有的子類。這是因?yàn)樽宇惡透割惖木o耦合關(guān)系是在編譯期產(chǎn)生的。

  不要僅僅為了多態(tài)而繼承。如果你的類之間沒有繼承關(guān)系,并且你想要實(shí)現(xiàn)多態(tài),那么你可以通過接口和組合的方式來實(shí)現(xiàn),這樣不僅可以實(shí)現(xiàn)代碼重用,同時(shí)也可以實(shí)現(xiàn)運(yùn)行時(shí)的靈活性。

  這就是為什么四人幫(Gang of Four)的設(shè)計(jì)模式里更傾向于使用組合而不是繼承的原因。面試者會(huì)在你的答案里著重關(guān)注這幾個(gè)詞語——“耦合”,“靜態(tài)還是動(dòng)態(tài)”,以及“發(fā)生在編譯期還是運(yùn)行時(shí)”。運(yùn)行時(shí)的靈活性可以通過組合來實(shí)現(xiàn),因?yàn)轭惪梢栽谶\(yùn)行時(shí)動(dòng)態(tài)地根據(jù)一個(gè)結(jié)果有條件或者無條件地進(jìn)行組合。但是繼承卻是靜態(tài)的。

  Q.你能夠通過實(shí)例來區(qū)別編譯期繼承和運(yùn)行時(shí)繼承,以及指出Java支持哪種嗎?

  A.“繼承”表示動(dòng)作和屬性從一個(gè)對(duì)象傳遞到另外一個(gè)對(duì)象的場景。Java語言本身只支持編譯期繼承,它是通過“extends”關(guān)鍵字來產(chǎn)生子類的方式實(shí)現(xiàn)的,如下所示:

  public class Parent {

  public String saySomething( ) {

    return “Parent is called”;

  }

  }

  public class Child extends Parent {

  @Override

  public String saySomething( ) {

    return super.saySomething( ) + “, Child is called”;

  }

  }

  “Child”類的saySomething()方法的調(diào)用會(huì)返回“Parent is called,Child is Called”,因?yàn),子類的調(diào)用繼承了父類的“Parenet is called”。關(guān)鍵字“super”是用來調(diào)用“Parent”類的方法。運(yùn)行時(shí)繼承表示在運(yùn)行時(shí)構(gòu)建父/子類關(guān)系。Java語言本身不支持運(yùn)行時(shí)繼承,但是有一種替代的方案叫做“代理”或者“組合”,它表示在運(yùn)行時(shí)組件一個(gè)層次對(duì)象的子類。這樣可以模擬運(yùn)行時(shí)繼承的實(shí)現(xiàn)。在Java里,代理的典型實(shí)現(xiàn)方式如下:

  public class Parent {

  public String saySomething( ) {

    return “Parent is called”;

  }

  }

  public class Child {

  public String saySomething( ) {

    return new Parent( ).saySomething( ) + “, Child is called”;

  }

  }

  子類代理了父類的調(diào)用。組合可以按照下面的方式來實(shí)現(xiàn):

  public class Child {

  private Parent parent = null;

  public Child( ){

    this.parent = new Parent( );

  }

  public String saySomething( ) {

    return this.parent.saySomething( ) + “, Child is called”;

  }

  }

【Java 問答面試題】相關(guān)文章:

Java面試題(精選)12-04

Java原理面試題03-19

Java基礎(chǔ)面試題集錦12-02

Java基礎(chǔ)語法面試題03-19

最新2016年Java精選面試題11-17

經(jīng)常被遺忘的Java面試題03-20

Java開發(fā)崗位面試題匯總03-18

華為Java程序員面試題12-04

高級(jí)Java多線程面試題及回答11-30