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

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

java筆試題(5)

2019-11-14 20:59:08
字體:
來源:轉載
供稿:網友
java筆試題(5)

1.Comparable和Comparator接口是干什么的?列出它們的區別。

Java提供了只包含一個compareTo()方法的Comparable接口。這個方法可以個給兩個對象排序。具體來說,它返回負數,0,正數來表明輸入對象小于,等于,大于已經存在的對象。

Java提供了包含compare()和equals()兩個方法的Comparator接口。compare()方法用來給兩個輸入參數排序,返回負數,0,正數表明第一個參數是小于,等于,大于第二個參數。equals()方法需要一個對象作為參數,它用來決定輸入參數是否和comparator相等。只有當輸入參數也是一個comparator并且輸入參數和當前comparator的排序結果是相同的時候,這個方法才返回true。

2.下面的代碼片段中,行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的代碼中,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命令都是查看編譯后的代碼(例如,字節碼)的利器。

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

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

4.下面哪些是發生在編譯時,運行時,或者兩者都有?

1

  • 方法重載:這個是發生在編譯時的。方法重載也被稱為編譯時多態,因為編譯器可以根據參數的類型來選擇使用哪個方法。
    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,這個功能已經是編譯器的一部分了。
    public class MyTest{    @Test     public void testEmptyness( ){         org.junit.Assert.assertTrue(getList( ).isEmpty( ));     }      private List getList( ){        //implemenation goes here     }}
    @Test是JUnit框架用來在運行時通過反射來決定調用測試類的哪個(些)方法的注解。
    @Test (timeout=100)public void testTimeout( ) {    while(true);   //infinite loop}
    如果運行時間超過100ms的話,上面的測試用例就會失敗。
    @Test (expected=IndexOutOfBoundsException.class)public void testOutOfBounds( ) {       new ArrayList<Object>( ).get(1);}
    如果上面的代碼在運行時沒有拋出IndexOutOfBoundsException或者拋出的是其他的異常的話,那么這個用例就會失敗。用戶自定義的注解可以在運行時通過Java反射API里新增的AnnotatedElement和”Annotation”元素接口來處理。
  • 異常(Exception):你可以使用運行時異常或者編譯時異常。
  • 運行時異常(RuntimeException)也稱作未檢測的異常(unchecked exception),這表示這種異常不需要編譯器來檢測。RuntimeException是所有可以在運行時拋出的異常的父類。一個方法除要捕獲異常外,如果它執行的時候可能會拋出RuntimeException的子類,那么它就不需要用throw語句來聲明拋出的異常。

    例如:NullPointerException,ArrayIndexOutOfBoundsException,等等

  • 受檢查異常(checked exception)都是編譯器在編譯時進行校驗的,通過throws語句或者try{}cathch{} 語句塊來處理檢測異常。編譯器會分析哪些異常會在執行一個方法或者構造函數的時候拋出。
  • 面向切面的編程(aspect Oriented Programming-AOP):切面可以在編譯時,運行時或,加載時或者運行時織入。
  • 編譯期:編譯期織入是最簡單的方式。如果你擁有應用的代碼,你可以使用AOP編譯器(例如,ajc – AspectJ編譯器)對源碼進行編譯,然后輸出織入完成的class文件。AOP編譯的過程包含了waver的調用。切面的形式可以是源碼的形式也可以是二進制的形式。如果切面需要針對受影響的類進行編譯,那么你就需要在編譯期織入了。
  • 編譯后:這種方式有時候也被稱為二進制織入,它被用來織入已有的class文件和jar文件。和編譯時織入方式相同,用來織入的切面可以是源碼也可以是二進制的形式,并且它們自己也可以被織入切面。
  • 裝載期:這種織入是一種二進制織入,它被延遲到JVM加載class文件和定義類的時候。為了支持這種織入方式,需要顯式地由運行時環境或者通過一種“織入代理(weaving agent)“來提供一個或者多個“織入類加載器(weaving class loader)”。
  • 運行時:對已經加載到JVM里的類進行織入
  • 繼承 – 發生在編譯時,因為它是靜態的
  • 代理或者組合 – 發生在運行時,因為它更加具有動態性和靈活性。

    5.你能夠通過實例來區別編譯期繼承和運行時繼承,以及指出Java支持哪種嗎?

    “繼承”表示動作和屬性從一個對象傳遞到另外一個對象的場景。Java語言本身只支持編譯期繼承,它是通過“extends”關鍵字來產生子類的方式實現的,如下所示:

    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()方法的調用會返回“Parent is called,Child is Called”,因為,子類的調用繼承了父類的“Parenet is called”。關鍵字“super”是用來調用“Parent”類的方法。運行時繼承表示在運行時構建父/子類關系。Java語言本身不支持運行時繼承,但是有一種替代的方案叫做“代理”或者“組合”,它表示在運行時組件一個層次對象的子類。這樣可以模擬運行時繼承的實現。在Java里,代理的典型實現方式如下:

    public class Parent {    public String saySomething( ) {          return “Parent is called”;    }} public class Child  {     public String saySomething( ) {          return new Parent( ).saySomething( ) +  “, Child is called”;    }}

    子類代理了父類的調用。組合可以按照下面的方式來實現:

    public class Child  {     private Parent parent = null;      public Child( ){          this.parent = new Parent( );     }      public String saySomething( ) {          return this.parent.saySomething( ) +  “, Child is called”;    }}

    6.Java中的volatile 變量是什么?

    volatile是一個特殊的修飾符,只有成員變量才能使用它。在Java并發程序缺少同步類的情況下,多線程對成員變量的操作對其它線程是透明的。volatile變量可以保證下一個讀取操作會在前一個寫操作之后發生。

    7.什么是FutureTask?

    在Java并發程序中FutureTask表示一個可以取消的異步運算。它有啟動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能取回,如果運算尚未完成get方法將會阻塞。一個FutureTask對象可以對調用了Callable和Runnable的對象進行包裝,由于FutureTask也是調用了Runnable接口所以它可以提交給Executor來執行。

    8.Java中interrupted 和 isInterrupted方法的區別?

    interrupted() 和 isInterrupted()的主要區別是前者會將中斷狀態清除而后者不會。Java多線程的中斷機制是用內部標識來實現的,調用Thread.interrupt()來中斷一個線程就會設置中斷標識為true。當中斷線程調用靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。而非靜態方法isInterrupted()用來查詢其它線程的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何拋出InterruptedException異常的方法都會將中斷狀態清零。無論如何,一個線程的中斷狀態有有可能被其它線程調用中斷來改變。

    9.如果你提交任務時,線程池隊列已滿。會時發會生什么?

    這個問題問得很狡猾,許多程序員會認為該任務會阻塞直到線程池隊列有空位。事實上如果一個任務不能被調度執行那么ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException異常。

    10.Java線程池中submit() 和 execute()方法有什么區別?

    兩個方法都可以向線程池提交任務,execute()方法的返回類型是void,它定義在Executor接口中, 而submit()方法可以返回持有計算結果的Future對象,它定義在ExecutorService接口中,它擴展了Executor接口,其它線程池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。

    11.volatile 變量和 atomic 變量有什么不同?

    首先,volatile 變量和 atomic 變量看起來很像,但功能卻不一樣。Volatile變量可以確保先行關系,即寫操作會發生在后續的讀操作之前, 但它并不能保證原子性。例如用volatile修飾count變量那么 count++ 操作就不是原子性的。而AtomicInteger類提供的atomic方法可以讓這種操作具有原子性如getAndIncrement()方法會原子性的進行增量操作把當前值加一,其它數據類型和引用變量也可以進行相似操作。

    12.如果同步塊內的線程拋出異常會發生什么?

    這個問題坑了很多Java程序員,若你能想到鎖是否釋放這條線索來回答還有點希望答對。無論你的同步塊是正常還是異常退出的,里面的線程都會釋放鎖,所以對比鎖接口我更喜歡同步塊,因為它不用我花費精力去釋放鎖,該功能可以在finally block里釋放鎖實現。

    我是天王蓋地虎的分割線


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 陆河县| 宜兰市| 社旗县| 武隆县| 磐石市| 合江县| 天镇县| 西畴县| 新宁县| 聊城市| 吉木萨尔县| 梓潼县| 肃南| 辉县市| 满城县| 南澳县| 博野县| 辽阳县| 昭平县| 宜兰市| 翁牛特旗| 资兴市| 长葛市| 黄冈市| 确山县| 南阳市| 漳州市| 青州市| 建昌县| 托里县| 永福县| 城口县| 梁山县| 巴马| 云龙县| 阜城县| 七台河市| 金川县| 长治县| 巨鹿县| 德格县|