Java 面試題之基礎篇

1. ".java" 源文件中可以包含多少個類?有什麼限制?

  • 可以包含多個類,但只能包含一個public類,並且public類名必須與文件名相同。通常一個文件裏只包含一個類。

2. switch語句能否作用在byte上,能否作用在long類型上,能否作用域String上?

  • switch(e),其中e必須是int型或 enum型,由於short、char或者byte會自動轉爲int的,所以,這些類型以及這些類型的包裝類型也是可以的。顯然,long類型是不可以的,String在jdk1.7之前不支持,在此之後是支持的。

3.short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?

  • 對於short s1=1;s1=s1+1;由於s1+1運算時會自動提升表達式的類型,所以結果是int型,再賦值給short類型s1時編譯器將報告類型轉換錯誤。

  • 對於short s1=1;s1 += 1;由於+=是java語言規定的運算符,java編譯器會對它進行特殊處理,因此可以正確編譯。

4.char類型變量佔幾個字節?

  • char型變量是用來存儲Unicode編碼的字符,佔用兩個字節。

5.使用final關鍵字修飾一個變量時,是引用不能變還是引用的對象不能變?

  • 使用final關鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內容還是可以改變的。例如,對於如下語句:final StringBuffer sb = new StringBuffer("test");
    sb = new StringBuffer(""); // 錯誤
    sb.append("hello "); //正確

6.靜態變量和實例變量的區別?

  • 在語言定義上的區別:靜態變量前要加static關鍵字,而實例變量前則不加

  • 在程序運行時的區別:實例變量屬於某個對象的屬性,必須創建了實例對象,實例變量纔會被分配空間,才能使用這個實例變量。靜態變量不屬於某個實例對象,而是屬於類,所以也稱爲類變量,只要程序加載了類的字節碼,不用創建如何實例對象,靜態變量就會被分配空間,靜態變量就可以被使用了。總之,實例變量必須創建對象後纔可以通過這個對象來使用,靜態變量則可以直接使用類名來引用。

  • 例如,對於下面的程序,無論創建多少個實例對象,永遠都只分配一個staticVar變量,並且每創建一個實例對象,這個staticVar就會加1;但是,每創建一個實例對象,就會分配一個instanceVar,即可能分配多個instanceVar,並且每個instanceVar的值都只自加了1次。

public class Test{
 public static int staticVar = 0;
 public int instanceVar = 0;
 public void Add(){
   staticVar++;
   instanceVar++;
   System.out.println("static var=" + staticVar + "instance Var=" + instanceVar);
 }
}

7.是否可以從一個static方法內部發出對非static方法的調用?

  • 不可以。因爲非static方法是要與對象關聯在一起的,必須創建一個對象後,纔可以在該對象上進行方法調用,而static方法調用時不需要創建對象,可以直接調用。也就是說,當一個static方法被調用時,可能還沒有創建任何實例對象,如果從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪個對象上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的調用。

8.Integer和int的區別?

  • int是java提供的8種原始數據類型之一。Java爲每個原始類型提供了封裝類,Integer是java爲int提供的封裝類。int的默認值爲0,而Integer的默認值爲null,即Integer可以區分出未賦值和值爲0的區別,int則無法表達出未賦值的情況。

9.接口是否可繼承接口?抽象類是否可實現(implements)接口?抽象類是否可繼承具體類(concreteclass)?抽象類中是否可以有靜態的main方法?

  • 接口可以繼承接口。抽象類可以實現(implements)接口,抽象類可以繼承具體類。抽象類中可以有靜態的main方法。

10.Java中實現多態的機制是什麼?

  • 靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。

11.抽象類和接口有什麼區別?

  • 抽象類可以有構造方法,接口中不能有構造方法。

  • 抽象類中可以有普通成員變量,接口中沒有普通成員變量

  • 抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。

  • 抽象類中的抽象方法的訪問類型可以是public,protected和默認類型,但接口中的抽象方法只能是public類型的,並且默認即爲public abstract類型。

  • 抽象類中可以包含靜態方法,接口中不能包含靜態方法

  • 抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是publicstatic final類型,並且默認即爲publicstatic final類型。

  • 一個類可以實現多個接口,但只能繼承一個抽象類。

12.內部類可以引用它的包含類的成員嗎?有沒有什麼限制?

  • 完全可以。如果不是靜態內部類,則沒有什麼限制。

  • 如果你把靜態嵌套類當作內部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變量,而只能訪問外部類中的靜態成員,例如,下面的代碼:

class Outer{
 static int x;
 static class Inner{
   void test()
   {
     System.out.println(x);
   }
 }
} 

13.String s = new String("xyz");創建了幾個StringObject?是否可以繼承String類?

  • 兩個或者一個,”xyz”作爲一個常量對象,這個對象會放在字符串常量緩衝區,常量”xyz”不管出現多少遍,在常量緩衝區中的只存在一個。new String("xyz")時,如果常量緩衝區不存在該對象,則需先在常量緩衝區創建一個新的對象,然後在使用該常量緩衝區對象內容來創建一個新String對象,因此會創建兩個對象,如果常量緩衝區以存在該對象("xyz"),則只會創建一個對象。

  • String類是不能繼承的,因爲String默認final修飾,是不可繼承的。

14.下面這條語句一共創建了多少個對象: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。這說明編譯器可以對字符串常量直接相加的表達式進行優化,不必要等到運行期再去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。

  • 題目中的第一行代碼被編譯器在編譯時優化後,相當於直接定義了一個"abcd"的字符串,所以,上面的代碼應該只創建了一個String對象。看如下代碼:

String s = "a" + "b" + "c" + "d"
System.out.println(s == "abcd");  //true

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

  • 我們知道finally{}裏的語句是一定會執行的,那麼這個是return之前還是return之後呢?看下面的代碼:

public class Test{
 public static void main(String[] args){
   System.out.println(new Test().test());
 }

 int test(){
   int x = 1;
   try{
     return x;
   }finally{
     ++x;
   }
 }
}
  • 運行的結果是1,說明return語句已經執行了再去執行finally語句,不過並沒有直接返回,而是將返回結果保存下來,然後去finally語句裏執行。

16.final, finally, finalize的區別?

  • final用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。內部類要訪問局部變量,局部變量必須定義成final類型。

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

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

17.運行時異常與一般異常有何異同?

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

18. error和exception有申請區別?

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

19. Java 中堆和棧有什麼區別?

  • JVM 中堆和棧屬於不同的內存區域,使用目的也不同。棧常用於保存方法幀和局部變量,而對象總是在堆上分配。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。

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

  • 堆:堆內存用來存放由 new 創建的對象和數組,在堆中分配的內存,由 Java 虛擬機的自動垃圾回收器來管理。在堆中產生了一個數組或者對象之後,還可以在棧中定義一個特殊的變量,讓棧中的這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量,以後就可以在程序中使用棧中的引用變量來訪問堆中的數組或者對象,引用變量就相當於是爲數組或者對象起的一個名稱。

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