前幾天,在茫茫的互聯網海洋中尋尋覓覓,我收藏了800道Java基礎經典面試題,有小夥伴私聊我要答案。因此感受沒有答案的面試題是沒有靈魂的,因而今天先整理基礎篇的前80道答案出來~html
全部的Java面試題已經上傳github,答案也上傳了一部分~java
公衆號:撿田螺的小男孩程序員
equalsgithub
兩個對象equals相等,則它們的hashcode必須相等,若是兩個對象的hashCode()相同,則equals()不必定爲true。面試
hashCode 的常規協定:sql
這個答案來自互聯網哈,我的以爲是最好理解的~編程
- BIO:線程發起 IO 請求,無論內核是否準備好 IO 操做,從發起請求起,線程一直阻塞,直到操做完成。
- NIO:線程發起 IO 請求,當即返回;內核在作好 IO 操做的準備以後,經過調用註冊的回調函數通知線程作 IO 操做,線程開始阻塞,直到操做完成。
- AIO:線程發起 IO 請求,當即返回;內存作好 IO 操做的準備以後,作 IO 操做,直到操做完成或者失敗,經過調用註冊的回調函數通知線程作 IO 操做完成或者失敗。
BIO 是一個鏈接一個線程。,NIO 是一個請求一個線程。,AIO 是一個有效請求一個線程。設計模式
- BIO:同步並阻塞,服務器實現模式爲一個鏈接一個線程,即客戶端有鏈接請求時服務器端就須要啓動一個線程進行處理,若是這個鏈接不作任何事情會形成沒必要要的線程開銷,固然能夠經過線程池機制改善。
- NIO:同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的鏈接請求都會註冊到多路複用器上,多路複用器輪詢到鏈接有I/O請求時才啓動一個線程進行處理。
- AIO:異步非阻塞,服務器實現模式爲一個有效請求一個線程,客戶端的 IO 請求都是由 OS 先完成了再通知服務器應用去啓動線程進行處理。
String:數組
StringBuffer:
StringBuilder:
基本類型 | 位數 | 字節 |
---|---|---|
int | 32 | 4 |
short | 16 | 2 |
long | 64 | 8 |
byte | 8 | 1 |
char | 16 | 2 |
float | 32 | 4 |
double | 64 | 8 |
boolean | ? | ? |
對於boolean,官方文檔未明肯定義,它依賴於 JVM 廠商的具體實現。邏輯上理解是佔用 1位,可是實際中會考慮計算機高效存儲因素
感興趣的小夥伴,能夠去看官網
在牛客網看到這道題的答案,以爲寫的最好~
連接:www.nowcoder.com/questionTer… 來源:牛客網
- Comparable & Comparator 都是用來實現集合中元素的比較、排序的,只是 Comparable 是在集合內部定義的方法實現的排序,Comparator 是在集合外部實現的排序,因此,如想實現排序,就須要在集合外定義 Comparator 接口的方法或在集合內實現 Comparable 接口的方法。
- Comparator位於包java.util下,而Comparable位於包 java.lang下。
- Comparable 是一個對象自己就已經支持自比較所須要實現的接口(如 String、Integer 本身就能夠完成比較大小操做,已經實現了Comparable接口) 自定義的類要在加入list容器中後可以排序,能夠實現Comparable接口,在用Collections類的sort方法排序時,若是不指定Comparator,那麼就以天然順序排序, 這裏的天然順序就是實現Comparable接口設定的排序方式。
- 而 Comparator 是一個專用的比較器,當這個對象不支持自比較或者自比較函數不能知足你的要求時,你能夠寫一個比較器來完成兩個對象之間大小的比較。
- 能夠說一個是自已完成比較,一個是外部程序實現比較的差異而已。 用 Comparator 是策略模式(strategy design pattern),就是不改變對象自身,而用一個策略對象(strategy object)來改變它的行爲。 好比:你想對整數採用絕對值大小來排序,Integer 是不符合要求的,你不須要去修改 Integer 類(實際上你也不能這麼作)去改變它的排序行爲,只要使用一個實現了 Comparator 接口的對象來實現控制它的排序就好了。
首先,String是一個final修飾的類,final修飾的類不能夠被繼承。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
複製代碼
String類爲何不能被繼承呢?
有兩個緣由:
舉個例子吧,假設有個Fruit父類,一個taste味道方法,兩個子類Apple和Pear,以下:
abstract class Fruit {
abstract String taste() ;
}
class Apple extends Fruit {
@Override
String taste() {
return "酸酸的";
}
}
class Pear extends Fruit {
@Override
String taste() {
return "甜甜的";
}
}
public class Test {
public static void main(String[] args) {
Fruit f = new Apple();
System.out.println(f.taste());
}
}
複製代碼
程序運行,當調用對象Fruit f的方法taste時,JVM查找Fruit對象類的方法表以肯定taste方法的直接引用地址,到底來自Apple仍是Pear,肯定後才真正調用對應子類的taste方法,
這個面試題,能夠看我這篇文章哈~
這裏考察3個知識點吧:
看個Integer的緩存的例子,加深一下印象哈:
Integer a = 10;
Integer b = 10;
Integer c = 129;
Integer d = 129;
System.out.println(a == b);
System.out.println(c == d);
輸出結果:
true
false
複製代碼
這道面試題,看我這篇文章哈:談談Java反射:從入門到實踐,再到原理
Java獲取反射的三種方法:
面向對象的三大特徵:
直接看個例子吧:
public class Parent {
{
System.out.println("父類非靜態代碼塊");
}
static {
System.out.println("父類靜態塊");
}
public Parent() {
System.out.println("父類構造器");
}
}
public class Son extends Parent {
public Son() {
System.out.println("子類構造器");
}
static {
System.out.println("子類靜態代碼塊");
}
{
System.out.println("子類非靜態代碼塊");
}
}
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
複製代碼
運行結果:
父類靜態塊
子類靜態代碼塊
父類非靜態代碼塊
父類構造器
子類非靜態代碼塊
子類構造器
複製代碼
因此,類實例化順序爲: 父類靜態代碼塊/靜態域->子類靜態代碼塊/靜態域 -> 父類非靜態代碼塊 -> 父類構造器 -> 子類非靜態代碼塊 -> 子類構造器
Java建立對象有5種方式
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
String str = "撿田螺的小男孩";
String strIso = new String(str.getBytes("GB2312"), "ISO-8859-1");
System.out.println(strIso);
}
}
複製代碼
這道面試題,能夠看我這篇文章哈:Java程序員必備:異常的十個關鍵知識點
從前從前,有位老人,他的名字叫Throwable,他生了兩個兒子,大兒子叫Error,二兒子叫Exception。
Error
表示編譯時或者系統錯誤,如虛擬機相關的錯誤,OutOfMemoryError等,error是沒法處理的。
Exception
代碼異常,Java程序員關心的基類型一般是Exception。它能被程序自己能夠處理,這也是它跟Error的區別。
它能夠分爲RuntimeException(運行時異常)和CheckedException(可檢查的異常)。
常見的RuntimeException異常:
- NullPointerException 空指針異常
- ArithmeticException 出現異常的運算條件時,拋出此異常
- IndexOutOfBoundsException 數組索引越界異常
- ClassNotFoundException 找不到類異常
- IllegalArgumentException(非法參數異常)
複製代碼
常見的 Checked Exception 異常:
- IOException (操做輸入流和輸出流時可能出現的異常)
- ClassCastException(類型轉換異常類)
複製代碼
這道面試題,能夠看我這篇文章哈:Java程序員必備基礎:內部類解析
String str ="whx";
String newStr =new String ("whx");
複製代碼
String str ="whx"
先在常量池中查找有沒有"whx" 這個對象,若是有,就讓str指向那個"whx".若是沒有,在常量池中新建一個「whx」對象,並讓str指向在常量池中新建的對象"whx"。
String newStr =new String ("whx");
是在堆中創建的對象"whx" ,在棧中建立堆中"whx" 對象的內存地址。
如圖所示:
網上這篇文章講的挺好的: String和New String()的區別
Class.forName和ClassLoader均可以對類進行加載。它們區別在哪裏呢? ClassLoader負責加載 Java 類的字節代碼到 Java 虛擬機中。Class.forName實際上是調用了ClassLoader,以下:
這裏面,forName0的第二個參數爲true,表示對加載的類進行初始化化。其實還能夠調用Class<?> forName(String name, boolean initialize, ClassLoader loader)
方法實現同樣的功能,它的源碼以下:
因此,Class.forName和ClassLoader的區別,就是在類加載的時候,class.forName有參數控制是否對類進行初始化。
網上這篇文章寫得不錯,描述Java動態代理的幾種實現方式,分別說出相應的優缺點
Error: 表示編譯時或者系統錯誤,如虛擬機相關的錯誤,OutOfMemoryError等,error是沒法處理的。
Exception: 代碼異常,Java程序員關心的基類型一般是Exception。它能被程序自己能夠處理,這也是它跟Error的區別。
它能夠分爲RuntimeException(運行時異常)和CheckedException(可檢查的異常)。 常見的RuntimeException異常:
- NullPointerException 空指針異常
- ArithmeticException 出現異常的運算條件時,拋出此異常
- IndexOutOfBoundsException 數組索引越界異常
- ClassNotFoundException 找不到類異常
- IllegalArgumentException(非法參數異常)
複製代碼
常見的 Checked Exception 異常:
- IOException (操做輸入流和輸出流時可能出現的異常)
- ClassCastException(類型轉換異常類)
複製代碼
有興趣能夠看我以前寫得這篇文章: Java程序員必備:異常的十個關鍵知識點
淺拷貝
複製了對象的引用地址,兩個對象指向同一個內存地址,因此修改其中任意的值,另外一個值都會隨之變化。
深拷貝
將對象及值複製過來,兩個對象修改其中任意的值另外一個值不會改變
有關於註解,建議你們看一下java編程思想的註解篇章哈~
設計模式分爲三大類:
最好平時積累一下,單例模式(7種實現方式),工廠模式,模板方法設計模式,策略模式,裝飾者模式、代理模式這幾種怎麼寫吧~
我的以爲,能夠看看Hollis大神相關設計模式的文章哈,寫得特別好!設計模式(二)——單例模式
static變量在Java中是屬於類的,它在全部的實例中的值是同樣的。當類被Java虛擬機載入的時候,會對static變量進行初始化。由於靜態的成員屬於類,隨着類的加載而加載到靜態方法區內存,當類加載時,此時不必定有實例建立,沒有實例,就不能夠訪問非靜態的成員。類的加載先於實例的建立,所以靜態環境中,不能夠訪問非靜態!
不支持多繼承,緣由:
2 << 3
複製代碼
構造器是不能被繼承的,由於每一個類的類名都不相同,而構造器名稱與類名相同,因此談不上繼承。 又因爲構造器不能被繼承,因此相應的就不能被重寫了。
在Java中,char類型佔2個字節,並且Java默認採用Unicode編碼,一個Unicode碼是16位,因此一個Unicode碼佔兩個字節,Java中不管漢子仍是英文字母都是用Unicode編碼來表示的。因此,在Java中,char類型變量能夠存儲一箇中文漢字。
char ch = '啦';
System.out.println("char:" + ch);
複製代碼
- hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中肯定對象的存儲地址的;
- 若是兩個對象相同,就是適用於equals(java.lang.Object) 方法,那麼這兩個對象的hashCode必定要相同;
- 若是對象的equals方法被重寫,那麼對象的hashCode也儘可能重寫,而且產生hashCode使用的對象,必定要和equals方法中使用的一致,不然就會違反上面提到的第2點;
- 兩個對象的hashCode相同,並不必定表示兩個對象就相同,也就是不必定適用於equals(java.lang.Object) 方法,只可以說明這兩個對象在散列存儲結構中.
這篇文章講得挺詳細的:Java中hashCode的做用
關於這個問題,《Effective Java》給咱們作的解答:
for-each可以讓代碼更加清晰,而且減小了出錯的機會。 下面的慣用代碼適用於集合與數組類型:
for (Element e : elements) { doSomething(e); } 複製代碼
使用for-each循環與常規的for循環相比,並不存在性能損失,即便對數組進行迭代也是如此。實際上,在有些場合下它還能帶來微小的性能提高,由於它只計算一次數組索引的上限。
7種:
能夠看這篇文章:單例模式的七種寫法
- NullPointerException 空指針異常
- ArithmeticException 出現異常的運算條件時,拋出此異常
- IndexOutOfBoundsException 數組索引越界異常
- ClassNotFoundException 找不到類異常
- IllegalArgumentException(非法參數異常)
複製代碼
有可能哈~
hashCode 的常規協定:
JDK 中的 java.lang.Math 類:
String 不屬於基礎類型,基礎類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬於對象。
不能夠。由於JDK處於安全性的考慮,基於雙親委派模型,優先加載JDK的String類,若是java.lang.String已經加載,便不會再次被加載。
- 在咱們的業務系統中判斷對象時有時候須要的不是一種嚴格意義上的相等,而是一種業務上的對象相等。在這種狀況下,原生的equals方法就不能知足咱們的需求了,因此這個時候咱們須要重寫equals方法,來知足咱們的業務系統上的需求。
- 那麼爲何在重寫equals方法的時候須要重寫hashCode方法呢? 若是隻重寫了equals方法而沒有重寫hashCode方法的話,則會違反約定的第二條:相等的對象必須具備相等的散列碼.因此hashCode和equals方法都須要重寫
能夠看網上這篇文章哈:java爲何要重寫hashCode和equals方法
Java 泛型(generics)是 JDK 5 中引入的一個新特性,其本質是參數化類型,解決不肯定具體對象類型的問題。
複製代碼
這個面試題,能夠看我這篇文章哈~Java程序員必備基礎:泛型解析
能夠看我這篇文章哈~ Java程序員必備:序列化全方位解析
匿名內部類就是沒有名字的內部類,平常開發中使用的比較多。
public class Outer {
private void test(final int i) {
new Service() {
public void method() {
for (int j = 0; j < i; j++) {
System.out.println("匿名內部類" );
}
}
}.method();
}
}
//匿名內部類必須繼承或實現一個已有的接口
interface Service{
void method();
}
複製代碼
匿名內部類還有如下特色:
能夠看我這篇文章哈~Java程序員必備基礎:內部類解析
沒有。由於 String 被設計成不可變(immutable)類,因此它的全部對象都是不可變對象。
1個而已啦。
Java 編譯器對字符串常量直接相加的表達式進行優化,不等到運行期去進行加法運算,在編譯時就去掉了加號,直接將其編譯成一個這些常量相連的結果。因此 "a"+"b"+"c"+"d" 至關於直接定義一個 "abcd" 的字符串。
try-catch-finally-return 執行描述:
看一個例子
public static void main(String[] args) throws IOException {
System.out.println("result:" + test());
}
private static int test() {
int temp = 1;
try {
System.out.println("start execute try,temp is:"+temp);
return ++temp;
} catch (Exception e) {
System.out.println("start execute catch temp is: "+temp);
return ++temp;
} finally {
System.out.println("start execute finally,temp is:" + temp);
++temp;
}
}
複製代碼
運行結果:
start execute try,temp is:1
start execute finally,temp is:2
result:2
複製代碼
分析:
++temp
表達式,temp變爲2,這個值被保存起來。++temp
表達式.try-with-resources,是Java7提供的一個新功能,它用於自動資源管理。
在try-with-resources
出現以前
try{
//open resources like File, Database connection, Sockets etc
} catch (FileNotFoundException e) {
// Exception handling like FileNotFoundException, IOException etc
}finally{
// close resources
}
複製代碼
Java7,try-with-resources
出現以後,使用資源實現
try(// open resources here){
// use resources
} catch (FileNotFoundException e) {
// exception handling
}
// resources are closed as soon as try-catch block is executed.
複製代碼
Java7使用資源demo
public class Java7TryResourceTest {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader(
"C:/jaywei.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
複製代碼
使用了try-with-resources
的好處
不能夠。
一個或兩個
- 第一次調用 new String("jay"); 時,會在堆內存中建立一個字符串對象,同時在字符串常量池中建立一個對象 "jay"
- 第二次調用 new String("jay"); 時,只會在堆內存中建立一個字符串對象,指向以前在字符串常量池中建立的 "jay"
能夠看老王這篇文章,很清晰~ 別再問我 new 字符串建立了幾個對象了!我來證實給你看!
this:
super:
能夠,咱們能夠作強制轉換,可是在Java中,int是32位,byte是8位,若是強制作轉化,int類型的高24位將會被丟棄。
public class Test {
public static void main(String[] args) {
int a =129;
byte b = (byte) a;
System.out.println(b);
int c =10;
byte d = (byte) c;
System.out.println(d);
}
}
輸出:
-127
10
複製代碼
不正確,精度不許確,應該用強制類型轉換
均可以的
參考這篇文章~ 同步和異步的區別
java中使用BigDecimal來表示價格是比較好的。
能夠看這篇文章,寫得很是好 老大說:誰要再用double定義商品金額,就本身收拾東西走
int數據類型佔4個字節 32位,跟JVM位數不要緊的