JavaSE常用API

  • 2019 年 11 月 10 日
  • 筆記

  1、Math.round(11.5)等於多少?Math.round(-11.5)又等於多少?

    Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11.四捨五入的原理是在參數上加0.5然後進行取整。

  

  2、switch是否能作用在byte上,是否能作用在long上,是否能作用在String上?

    Java5以前switch(expr)中,expr只能是byte、short、char、int。從Java5開始,Java引入了枚舉類型,expr也可以是enum類型

    從Java7開始expr還可以是字符串String,但是長整型(long)在目前所有的版本中都是不可以的

  

  3、String、StringBuilder、StringBuffer的區別?

    Java平台提供了兩種類型的字符串:String和StringBuffer/StringBuilder,它們都可以儲存和操作字符串,區別如下。

      1)String(最終類)是只讀字符串,也就意味這String引用的字符串內容是不可改變的。初學者可能會有這樣的誤解:

          String str = “abc”;

          str = “bcd”;

        如上、字符串str明明是可以改變的呀,其實不然,str僅僅是一個引用對象,它指向一個字符串對象“abc”。第二行代碼的含義是讓str重新指向了一個新的字符串“bcd”對象,而“abc”對象並沒有任何改變,只不過該對象已經成為了一個不可及對象(GC將要回收的對象)罷了。

      2)StringBuilder/StringBuffer表示的字符串對象可以直接進行修改。

      3)StringBuilder是Java5引入的,它和StringBuffer的方法完全相同,區別在於它是在單線程環境下使用的,因為它的所有方法都沒有被synchronized修飾,因此它的小輪理論上也要比StringBuffer要高。

 

   4、什麼情況下用“+”運算符進行字符串連接比調用StringBuilder/StringBuffer對象的append方法連接字符串性能更好?

    字符串是Java程序最常用的數據結構之一。在Java中String類已經重載了“+”。也就是說,字符串可以直接使用”+“進行連接,如下面代碼所示:

    String s = “abc” + “def”;

    但這樣做真的好嗎?當然,這個問題不能簡單的回答yes or no 。要根據具體情況來定。在Java中提供了一個StringBuilder類(Java5以後版本提供),這個類也可以起到”+“的作用。那麼我們應該用哪個呢?

    下面我們先看看如下的代碼:

      package string ;

        public class TestSimplePlus{

          public static void main(String[] args){

              String s = “abc”;

              String ss = “ok” + s + “xyz” + 5;

              System.out.println(ss);

            }

        }

    上面的代碼將會輸出正確的結果。從表面看,對字符串和整型使用”+“並沒有什麼區別,但事實真的如此嗎?下面讓我們開看看這段代碼的本質。

    我們首先使用反編譯工具(如 jdk 帶的 javap、或 jad)將 TestSimplePlus 反編譯成 Java Byte Code,其中的奧秘就一目了然了。在本文將使用 jad 來反編譯,命令如下:jad -o -a -s d.java TestSimplePlus.class
      反編譯後的代碼如下:

      

  讀者可能看到上面的 Java 位元組碼感到迷糊,不過大家不必擔心。本文的目的並不是講解 Java Byte Code,因此,並不用了解具體的位元組碼的含義。使用 jad 反編譯的好處之一就是可以同時生成位元組碼和源代碼。這樣可以進行對照研究。從上面的代碼很容易看出,雖然在源程序中使用了”+”,但在編譯時仍然將”+”轉換成 StringBuilder。因此,我們可以得出結論,在 Java 中無論使用何種方式進行字符串連接,實際上都使用的是 無論使用何種方式進行字符串連接,實際上都使用的是 StringBuilder 。那麼是不是可以根據這個結論推出使用”+”和 StringBuilder 的效果是一樣的呢?這個要從兩個方面的解釋。如果從運行結果來解釋,那麼”+”和 StringBuilder 是完全等效的。但如果從運行效率和資源消耗方面看,那它們將存在很大的區別。當然,如果連接字符串行表達式很簡單(如上面的順序結構),那麼”+”和 StringBuilder 基本是一樣的,但如果結構比較複雜,如使用循環來連接字符串,那麼產生的 Java Byte Code 就會有很大的區別。先讓我們看看如下的代碼

    

    大家可以看到,雖然編譯器將“+”轉換成了StringBuilder,但創建StringBuilder對象的位置卻在for語句內部。這就意味着每執行一次循環,就會創建一個StringBuilder對象(對於本例來說,是創建了10個StringBuilder對象),雖然Java有垃圾回收器,但這個回收器的工作時間是不定的。如果不斷產生這樣的垃圾,那麼仍然會佔用大量的資源。解決這個問題的方法就是在程序中直接使用StringBuilder來連接字符串,代碼如下:

    

    上面代碼反編譯後的結果如下所示:

    

    從上面的反編譯結果可以看出,創建StringBuilder的代碼被放在了for語句外。雖然這樣處理在源程序中看起來複雜,但卻換來了更好的效率,同樣的消耗的資源也更少了。

    4在使用StringBuilder時要注意,盡量不要“+”和StringBuilder混着用,否則會創建更多的StringBuilder對象,如下面代碼所示:

    

    改成如下形式:

    

    則反編譯後的結果如下:

    

    從上面的代碼可以看出,Java編譯器將“+”編譯成了StringBuilder,這樣for語句每循環一次,又創建了一個StringBuilder對象。

    如果將上面的代碼在JDK1.4下編譯,必須將StringBuilder改為StringBuffer,而JDK1.4將“+”轉換為StringBuffer。StringBuffer和StringBuilder的功能基本一樣,只是StringBuffer是線程安全的,而StringBuilder不是線程安全的。因此,StringBuilder的效率會更高。

    

    6、請說出下面程序的輸出

      

    補充:解答上面的面試題需要知道如下兩個知識點:

      1)String對象的intern()方法會得到字符串對象在常量池對應的版本中的引用(如果常量池中有一個字符串與String對象的equals結果是true),如果常量池中沒有對應的字符串,則該字符串被添加到常量池中,然後返回常量池中字符串的引用;

      2)字符串的+操作其本質是創建了StringBuilder對象進行append操作,然後將拼接後的StringBuilder對象用toString方法處理成為String對象,這一點可以用javap -c StringEqualTest.class命令獲得class文件對應的JVM位元組碼指令就可以看出來。