面經-Java基礎

HashMap、HashTable、ConCurrentHasgMap的區別以及實現原理?
ConCurrentHasgMap調用get()方法的時候有鎖嗎?

對于put和remove操作,是使用鎖同步來進行的,不過是用的ReentrantLock而不是synchronized,性能上要更高一些。它們的實現前文都已經提到過,就沒什么可分析的了。

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

使用final關鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內容還是可以改變的。例如,對于如下語句:

final StringBuffer a=new StringBuffer("immutable");
執行如下語句將報告編譯期錯誤:

a=new StringBuffer("");
但是,執行如下語句則可以通過編譯:

a.append(" broken!");

"=="和equals方法究竟有什么區別?

String a = new String("foo");
String b = new String("foo");
System.out.println(a == b);// false
System.out.println(a.equals(b));// true

默認的equals方法
public boolean equals(Object obj) {
return (this == obj);
}

String 類重寫了 equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

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

不可以。也就是說,當一個static方法被調用時,可能還沒有創建任何實例對象,如果從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪個對象上的呢?這個邏輯無法成立,所以,一個static方法內部發出對非static方法的調用。

Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math類中提供了三個與取整有關的方法:ceil、floor、round,這些方法的作用與它們的英文名稱的含義相對應,例如,ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結果為12,Math.ceil(-11.3)的結果是-11;floor的英文意義是地板,該方法就表示向下取整,Math.ceil(11.6)的結果為11,Math.ceil(-11.6)的結果是-12;最難掌握的是round方法,它表示“四舍五入”,算法為Math.floor(x+0.5),即將原來的數字加上0.5后再向下取整,所以,Math.round(11.5)的結果為12,Math.round(-11.5)的結果為-11。

請說出作用域public,private,protected,以及不寫時的區別

這四個作用域的可見范圍如下表所示。

說明:如果在修飾的元素上面沒有寫任何訪問修飾符,則表示friendly。

作用域 當前類 同一package 子孫類 其他package

public √ √ √ √

protected √ √ √ ×

friendly √ √ × ×

private √ × × ×

備注:只要記住了有4種訪問權限,4個訪問范圍,然后將全選和范圍在水平和垂直方向上分別按排從小到大或從大到小的順序排列,就很容易畫出上面的圖了。

Overloaded的方法是否可以改變返回值的類型?

至于Overloaded的方法是否可以改變返回值的類型這個問題,要看你倒底想問什么呢?這個題目很模糊。如果幾個Overloaded的方法的參數列表不一樣,它們的返回者類型當然也可以不一樣。但我估計你想問的問題是:如果兩個方法的參數列表完全一樣,是否可以讓它們的返回值不同來實現重載Overload。這是不行的,我們可以用反證法來說明這個問題,因為我們有時候調用一個方法時也可以不定義返回結果變量,即不要關心其返回結果,例如,我們調用map.remove(key)方法時,雖然remove方法有返回值,但是我們通常都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數列表完全相同的方法,僅僅是返回類型不同,java就無法確定編程者倒底是想調用哪個方法了,因為它無法通過返回結果類型來判斷。

構造器Constructor是否可被override?

構造器Constructor不能被繼承,因此不能重寫Override,但可以被重載Overload。

面向對象的特征有哪些方面?封裝 繼承 多態 抽象

java中的匿名內部類總結

匿名內部類也就是沒有名字的內部類
正因為沒有名字,所以匿名內部類只能使用一次,它通常用來簡化代碼編寫
但使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個接口

Thread類的匿名內部類實現

Runnable接口的匿名內部類實現

String是最基本的數據類型嗎?

基本數據類型包括byte、int、char、long、float、double、boolean和short。

java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。為了提高效率節省空間,我們應該用StringBuffer類

是否可以繼承String類?

String類是final類故不可以繼承

重寫equals()時為什么也得重寫hashCode()之深度解讀equals方法與hashCode方法淵源

使用hashCode()和equals()

hashCode()方法被用來獲取給定對象的唯一整數。這個整數被用來確定對象被存儲在HashTable類似的結構中的位置。默認的,Object類的hashCode()方法返回這個對象存儲的內存地址的編號。

String、Math等封裝類都對equals()方法進行了重寫。下面是String的equals()方法。

數組有沒有length()這個方法? String有沒有length()這個方法?

數組沒有length()這個方法,有length的屬性。String有有length()這個方法。

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

try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執行,什么時候被執行,在return前還是后?

答案是在return之前 但是return 的結果不會被finally 的運行改變

finally中的代碼比return和break語句后執行

final, finally, finalize的區別。

final 用于聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。

內部類要訪問局部變量,局部變量必須定義成final類型,例如,一段代碼……

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

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

不同類型的異常分別用不同的Java類表示,所有異常的根類為java.lang.Throwable,Throwable下面又派生了兩個子類:Error和Exception

編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,所以普通異常也稱為checked異常,而系統異常可以處理也可以不處理,所以,編譯器不強制用try..catch處理或用throws聲明,所以系統異常也稱為unchecked異常。

提示答題者:就按照三個級別去思考:虛擬機必須宕機的錯誤,程序可以死掉也可以不死掉的錯誤,程序不應該死掉的錯誤;

請寫出你最常見到的5個runtime exception。

NullPointerException、ArrayIndexOutOfBoundsException、ClassCastException。

啟動一個線程是用run()還是start()? .

啟動一個線程是調用start()方法,使線程就緒狀態,以后可以被調度為運行狀態,一個線程必須關聯一些具體的執行代碼,run()方法是該線程所關聯的執行代碼。

java中有幾種方法可以實現一個線程?用什么關鍵字修飾同步方法? stop()和suspend()方法為何不推薦使用?

new Thread(){

public void run(){

}

}.start();

new Thread(new Runnable(){

           public voidrun(){

           }   

    }

).start();

ExecutorService pool = Executors.newFixedThreadPool(3)

for(int i=0;i<10;i++)

{

pool.execute(newRunable(){public void run(){}});

}

Executors.newCachedThreadPool().execute(new Runable(){publicvoid run(){}});

Executors.newSingleThreadExecutor().execute(new Runable(){publicvoid run(){}});
用synchronized關鍵字修飾同步方法

sleep()和 wait()有什么區別?

 (網上的答案:sleep是線程類(Thread)的方法,導致此線程暫停執行指定時間,給執行機會給其他線程,但是監控狀態依然保持,到時后會自動恢復。調用sleep不會釋放對象鎖。 wait是Object類的方法,對此對象調用wait方法導致本線程放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象發出notify方法(或notifyAll)后本線程才進入對象鎖定池準備獲得對象鎖進入運行狀態。)

同步和異步有何異同,在什么情況下分別使用他們?舉例說明。

如果數據將在線程間共享。例如正在寫的數據以后可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那么這些數據就是共享數據,必須進行同步存取。

當應用程序在對象上調用了一個需要花費很長時間來執行的方法,并且不希望讓程序等待方法的返回時,就應該使用異步編程,在很多情況下采用異步途徑往往更有效率。

多線程有幾種實現方法?同步有幾種實現方法?

多線程有兩種實現方法,分別是繼承Thread類與實現Runnable接口

同步的實現方面有兩種,分別是synchronized,wait與notify

Object.wait():使一個線程處于等待狀態,并且釋放所持有的對象的lock。

Thread.sleep():使一個正在運行的線程處于睡眠狀態,是一個靜態方法,調用此方法要捕捉InterruptedException(中斷異常)異常。

Object.notify():喚醒一個處于等待狀態的線程,注意的是在調用此方法的時候,并不能確切的喚醒某一個等待狀態的線程,而是由JVM確定喚醒哪個線程,而且不是按優先級。

Object.Allnotity():喚醒所有處入等待狀態的線程,注意并不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。

簡述synchronized和java.util.concurrent.locks.Lock的異同?

主要相同點:Lock能完成synchronized所實現的所有功能

主要不同點:Lock有比synchronized更精確的線程語義和更好的性能。synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。Lock還有更強大的功能,例如,它的tryLock方法可以非阻塞方式去拿鎖。

Java集合框架是什么?說出一些集合框架的優點?

每種編程語言中都有集合,最初的Java版本包含幾種集合類:Vector、Stack、HashTable和Array。

為何Map接口不繼承Collection接口?

盡管Map接口和它的實現也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map繼承Collection毫無意義,反之亦然

Enumeration和Iterator接口的區別?

Enumeration的速度是Iterator的兩倍,也使用更少的內存。Enumeration是非常基礎的,也滿足了基礎的需要。但是,與Enumeration相比,Iterator更加安全,因為當一個集合正在被遍歷的時候,它會阻止其它線程去修改集合。

迭代器取代了Java集合框架中的Enumeration。迭代器允許調用者從集合中移除元素,而Enumeration不能做到。為了使它的功能更加清晰,迭代器方法名已經經過改善。

如何決定選用HashMap還是TreeMap?

對于在Map中插入、刪除和定位元素這類操作,HashMap是最好的選擇。然而,假如你需要對一個有序的key集合進行遍歷,TreeMap是更好的選擇。基于你的collection的大小,也許向HashMap中添加元素會更快,將map換為TreeMap進行有序key的遍歷。

ArrayList和Vector的不同點。

(1)Vector是同步的,而ArrayList不是。然而,如果你尋求在迭代的時候對列表進行改變,你應該使用CopyOnWriteArrayList。

(2)ArrayList比Vector快,它因為有同步,不會過載。

(3)ArrayList更加通用,因為我們可以使用Collections工具類輕易地獲取同步列表和只讀列表。

Comparable和Comparator接口有何區別?

Comparable和Comparator接口被用來對對象集合或者數組進行排序。Comparable接口被用來提供對象的自然排序,我們可以使用它來提供基于單個邏輯的排序。

Comparator接口被用來提供不同的排序算法,我們可以選擇需要使用的Comparator來對給定的對象集合進行排序。

當一個集合被作為參數傳遞給一個函數時,如何才可以確保函數不能修改它?

在作為參數傳遞之前,我們可以使用Collections.unmodifiableCollection(Collection c)方法創建一個只讀集合,這將確保改變集合的任何操作都會拋出UnsupportedOperationException。

我們如何從給定集合那里創建一個synchronized的集合?

我們可以使用Collections.synchronizedCollection(Collection c)根據指定集合來獲取一個synchronized(線程安全的)集合。

使用JDK提供的不可變類作為Map的key,可以避免自己實現hashCode()和equals()。

(6)盡可能使用Collections工具類,或者獲取只讀、同步或空的集合,而非編寫自己的實現。它將會提供代碼重用性,它有著更好的穩定性和可維護性。

一般會把List初始化成一個合適的大小,以減少調整大小的次數。

HashMap和Hashtable之間的區別?
同步或線程安全
Null鍵和Null值
迭代值
默認容量大小

更多HashMap和Hashtable之間的區別請點擊這里

Java 中 Set 與 List 有什么不同?

Set是一個不允許重復元素存在的集合
Set沒有索引
Set僅僅允許一個null值
Set有類:HashSet、LinkedHashMap、TreeSet
List有索引
List允許N個null值
List可以按插入順序顯示
List有類:Vector、ArrayList、LinkedList
Vector 在Java的第一個版本就引入了,也就是說vector是一個合法規范的類
ArrayList在Java1.2版本引入的,是Java 集合框架的組成部分
Vector是同步的
ArrayList是不同步的

什么類實現了List接口?

ArrayList
LinkedList
Vector

什么類實現了Set接口?

HashSet
LinkedHashSet
TreeSet

如何保證一個集合線程安全?

Vector, Hashtable, Properties 和 Stack 都是同步的類,所以它們都線程安全的,可以被使用在多線程環境中
使用Collections.synchronizedList(list)) 方法,可以保證list類是線程安全的
使用java.util.Collections.synchronizedSet()方法可以保證set類是線程安全的

HashSet 實現了哪個數據結構?

HashSet 內部實現了hashmap

為什么沒有類似Iterator.add()這樣的方法來向集合中添加元素?

如果迭代器無法保證迭代的順序,那么這種說法是不清晰的(unclear)。注意的是,ListIterator就提供了add()方法,因為它能保證迭代的順序。

在迭代一個集合時如何避免ConcurrentModificationException?

可以使用并發集合類來遍歷集合從而避免ConcurrentModificationException異常。例如, 使用CopyOnWriteArrayList 來替代 ArrayList.

對于HashMap,還要著重了解的是初始容量(capacity)、加載因子(load factor)、自動擴容(threshold resizing)機制。HashMap默認初始容量是32,加載因子是0.75。閾值(threshold)=初始容量x加載因子,當map的大小超過 閾值時,則要對該哈希表進行rehash 操作,即重建內部數據結構(這一過程可能會引起性能問題),從而哈希表將具有大約兩倍的容量,容量通常是2的冪次方。因此,如果能估測出元素的數量,那么最好在初始化HashMap時指定合適的capacity和 load factor。

正確 地實現這兩個方法是非常重要的 要實現它們,請遵循以下原則:

If o1.equals(o2), 那么o1.hashCode() == o2.hashCode()總為真。
Ifo1.hashCode() == o2.hashCodeis 為真, 并不意味著 o1.equals(o2)也為真。

Hashtable是一種比較基礎的類,如果想在迭代時對map進行修改,那么應該使用 ConcurrentHashMap

怎樣決定何時使用HashMap何時使用TreeMap?

對 于插入、刪除、定位元素頻繁的操作,HashMap提供了最好的效率。如果想要按key的排序來遍歷,那么TreeMap是不二選擇。某些情況下,依賴集 合的大小,先向HashMap中添加元素,然后轉換為TreeMap再按key的排序進行遍歷也許會帶來效率上的提高。

哪些集合類是線程安全的?

Vector, Hashtable, Properties and Stack都是同步的(synchronized)類,因此是線程安全的,可以在多線程環境下使用. Java 1.5 Concurrent API 引入了一些允許在迭代過程中可以修改集合的并發類,由于它們會在迭代時會clone一份集合,所以在多線程環境下也是安全的。

Java集合框架都有哪些最佳實踐?

要根據需求來選擇正確的容器類型,例如,如果大小固定,也許選擇Array就比ArrayList更明智。如果想按插入順序對Map進行迭代,那么需要選TreeMap。如果集合不允許重復,那么就應該選Set。
某些集合類允許指定初始容量,如果我們能粗略的估計下要存儲元素的數量,那么我們就可能避免重新hash(rehashing)和自動擴容(resizing)所帶來的某些性能問題。
要針對接口編程而不是針對實現編程,這允許我們以后可以輕松的變更實現。
要盡可能的使用泛型以保證類型安全,從而避免運行時的ClassCastException異常。
使用JDK提供的不可變的(immutable)類型來作為Map的鍵,從而避免自己實現hashCode() 和equals()方法。
盡可能多的使用Collections這一工具類,因為我們可以很輕松的調用它已實現的算法或用來獲取只讀的、同步的或空的集合對象,從而避免自己實現。這會極大的提高代碼的復用性、穩定性,降低維護成本。

在多線程并發編程中synchronized和Volatile都扮演著重要的角色,Volatile是輕量級的synchronized,它在多處理器開發中保證了共享變量的“可見性”。可見性的意思是當一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值。

Volatile變量修飾符如果使用恰當的話,它比synchronized的使用和執行成本會更低,因為它不會引起線程上下文的切換和調度。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容