天天看點

[ Java面試題 ]基礎篇之二

1、String s = new String("xyz");建立了幾個StringObject?是否可以繼承String類?

  兩個或一個都有可能,”xyz”對應一個對象,這個對象放在字元串常量緩沖區,常量”xyz”不管出現多少遍,都是緩沖區中的那一個。NewString每寫一遍,就建立一個新的對象,它使用常量”xyz”對象的内容來建立出一個新String對象。如果以前就用過’xyz’,那麼這裡就不會建立”xyz”了,直接從緩沖區拿,這時建立了一個StringObject;但如果以前沒有用過"xyz",那麼此時就會建立一個對象并放入緩沖區,這種情況它建立兩個對象。至于String類是否繼承,答案是否定的,因為String預設final修飾,是不可繼承的。

2、String和StringBuffer的差別

  JAVA平台提供了兩個類:String和StringBuffer,它們可以儲存和操作字元串,即包含多個字元的字元資料。這個String類提供了數值不可改變的字元串。而這個StringBuffer類提供的字元串可以進行修改。當你知道字元資料要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動态構造字元資料。

3、下面這條語句一共建立了多少個對象:String s="a"+"b"+"c"+"d";

對于如下代碼:

String s1 = "a";

String s2 = s1 + "b";

String s3 = "a" + "b";

System.out.println(s2 == "ab");

System.out.println(s3 == "ab");           

複制

第一條語句列印的結果為false,第二條語句列印的結果為true,這說明javac編譯可以對字元串常量直接相加的表達式進行優化,不必要等到運作期再去進行加法運算處理,而是在編譯時去掉其中的加号,直接将其編譯成一個這些常量相連的結果。

題目中的第一行代碼被編譯器在編譯時優化後,相當于直接定義了一個”abcd”的字元串,是以,上面的代碼應該隻建立了一個String對象。寫如下兩行代碼,

  String s ="a" + "b" +"c" + "d";

  System.out.println(s== "abcd");           

複制

最終列印的結果應該為true。

4、try {}裡有一個return語句,那麼緊跟在這個try後的finally{}裡的code會不會被執行,什麼時候被執行,在return前還是後?

  我們知道finally{}中的語句是一定會執行的,那麼這個可能正常脫口而出就是return之前,return之後可能就出了這個方法了,鬼知道跑哪裡去了,但更準确的應該是在return中間執行,請看下面程式代碼的運作結果:

public classTest {

    public static void main(String[]args) {

       System.out.println(newTest().test());;

    }

    static int test()
    {
       intx = 1;
       try
       {
          returnx;
       }
       finally
       {
          ++x;
       }

    }  

}           

複制

---------執行結果 ---------

1

運作結果是1,為什麼呢?主函數調用子函數并得到結果的過程,好比主函數準備一個空罐子,當子函數要傳回結果時,先把結果放在罐子裡,然後再将程式邏輯傳回到主函數。所謂傳回,就是子函數說,我不運作了,你主函數繼續運作吧,這沒什麼結果可言,結果是在說這話之前放進罐子裡的。

5、final, finally, finalize的差別。 

  final 用于聲明屬性,方法和類,分别表示屬性不可變,方法不可覆寫,類不可繼承。内部類要通路局部變量,局部變量必須定義成final類型。

  finally是異常處理語句結構的一部分,表示總是執行。

  finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,可以覆寫此方法提供垃圾收集時的其他資源回收,例如關閉檔案等。但是JVM不保證此方法總被調用

6、運作時異常與一般異常有何異同?

  異常表示程式運作過程中可能出現的非正常狀态,運作時異常表示虛拟機的通常操作中可能遇到的異常,是一種常見運作錯誤。java編譯器要求方法必須聲明抛出可能發生的非運作時異常,但是并不要求必須聲明抛出未被捕獲的運作時異常。

7、error和exception有什麼差別?

  error 表示恢複不是不可能但很困難的情況下的一種嚴重問題。比如說記憶體溢出。不可能指望程式能處理這樣的情況。exception表示一種設計或實作問題。也就是說,它表示如果程式運作正常,從不會發生的情況。

8、簡單說說Java中的異常處理機制的簡單原理和應用。

  異常是指java程式運作時(非編譯)所發生的非正常情況或錯誤,與現實生活中的事件很相似,現實生活中的事件可以包含事件發生的時間、地點、人物、情節等資訊,可以用一個對象來表示,Java使用面向對象的方式來處理異常,它把程式中發生的每個異常也都分别封裝到一個對象來表示的,該對象中包含有異常的資訊。

  Java對異常進行了分類,不同類型的異常分别用不同的Java類表示,所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個子類:

  Error和Exception,Error表示應用程式本身無法克服和恢複的一種嚴重問題,程式隻有奔潰了,例如,說記憶體溢出和線程死鎖等系統問題。

  Exception表示程式還能夠克服和恢複的問題,其中又分為系統異常和普通異常:

  系統異常是軟體本身缺陷所導緻的問題,也就是軟體開發人員考慮不周所導緻的問題,軟體使用者無法克服和恢複這種問題,但在這種問題下還可以讓軟體系統繼續運作或者讓軟體挂掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);

  普通異常是運作環境的變化或異常所導緻的問題,是使用者能夠克服的問題,例如,網絡斷線,硬碟空間不夠,發生這樣的異常後,程式不應該死掉。

java為系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續抛給上層調用方法處理,是以普通異常也稱為checked異常,而系統異常可以處理也可以不處理,是以,編譯器不強制用try..catch處理或用throws聲明,是以系統異常也稱為unchecked異常。

9、Java 中堆和棧有什麼差別?

  JVM 中堆和棧屬于不同的記憶體區域,使用目的也不同。棧常用于儲存方法幀和局部變量,而對象總是在堆上配置設定。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。

  棧:在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧記憶體中配置設定,當在一段代碼塊定義一個變量時,Java 就在棧中為這個變量配置設定記憶體空間,當超過變量的作用域後,Java 會自動釋放掉為該變量配置設定的記憶體空間,該記憶體空間可以立即被另作它用。

  堆:堆記憶體用來存放由 new 建立的對象和數組,在堆中配置設定的記憶體,由 Java 虛拟機的自動垃圾回收器來管理。在堆中産生了一個數組或者對象之後,還可以在棧中定義一個特殊的變量,讓棧中的這個變量的取值等于數組或對象在堆記憶體中的首位址,棧中的這個變量就成了數組或對象的引用變量,以後就可以在程式中使用棧中的引用變量來通路堆中的數組或者對象,引用變量就相當于是為數組或者對象起的一個名稱。

10、能将 int 強制轉換為 byte 類型的變量嗎?如果該值大于 byte 類型的範圍,将會出現什麼現象? 

  我們可以做強制轉換,但是 Java 中 int 是 32 位的,而 byte 是 8 位的,是以,如果強制轉化,int 類型的高 24 位将會被丢棄,因為byte 類型的範圍是從 -128 到 127。

11、a.hashCode() 有什麼用?與 a.equals(b) 有什麼關系?

  hashCode() 方法對應對象整型的 hash 值。它常用于基于 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關系特别緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具有相同的 hash code。

12、位元組流與字元流的差別

  要把一段二進制資料資料逐一輸出到某個裝置中,或者從某個裝置中逐一讀取一段二進制資料,不管輸入輸出裝置是什麼,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名為IO流,對應的抽象類為OutputStream和InputStream,不同的實作類就代表不同的輸入和輸出裝置,它們都是針對位元組進行操作的。

  計算機中的一切最終都是二進制的位元組形式存在。對于經常用到的中文字元,首先要得到其對應的位元組,然後将位元組寫入到輸出流。讀取時,首先讀到的是位元組,可是我們要把它顯示為字元,我們需要将位元組轉換成字元。由于這樣的需求很廣泛,Java專門提供了字元流包裝類。

  底層裝置永遠隻接受位元組資料,有時候要寫字元串到底層裝置,需要将字元串轉成位元組再進行寫入。字元流是位元組流的包裝,字元流則是直接接受字元串,它内部将串轉成位元組,再寫入底層裝置,這為我們向IO裝置寫入或讀取字元串提供了一點點友善。

  字元向位元組轉換時,要注意編碼的問題,因為字元串轉成位元組數組,其實是轉成該字元的某種編碼的位元組形式,讀取也是反之的道理。

13、什麼是java序列化,如何實作java序列化?或者請解釋Serializable接口的作用。

  我們有時候将一個java對象變成位元組流的形式傳出去或者從一個位元組流中恢複成一個java對象,例如,要将java對象存儲到硬碟或者傳送給網絡上的其他計算機,這個過程我們可以自己寫代碼去把一個java對象變成某個格式的位元組流再傳輸。

  但是,jre本身就提供了這種支援,我們可以調用OutputStream的writeObject方法來做,如果要讓java幫我們做,要被傳輸的對象必須實作serializable接口,這樣,javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實作Serializable接口,該接口是一個mini接口,其中沒有需要實作方法,implements Serializable隻是為了标注該對象是可被序列化的。

  例如,在web開發中,如果對象被儲存在了Session中,tomcat在重新開機時要把Session對象序列化到硬碟,這個對象就必須實作Serializable接口。如果對象要經過分布式系統進行網絡傳輸,被傳輸的對象就必須實作Serializable接口。

14、描述一下JVM加載class檔案的原理機制?

  JVM中類的裝載是由ClassLoader和它的子類來實作的,Java ClassLoader是一個重要的Java運作時系統元件。它負責在運作時查找和裝入類檔案的類。

15、heap和stack有什麼差別。

  java的記憶體分為兩類,一類是棧記憶體,一類是堆記憶體。棧記憶體是指程式進入一個方法時,會為這個方法單獨配置設定一塊私屬存儲空間,用于存儲這個方法内部的局部變量,當這個方法結束時,配置設定給這個方法的棧會釋放,這個棧中的變量也将随之釋放。

  堆是與棧作用不同的記憶體,一般用于存放不在目前方法棧中的那些資料,例如,使用new建立的對象都放在堆裡,是以,它不會随方法的結束而消失。方法中的局部變量使用final修飾後,放在堆中,而不是棧中。

16、GC是什麼?為什麼要有GC?

  GC是垃圾收集的意思(Gabage Collection),記憶體處理是程式設計人員容易出現問題的地方,忘記或者錯誤的記憶體回收會導緻程式或系統的不穩定甚至崩潰,Java提供的GC功能可以自動監測對象是否超過作用域進而達到自動回收記憶體的目的,Java語言沒有提供釋放已配置設定記憶體的顯示操作方法。

17、垃圾回收的優點和原理。并考慮2種回收機制。

  Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程式員最頭疼的記憶體管理的問題迎刃而解,它使得Java程式員在編寫程式的時候不再需要考慮記憶體管理。由于垃圾回收機制,Java中的對象不再有"作用域"的概念,隻有對象的引用才有"作用域"。

  垃圾回收可以有效的防止記憶體洩露,有效的使用可以使用的記憶體。垃圾回收器通常是作為一個單獨的低級别的線程運作,不可預知的情況下對記憶體堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程式員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。

  回收機制有分代複制垃圾回收和标記垃圾回收,增量垃圾回收。

18、垃圾回收器的基本原理是什麼?垃圾回收器可以馬上回收記憶體嗎?有什麼辦法主動通知虛拟機進行垃圾回收?

  對于GC來說,當程式員建立對象時,GC就開始監控這個對象的位址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式确定哪些對象是"可達的",哪些對象是"不可達的"。當GC确定一些對象為"不可達"時,GC就有責任回收這些記憶體空間。

  程式員可以手動執行System.gc(),通知GC運作,但是Java語言規範并不保證GC一定會執行。

19、Java 中,throw 和 throws 有什麼差別

  throw 用于抛出 java.lang.Throwable 類的一個執行個體化對象,意思是說你可以通過關鍵字 throw 抛出一個Exception,如: 

throw new IllegalArgumentException(“XXXXXXXXX″)           

複制

  而throws 的作用是作為方法聲明和簽名的一部分,方法被抛出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。

20、java中會存在記憶體洩漏嗎,請簡單描述。

  先解釋什麼是記憶體洩漏:所謂記憶體洩露就是指一個不再被程式使用的對象或變量一直被占據在記憶體中。java中有垃圾回收機制,它可以保證當對象不再被引用的時候,對象将自動被垃圾回收器從記憶體中清除掉。

  由于Java使用有向圖的方式進行垃圾回收管理,可以消除引用循環的問題,例如有兩個對象,互相引用,隻要它們和根程序不可達,那麼GC也是可以回收它們的。

  java中的記憶體洩露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發生記憶體洩露,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導緻不能被回收,這就是java中記憶體洩露的發生場景,通俗地說,就是程式員可能建立了一個對象,以後一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是java中可能出現記憶體洩露的情況,例如,緩存系統,我們加載了一個對象放在緩存中(例如放在一個全局map對象中),然後一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。