1. 程式人生 > >Java常見面試題整理【1】

Java常見面試題整理【1】

--------------------- 
作者:ImportNewXXT0101 
來源:CSDN 
原文:https://blog.csdn.net/m0_37955444/article/details/78878030 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

1. 什麼是Java虛擬機器?為什麼Java被稱作是“平臺無關的程式語言”? 


    java的跨平臺不是java源程式的跨平臺 ,如果是這樣,那麼所以語言都是跨平臺的, java源程式先經過javac編譯器編譯成二進位制的.class位元組碼檔案(java的跨平臺指的就是.class位元組碼檔案的跨平臺,.class位元組碼檔案是與平臺無關的),.class檔案再執行在jvm上,java直譯器(jvm的一部分)會將其解釋成對應平臺的機器碼執行,所以java所謂的跨平臺就是在不同平臺上安裝了不同的jvm,而在不同平臺上生成的.class檔案都是一樣的,而.class檔案再由對應平臺的jvm解釋成對應平臺的機器碼執行。
    再解釋下機器碼和位元組碼的區別: 
    一,機器碼,完全依附硬體而存在~並且不同硬體由於內嵌指令集不同,即使相同的0 1程式碼 意思也可能是不同的~換句話說,根本不存在跨平臺性~比如~不同型號的CPU,你給他個指令10001101,他們可能會解析為不同的結果。
    二,我們知道JAVA是跨平臺的,為什麼呢?因為他有一個jvm,不論哪種硬體,只要你裝有jvm,那麼他就認識這個JAVA位元組碼,至於底層的機器碼,咱不用管,有jvm搞定,他會把位元組碼再翻譯成所在機器認識的機器碼。
2. JDK和JRE的區別是什麼?


 JRE: Java Runtime Environment  
 JDK:Java Development Kit
 JRE顧名思義是java執行時環境,包含了java虛擬機器,java基礎類庫。是使用java語言編寫的程式執行所需要的軟體環境,是提供給想執行java程式的使用者使用的。
 JDK顧名思義是java開發工具包,是程式設計師使用java語言編寫java程式所需的開發工具包,是提供給程式設計師使用的。JDK包含了JRE,同時還包含了編譯java原始碼的編譯器javac,還包含了很多java程式除錯和分析的工具:jconsole,jvisualvm等工具軟體,還包含了java程式編寫所需的文件和demo例子程式。
 如果你需要執行java程式,只需安裝JRE就可以了。如果你需要編寫java程式,需要安裝JDK。
3. ”static”關鍵字是什麼意思?Java中是否可以覆蓋(override)一個private或者是static的方法?

首先是static關鍵字,static原意是“靜態的”。

①static可以修飾內部類,但是不能修飾普通類。靜態內部類的話可以直接呼叫靜態構造器(不用物件)。


②static修飾方法, static 方法就是沒有 this 的方法。在 static 方法內部不能呼叫非靜態方法,反過來是可以的。因為靜態的成員屬於類,隨著類的載入而載入到靜態方法區記憶體,當類載入時,此時不一定有例項建立,沒有例項,就不可以訪問非靜態的成員。類的載入先於例項的建立。而且可以在沒有建立任何物件的前提下,僅僅通過類本身來呼叫 static 方法。這實際上正是 static 方法的主要用途。 方便在沒有建立物件的情況下來進行呼叫(方法/變數)。

最常見的static方法就是main,因為所有物件都是在該方法裡面例項化的,而main是程式入口,所以要通過類名來呼叫。還有就是main中需要經常訪問隨類載入的成員變數。

③static修飾變數,就變成了靜態變數,隨類載入一次,可以被多個物件共享。

④static修飾程式碼塊,形成靜態程式碼塊,用來優化程式效能,將需要載入一次的程式碼設定成隨類載入,靜態程式碼塊可以有多個。
Java中static方法不能被覆蓋,因為方法覆蓋是基於執行時動態繫結的,而static方法是編譯時靜態繫結的。
還有私有的方法不能被繼承,子類就沒有訪問許可權,肯定也是不能別覆蓋的。

4. Java支援的資料型別有哪些?什麼是自動拆裝箱?

基本資料型別:

整數值型:byte,short,int,long, 字元型:char
浮點型別:float,double

布林型:boolean

整數預設int型,小數預設是double型。Float和long型別的必須加字尾。
首先知道String是引用型別不是基本型別,引用型別宣告的變數是指該變數在記憶體中實際儲存的是一個引用地址,實體在堆中。引用型別包括類、介面、陣列等。String類還是final修飾的。
 而包裝類就屬於引用型別,自動裝箱和拆箱就是基本型別和引用型別之間的轉換,至於為什麼要轉換,因為基本型別轉換為引用型別後,就可以new物件,從而呼叫包裝類中封裝好的方法進行基本型別之間的轉換或者toString(當然用類名直接呼叫也可以,便於一眼看出該方法是靜態的),還有就是如果集合中想存放基本型別,泛型的限定型別只能是對應的包裝型別。
5. Java中的方法覆蓋(Overriding)和方法過載(Overloading)是什麼意思?

方法重寫的原則:

重寫方法的方法名稱、引數列表必須與原方法的相同,返回型別可以相同也可以是原型別的子型別(從Java SE5開始支援)。
重寫方法不能比原方法訪問性差(即訪問許可權不允許縮小)。
重寫方法不能比原方法丟擲更多的異常。
被重寫的方法不能是final型別,因為final修飾的方法是無法重寫的。
被重寫的方法不能為private,否則在其子類中只是新定義了一個方法,並沒有對其進行重寫。
被重寫的方法不能為static。如果父類中的方法為靜態的,而子類中的方法不是靜態的,但是兩個方法除了這一點外其他都滿足重寫條件,那麼會發生編譯錯誤;反之亦然。即使父類和子類中的方法都是靜態的,並且滿足重寫條件,但是仍然不會發生重寫,因為靜態方法是在編譯的時候把靜態方法和類的引用型別進行匹配。
重寫是發生在執行時的,因為編譯期編譯器不知道並且沒辦法確定該去呼叫哪個方法,JVM會在程式碼執行的時候作出決定。
方法過載的原則:

方法名稱必須相同。
引數列表必須不同(個數不同、或型別不同、引數型別排列順序不同等)。
方法的返回型別可以相同也可以不相同。
僅僅返回型別不同不足以成為方法的過載。
過載是發生在編譯時的,因為編譯器可以根據引數的型別來選擇使用哪個方法。
重寫和過載的不同:

方法重寫要求引數列表必須一致,而方法過載要求引數列表必須不一致。
方法重寫要求返回型別必須一致(或為其子型別),方法過載對此沒有要求。
方法重寫只能用於子類重寫父類的方法,方法過載用於同一個類中的所有方法。
方法重寫對方法的訪問許可權和丟擲的異常有特殊的要求,而方法過載在這方面沒有任何限制。
父類的一個方法只能被子類重寫一次,而一個方法可以在所有的類中可以被過載多次。
過載是編譯時多型,重寫是執行時多型。
6. Java中,什麼是構造方法?什麼是構造方法過載?什麼是複製構造方法?

    java中的建構函式是為了初始化物件的,建構函式的函式名和類名一致,預設的建構函式沒有引數,沒有返回值,建構函式的函式體內,沒有內容。建構函式的過載是函式名與類名相同,引數型別不同,引數不同。同樣的作用也是為了初始化物件的,當新物件被建立的時候,建構函式會被呼叫。
關於複製建構函式:C++中的複製建構函式通常有三種作用
1.物件作為函式引數
2.物件作為函式返回值
3.使用一個物件對另一個物件初始化。
C++語法允許使用者定義自己的複製建構函式以實現自定義的複製,比如說進行深複製。Java並不支援這樣的複製建構函式。但是這並不代表Java中沒有這種機制,在Java中Object類的clone()方法就是這種機制的體現。而且通過以上三種方式對Java物件進行的操作都是對引用的操作,不像C++裡面是對原物件的操作,因此Java中也不需要考慮需要使用複製建構函式這種問題。
7.  介面和抽象類的區別是什麼?

從設計層面來說,抽象是對類的抽象,是一種模板設計,介面是行為的抽象,是一種行為的規範。

1.抽象類可以有構造方法,介面中不能有構造方法。 
2.抽象類中可以有普通成員變數,介面中沒有。
3.抽象類中可以包含非抽象的普通方法,介面中所有方法必須都是抽象的。 
4.抽象類中的抽象方法的訪問型別可以是public,protected,但介面中的抽象方法只能是public,並且預設為
  public abstract型別。
5.抽象類中可以包含靜態方法,介面中不能有。
6.抽象類和介面中都可以包含靜態成員變數,抽象類中的靜態成員變數的訪問型別可以任意,但介面中定義的變數只能是
  public staticfinal型別。
 7.一個類可以實現多個介面,但只能繼承一個抽象類。
8.  什麼是值傳遞和引用傳遞?

值傳遞是指將值的副本傳遞給呼叫的函式,呼叫的函式可以改變副本的值,但是並不會影響main函式中的原值。 引用傳值,傳遞的是物件的引用,同一個引用指向相同的實體,所以改變引用指向實體的值,可以影響main函式中實體的值。

一:搞清楚 基本型別 和 引用型別的不同之處

int num = 10;
String str = "hello";


如圖所示,num是基本型別,值就直接儲存在變數中。而str是引用型別,變數中儲存的只是實際物件的地址。一般稱這種變數為"引用",引用指向實際物件,實際物件中儲存著內容。

二:搞清楚賦值運算子(=)的作用

num = 20;
str = "java";
對於基本型別 num ,賦值運算子會直接改變變數的值,原來的值被覆蓋掉。
對於引用型別 str,賦值運算子會改變引用中所儲存的地址,原來的地址被覆蓋掉。但是原來的物件不會被改變(重要)。
如上圖所示,"hello" 字串物件沒有被改變。(沒有被任何引用所指向的物件是垃圾,會被垃圾回收器回收)
 
三:呼叫方法時發生了什麼?引數傳遞基本上就是賦值操作。
第一個例子:基本型別

void foo(int value) {
    value = 100;
}
foo(num); // num 沒有被改變
第二個例子:沒有提供改變自身方法的引用型別

void foo(String text) {
    text = "windows";
}
foo(str); // str 也沒有被改變
第三個例子:提供了改變自身方法的引用型別

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改變了,變成了"iphone4"。
第四個例子:提供了改變自身方法的引用型別,但是不使用,而是使用賦值運算子。

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 沒有被改變,還是 "iphone"。
重點理解為什麼,第三個例子和第四個例子結果不同?

下面是第三個例子的圖解:
 
builder.append("4")之後
 
下面是第四個例子的圖解:
 
builder = new StringBuilder("ipad"); 之後