未看第一篇的,這里可以直達
Java面試(基礎篇) - 第一篇
Integer對象可以用==判斷嗎?為什么?
回答
不可以,因為 == 比較的是對象的實例(內存地址),Integer是有一個緩存機制的,它會將-128–127之間的數字緩存下,所以,我們使用 == 比較,在這個數字區間內,它是相等的。但是,如果超過了這個區間,他就不相等了。所以,建議還是使用equals方法比較。
擴展
測試一下 看看代碼
Integer a=10;Integer b=10;System.out.println(a==b);//trueInteger c=128;Integer d=128;System.out.println(c==d);//falseSystem.out.println(c.equals(d));//true
Java為什么不支持多繼承?
回答
如果支持多繼承 就會產生菱形繼承問題。即,
Parrot無法確定是從Bird 還是Mammal繼承Animal的方法。
其次,如果支持多繼承,Java中的復雜度也會上升,不利于維護。修改一個父類,可能會影響多個子類,增加代碼的復雜度。
Java中 是通過接口實現 來達到多繼承的效果的。
擴展
這個問題,java之父,James Gosling也曾回答過,就是因為會產生菱形繼承問題。
此外 Java提供了另一種方式,即多實現接口 來達到同樣的效果。
那么,新問題,實現的兩個接口中,有一個方法名,參數相同的方法,此時繼承類要實現哪一個?
答案是,會編譯報錯,此時,這個問題就交給開發人員去解決。進行重寫這個方法。
接口 和抽象類的區別是什么?
回答
接口和抽象類都可以代表抽象層,只不過說,兩者的含義不一樣。接口更多用于制定規范,抽象類則用于復用。
另外,抽象類可以有構造器,接口沒有。雖然說 抽象類不能直接new,但是抽象類的構造器也可以作為初始化賦值來用。
接口在java8之前,只能定義,并且默認修飾符public,不能用其他修飾符,而抽象類則可以有具體的方法實現。
擴展
說到接口和抽象類的區別,我們可以通過模板方法來深入理解一下。
模板方法作為一種設計模式,它主要就是為了解決代碼中的復用問題。
public abstract class Coupon {public final void applyCoupon() {//打印是否有效invalidCoupon();//打印折扣applyDisCount();}//具體折扣邏輯protected abstract void applyDisCount();//無效優惠卷邏輯protected abstract void invalidCoupon();
}
public class FixedAmountCoupon extends Coupon{@Overrideprotected void applyDisCount() {System.out.println("滿100減10");}@Overrideprotected void invalidCoupon() {System.out.println("無效優惠卷");}
}
public class PercentageCoupon extends Coupon{@Overrideprotected void applyDisCount() {System.out.println("打八折");}@Overrideprotected void invalidCoupon() {System.out.println("無效優惠卷");}
}public static void main(String[] args) {Coupon fixedAmountCoupon = new FixedAmountCoupon();fixedAmountCoupon.applyCoupon();}
如何理解Java中的多態?
回答
統一操作針對不同的對象,得到不同的結果。在Java中,子類重寫父類的方法,就是多態的一種體現。
滿足三個條件即可。
類繼承或實現方法。
子類重寫父類的方法。
父類的指針指向子類的引用。
擴展
多態是一種運行期的概念,有人說多態分為兩種,靜態多態和動態多態。靜態多態就是重載,編譯器實現方法名相同,參數類型個數不同。不過我認為 多態是一種運行期的概念,重寫更能體現。
有了基本數據類型 為什么還要使用包裝類?
回答
因為,Java是面向對象的語言,很多地方要求使用對象。比如說集合,泛型。
另外,包裝類也提供了一些方法,可以直接使用,便于開發。
擴展
如果包裝類Integer 和基本數據類型int進行數據比較,是int轉為Integer 還是Integer 轉為int呢?
實際上,不管是包裝類和基本類比較,還是包裝類和包裝類比較,都是轉為int,底層使用intValue這個方法進行比較的。
可以使用浮點數表示金額計算嗎?為什么?
回答
不可以,不是所有的小數都可以用浮點數來表示的。IEEE提出用近似值表示小數,并且引入了精度的概念,這就是我們所說的浮點數。浮點數只是近似值,而不是精確值,所以不能用來表示金額,否則精度會缺失。
擴展
不是所有的數都可以用二進制表示的,比如0.1,轉化為二進制就會出現無限循環的情況。
為了解決精度問題,Java提供了BigDecimal來進行精確運算。
可以使用BigDecimal的equals進行等值比較嗎?為什么?
回答
不可以,equals比較是兩部分,值和標度,對于0.1和0.10這兩個數,雖然他們的值相同,但他們的標度不同,所以也不相等。
擴展
BigDecimal 提供了四種類型的接收,int,long,double,String。其中int 和long是整數,所以他們的標度是0,而對于
double,使用new BigDecimal(0.1)創建的時候,實際上我們拿到的是0.1的近似值,也就是一個55位的小數。標度為55.
而我們使用new Bigdecimal(“0.1”)的時候,值是01.而標度則是1.
對于比較BigDecimal,推薦的做法是 使用CompareTo方法,這個方法只比較兩個數字的值,不比較標度,相等則返回0.
Java中負數取絕對值,結果一定是正數嗎?
回答
不一定,Math.abs(),這里要是取到了Integer的最小值,取絕對值出來,還是一個負數。這是因為,此時這個最小數已經是Int類型的最小數了,再去拿絕對值,就會發生越界。超出int的范圍。
System.out.println(Math.abs(Integer.MIN_VALUE));
如何解決呢,只需要將他轉為Long類型即可。
System.out.println(Math.abs((long)Integer.MIN_VALUE));
擴展
我們直到Java中的基本數據類型中的整型有 byte,short,int,long四種。數字的范圍也是從小到大的。1byte=1個字節。范圍是,-2^7 ~2^7-1.也就是-128到127。初始化時,byte默認值是0.short則使用兩個字節存儲,范圍是-32768 - 32767 (-2^15 ~ 215-1).int則是四個字節存儲,-231 ~ 2^31-1.long 則是八個字節 范圍為-2^63 ~ 2 ^63-1。
超出范圍,就會發生溢出,溢出并不會拋出異常,已沒有任何提示,所以在進行數據運算的時候,一定要注意。
什么是泛型?為什么要用泛型?
回答
泛型是JDK5引入的概念,允許在定義類或者接口的時候,使用類型參數。聲明的類型參數在使用時用具體的類型來替換。
好處就是,提高了代碼的復用性,以及安全性。在泛型出來之前,做類型轉換的時候,要進行類型檢查,如果類型轉換出錯,就會直接宕掉。而泛型的作用就是在編譯時,進行類型檢查,增加程序的安全性。
擴展
舉個例子看一下,如何定義一個簡單的泛型。
public static void main(String[] args) {List<String> listString = new ArrayList<>();listString.add("1");String first = getFirst(listString);List<Integer> listInteger = new ArrayList<>();Integer first1 = getFirst(listInteger);System.out.println(first1);}//定義一個靜態方法 傳入List<?> 泛型 返回對應類型的第一個數據,沒有數據則返回nullpublic static <T> T getFirst(List<T> list){if(list.size() == 0){return null;}return list.get(0);}
可以看到 這里我傳入是String類型,它就會返回String類型的參數。如果是Integer類型,則會返回Integer類型的參數。如此,就可以實現,一個方法,多種類型都可以使用,增加了代碼的復用性。
了解過類型擦除嗎?為什么要進行類型擦除?
回答
簡單理解就是 將泛型Java代碼轉化為普通Java代碼。不過編譯器更直接點,將泛型Java代碼轉為字節碼。
所謂的類型擦除 就是將泛型信息擦除掉 轉為使用Object對象接收。這也是為什么要使用包裝類的一個原因。基本數據類型非對象,不進行裝箱,無法使用泛型。
擴展
泛型中用于定義的字母,主要有K T V E Object。
E主要在集合中使用,代表的是元素。
T則主要代表Java類,如我們自定義的User類,就可以用T代替。
K V 指的是鍵值
N代指數據類型。
? 則表示不確定的Java類型。
Object 代指所有類的根類,任何類的對象,都可以設置為Object的引用變量,使用時進行強制類型轉換即可。
泛型中的上下界限定符extends supper區別是什么?
回答
一般我們認為,extends代表的是類型的上界,也就是參數只能傳它本身或者它的子類。比如,我們有一個people類,teacher 和 student都是它的子類。 使用Student 就可以正常調用方法,但是如果傳入一個沒有繼承People的User,則在編譯期就會報錯。
public static void main(String[] args) {Student people = getPeople(new Student());getPeople(new User());}//定義一個靜態方法 傳入List<?> 泛型 返回對應類型的第一個數據,沒有數據則返回nullpublic static <T extends People> T getPeople(T t){return t;}
了解了泛型中的上界限定符,我們再來看一下下界限定符,其實它的作用和上界限定符剛好相反。表示,參數化類型必須是此類或者此類的父類。
public static void main(String[] args) {test(new ArrayList<People>());test(new ArrayList<Student>());test(new ArrayList<Teacher>());}//定義一個靜態方法 演示下界限定符 使用Student類 他的父類是People public static <T> T test(List<? super Student> t) {return null;}
擴展
使用限定通配符 我們需要遵守PECS原則。即,上界生產,下界消費。
如果 需要向集合讀取,就可以使用 ?extends 通配符。我們認為,從集合中讀 集合就是生產者。
如果不需要讀,只要寫入,那就可以使用? supper通配符。
如果 即要存又要取 那就不要使用任何限定符。