java基礎
1. 抽象、繼承 和 多態
抽象:就是對一些具有共同特征的對象,抽象出一個具有共同特征的類;這個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象類往往用來表征我們在對問題領域進行分析、 設計中得出的抽象概念
繼承:當兩個類具有相同的特征(屬性)和行為(方法)時,可以將相同的部分抽取出來放到一個類中作為父類,其它兩個類繼承這個父類。繼承后子類自動擁有了父類的屬性和方法,但特別注意的是,父類的私有屬性和構造方法并不能被繼承。
多態:相同的事務,調用其相同的方法,屬性值也相同,但表現的行為卻不同
三個必要條件: 繼承,重寫,向上轉型
2. 泛型的作用及其使用場景
泛型定義類和接口的時候使用類型參數(type parameter)。聲明的類型參數在使用時用具體的類型來替換。
作用:能夠更好的保護數據類型,避免編譯時出錯。減少類型轉換的代碼。
使用場景:配合抽象類說
3. 枚舉的特點及使用場景
它被用來將一組類似的值包含到一種類型當中。而這種枚舉類型的名稱則會被定義成獨一無二的類型描述符,在這一點上和常量的定義相似。不過相比較常量類型,枚舉類型可以為申明的變量提供更大的取值范圍。
使用:
1,枚舉常量沒有任何修飾符
2,每個常量以“,”分隔,以“;”結束枚舉常量的描述。
3,枚舉常量必須定義在所有方法或者構造器之前
4. JAVA反射機制
只要有了java.lang.Class類 的對象,就可以通過其中的方法來獲取到該類中的構造方法、域和方法。對應的方法分別是getConstructor、getField和getMethod。類繼承自哪個類 實現了哪些接口 有哪些屬性 有哪些方法 有哪些構造方法
5. weak/soft/strong引用的區別
1、強引用(StrongReference)
如果一個對象具有強引用,那垃圾回收器絕不會回收它。顯式地設置o為null,或超出對象的生命周期范圍,則gc認為該對象不存在引用,這時就可以回收這個對象。具體什么時候收集這要取決于gc的算法。
2、 軟引用(SoftReference)
如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。
3、弱引用(WeakReference)
只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由于垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。
4、虛引用(PhantomReference)
如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
java集合類
1. JAVA常用集合類功能、區別和性能
List系列
-
ArrayList
ArrayList
以數組實現,允許重復。超出限制時會增加50%的容量(grow()方法中實現,如下所示),每次擴容都底層采用System.arrayCopy()
復制到新的數組,因此最好能給出數組大小的預估值。默認第一次插入元素時創建數組的大小為10. -
LinkedList
LinkedList
以雙向鏈表實現,允許重復。(如下Node
的實現)并保留頭指針和尾指針。鏈表無容量限制,但雙向鏈表本身使用了更多空間,也需要額外的鏈表指針操作。
按下標訪問元素—get(i)/set(i,e)
要悲劇的遍歷鏈表將指針移動到位(如果i>數組大小的一半,會從末尾移起)。 -
Vector
Vector
和ArrayList
幾乎是完全相同的,唯一的區別在于Vector
是同步類(synchronized
),屬于強同步類。Vector
每次請求其大小的雙倍空間,而ArrayList每次對size增長50%. -
Stack
Stack
繼承自Vector
,實現了一個后進先出的堆棧。
ArrayList和LinkedList的區別
-
ArrayList
是實現了基于動態數組的數據結構,LinkedList
基于鏈表的數據結構。 - 對于隨機訪問
get
和set
,ArrayList
覺得優于LinkedList
,因為LinkedList
要移動指針。 - 對于新增和刪除操作
add
和remove
,LinkedList
比較占優勢,因為ArrayList
要移動數據。
ArrayList和Vector的區別
-
Vector
和ArrayList
幾乎是完全相同的,唯一的區別在于Vector
是同步類(synchronized),屬于強同步類。因此開銷就比ArrayList
要大,訪問要慢。正常情況下,大多數的Java程序員使用ArrayList
而不是Vector
,因為同步完全可以由程序員自己來控制。 -
Vector
每次擴容請求其大小的2倍空間,而ArrayList
是1.5倍。 -
Vector
還有一個子類Stack
.
Map
-
HashMap
通過hash
的方法,通過put
和get
存儲和獲取對象。存儲對象時,我們將K/V
傳給put
方法時,它調用hashCode
計算hash
從而得到bucket
位置,進一步存儲,HashMap
會根據當前bucket
的占用情況自動調整容量(超過Load Factor
則resize
為原來的2倍)。獲取對象時,我們將K
傳給get
,它調用hashCode
計算hash
從而得到bucket
位置,并進一步調用equals()
方法確定鍵值對。如果發生碰撞的時候,Hashmap
通過鏈表將產生碰撞沖突的元素組織起來,在Java 8
中,如果一個bucket
中碰撞沖突的元素超過某個限制(默認是8),則使用紅黑樹來替換鏈表,從而提高速度。
HashMap
的容量(Capacity
)是 16,負載因子(load factor
是0.75 -
LinkedhashMap
LinkedHashMap
是Hash
表和鏈表的實現,并且依靠著雙向鏈表保證了迭代順序是插入的順序。非線程安全,LinkedHashMap
會記錄插入的順序,允許null
的鍵值,當key
值重復時,后面的會替換前面的。 -
TreeHash
紅黑樹實現 -
HashTable
HashMap
幾乎可以等價于Hashtable
,除了HashMap
是非synchronized
的,并可以接受null
-
WeakHashMap
WeakHashMap
實現了Map
接口,是HashMap
的一種實現,它比HashMap
多了一個引用隊列.
博主認真比對過WeakHashMap
和HashMap
的源碼,發現WeakHashMap
中方法的實現方式基本和HashMap
的一樣,注意“基本”兩個字,除了沒有實現Cloneable和Serializable
這兩個標記接口,最大的區別在于在于expungeStaleEntries()
這個方法,這個是整個WeakHashMap
的精髓:每調用一次expungeStaleEntries()
方法,就會在引用隊列中尋找是否有被清楚的key
對象,如果有則在table
中找到其值,并將value
設置為null
,next
指針也設置為null
,讓GC去回收這些資源。 -
EnumMap
EnumMap
是專門為枚舉類型量身定做的Map
實現。雖然使用其它的Map
實現(如HashMap
)也能完成枚舉類型實例到值得映射,但是使用EnumMap
會更加高效:它只能接收同一枚舉類型的實例作為鍵值,并且由于枚舉類型實例的數量相對固定并且有限,所以EnumMap
使用數組來存放與枚舉類型對應的值。這使得EnumMap
的效率非常高。EnumMap
在內部使用枚舉類型的ordinal()
得到當前實例的聲明次序,并使用這個次序維護枚舉類型實例對應值在數組的位置。
HashMap
與HashTable
的區別
-
HashTable
是線程安全的,多個線程可以共享一個Hashtable
;而如果沒有正確的同步的話,多個線程是不能共享HashMap
的。 - 另一個區別是
HashMap
的迭代器(Iterator)是fail-fast
迭代器,而Hashtable
的enumerator
迭代器不是fail-fast
的。 -
Hashtable
和HashMap
它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTable
中hash
數組默認大小是11,增加的方式是 old*2+1。HashMap
中hash
數組的默認大小是16,而且一定是2的指數。
Set:
Set
幾乎都是內部用一個Map
來實現, 因為Map
里的KeySet
就是一個Set
,而value
是假值,全部使用同一個Object
。Set
的特征也繼承了那些內部Map
實現的特征。
HashSet
HashSet
是基于HashMap
來實現的,操作很簡單,更像是對HashMap
做了一次“封裝”,而且只使用了HashMap的key
來實現各種特性,而HashMap
的value
始終都是PRESENT
。
HashSet
不允許重復(HashMap
的key不允許重復,如果出現重復就覆蓋),允許null
值,非線程安全。
LinkHashSet
LinkedHashSet
就是基于LinkedHashMap
實現的,允許null
值,保留插入順序,非線程安全。
TreeSet
TreeSet
的內部基于TreeMap
實現,同樣value
永遠為PRESENT
.
不允許重復,不允許null
值(如果有基于null的比較器,就可以允許為null),默認按升序排列。
2.并發相關的集合類
-
Collections 類提供的并發集合
java.util.Collections提供了一系列方法將一個普通的集合包裝成線程安全的集合,如Collections.synchronizedCollection() Collections.synchronizedSet()
等。
它們的實現很簡單,Collections
內部定義了一系列集合類,它們的作用就是包裝用戶傳進來的集合并把操作都代理給后者,唯一不同的是,這些內部集合類的每個方法都是synchronized
的,保證每個方法的互斥,雖然正確,但是效率不高,不推薦使用。
- JUC 提供的并發集合
ConcurrentHashMap
拆分鎖
一個動作只會影響結構的一部分,則把整體拆分成若干部分,每個部分一個鎖,部分A被鎖不會影響部分B,從而提高并發程度。
hashcode 決定桶的位置,equals決定兩個對象是否相同。
內部用若干 segment
保存 entry
;每個segment
是一個小hashmap
,它繼承 ReentrantLock
,內部的 update
動作均須先加鎖。segment
個數由參數concurrencyLevel
決定。
put/remove
首先找segmengt
,后者先加鎖,再操作。put
插入時是插在鏈表頭;remove
先找元素,再執行一個普通的鏈表節點刪除操作。
Segment
的 rehash
是不加鎖的,它先創建一個新的空數組,接著將元素 rehash
到該數組,最后將新數組和舊數組切換。
get/contains/iterator
讀取操作不加鎖,這是因為put/remove
動作對數據結構的改變最終是個原子動作(put
是一個對數組元素Entry
指針的賦值操作;remove
是一個對 entry.next
的賦值操作,rehash是一個對數組引用的賦值操作),因此read
不會看到一個更新動作的中間狀態;但它可能和并發的put/remove
方法調用重疊,它所看到的狀態是其所在Segment
在最后一個完成的update
動作后的狀態,正在進行但未完成的put/remove
對read是不可見的,如果前者先于read
完成,read
是有可能看到臟數據的。
沒有提供鎖全部segment
的方法,size
的實現是先走幾次fast-path
,即不加鎖統計所有segment的count
和modcount
兩次,如果modcount
發生改變,說明有并發操作,需要重新統計。如果重復該動作3次依然有問題,則依次對所有segment
加鎖,統計count
。
CopyOnWriteArrayList
** copyonwrite **
所有的update動作都加鎖,且對當前結構創建一個snapshot,在snapshot上完成update動作后,再將其轉正,丟棄原結構 **
add/remove/set
均使用同一把 reentrantlock
實現互斥,并復制一份當前的數組,在該數組上完成write動作,最后用一個原子的引用賦值動作將snapshot
切換為當前數組;即內部數組永遠不會改變結構(readonly),只會發生整個數組的切換。
get不加鎖,和ConcurrentHashMap
類似,由于write
動作最終實質上是個原子的引用切換動作,因此get
看到的要么是修改完成前的數組,要么是完成后的數組,它不會看到一個不穩定的中間狀態,它也是不用加鎖的。read
看到的也是最后一個完成的write
后的數組,但很可能read
時依然有進行中的write
動作,這對read
而言是不可見的,但如果它先于read
完成,read
是有可能讀到臟數據的。
CopyOnWriteArraySet:
基于 CopyOnWriteArrayList
實現,add
時創建數組副本,并用equals
判重。
不是hashset
那種實現,和hashcode
沒關系。
BlockQueue接口
阻塞隊列,它實質上就是一種帶有一點扭曲的 FIFO
數據結構。它提供了可阻塞的put
和take
方法。如果Queue
已經滿了,put
方法會被阻塞直到有空間可用;如果Queue
是空的,那么take
方法會被阻塞,直到有元素可用。Queue
的長度可用有限,也可以無限;無限的Queue
永遠不會充滿,所以它的put
方法永遠不會被阻塞。阻塞隊列支持生產者-消費者設計模式。
BlockingQueue
接口的幾個主要的實現類:
-
ArrayBlockingQueue
:一個由數組支持的有界隊列。 -
LinkedBlockingQueue
:一個由鏈接節點支持的可選有界隊列。 -
PriorityBlockingQueue
:一個由優先級堆支持的無界優先級隊列。 -
DelayQueue
:一個由優先級堆支持的、基于時間的調度隊列。 -
SynchronousQueue
:一個利用BlockingQueue
接口的簡單聚集(rendezvous)機制。
3. 部分常用集合類的內部實現方式
java線程
1. 線程sleep和wait的區別
Java程序中wait
和sleep
都會造成某種形式的暫停,它們可以滿足不同的需要。wait()
方法用于線程間通信,如果等待條件為真且其它線程被喚醒時它會釋放鎖,而sleep()
方法僅僅釋放CPU資源或者讓當前線程停止執行一段時間,但不會釋放鎖。需要注意的是,sleep()
并不會讓線程終止,一旦從休眠中喚醒線程,線程的狀態將會被改變為Runnable
,并且根據線程調度,它將得到執行。
3. Thread、Runnable、Callable、Futrue類關系與區別
Thread
:
在java中可有兩種方式實現多線程,一種是繼承Thread
類,一種是實現Runnable
接口。但是最終被線程執行的是Runnable
,而非Thread
,Thread
僅僅是對于Runnable
的包裝。
public class Thread extends Object implements Runnable```
`Runnable`:
它只有一個`run()`函數,用于將耗時操作寫在其中,**該函數沒有返回值**。然后使用某個線程去執行該`runnable`即可實現多線程,`Thread`類在調用`start()`函數后就是執行的是`Runnable`的`run()`函數
public interface Runnable {
public abstract void run();
}```
Callable
:
Callable
與Runnable
的功能大致相似,Callable
中有一個call()
函數,但是call()
函數有返回值,而Runnable
的run()
函數不能將結果返回給客戶程序
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}```
`Future`:
`Future`就是對于具體的`Runnable`或者`Callable`任務的執行結果進行取消、查詢是否完成、獲取結果。必要時可以通過`get`方法獲取執行結果,該方法會阻塞直到任務返回結果。
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning); //取消任務
boolean isCancelled(); //判斷任務是否被取消
boolean isDone(); //任務是否已經完成
V get() throws InterruptedException, ExecutionException;//用來獲取執行結果,這個方法會產生阻塞,會一直等到任務執行完畢才返回;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException; //用來獲取執行結果,如果在指定時間內,還沒獲取到結果,就直接返回null。
}```
FutureTask
:
我們先來看一下FutureTask的實現:
public class FutureTask<V> implements RunnableFuture<V>```
`FutureTask`類實現了`RunnableFuture接口`,我們看一下`RunnableFuture`接口的實現:
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}```
可以看出RunnableFuture
繼承了Runnable
接口和Future
接口,而FutureTask
實現了RunnableFuture
接口。所以它既可以作為Runnable
被線程執行,又可以作為Future
得到Callable
的返回值。
FutureTask提供了2個構造器:
public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}```
事實上,FutureTask是Future接口的一個唯一實現類。
#### 4. wait、 sleep、 join 、yield、notify、 notifyAll
`wait`:
wait()方法使當前線程暫停執行并釋放對象鎖標志,讓其他線程可以進入Synchronized數據塊,當前線程被放入對象等待池中。
`sleep`:
使當前線程(即調用該方法的線程)暫停執行一段時間,讓其他線程有機會繼續執行,但它并不釋放對象鎖。
`join`:
調用該方法的線程在此之前執行完畢,也就是等待調用該方法的線程執行完畢后再往下繼續執行。注意該方法也要捕獲異常。
`yield`:
停止當前線程,讓同等優先權的線程運行。如果沒有同等優先權的線程,那么`Yield()`方法將不會起作用。
`notify`:
喚醒在此對象監視器上等待的單個線程。當它被一個`notify()`方法喚醒時,等待池中的線程就被放到了鎖池中。該線程將等待從鎖池中獲得機鎖,然后回到wait()前的中斷現場。
`notifyAll`:
notifyAll()則從對象等待池中移走所有等待那個對象的線程并放到鎖標志等待池中。
#### 5.JDK中默認提供了哪些線程池,有何區別
`newSingleThreadExecutor`
創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當于單線程串行執行所有任務。如果這個唯一的線程因為異常結束,那么會有一個新的線程來替代它。此線程池保證所有任務的執行順序按照任務的提交順序執行。
`newFixedThreadPool`
創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那么線程池會補充一個新線程。
`newCachedThreadPool`
創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那么就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(或者說JVM)能夠創建的最大線程大小。
`newScheduledThreadPool`
創建一個大小無限的線程池。此線程池支持定時以及周期性執行任務的需求。
#### 6. 線程同步有幾種方式,分別闡述在項目中的用法
同步方法、同步代碼塊、Volatile、可重入鎖ReentreentLock、局部變量ThreadLocal
#### 7. 在理解默認線程池的前提下,自己實現線程池
package mine.util.thread;
import java.util.LinkedList;
import java.util.List;
/**
-
線程池類,線程管理器:創建線程,執行任務,銷毀線程,獲取線程基本信息
*/
public final class ThreadPool {
// 線程池中默認線程的個數為5
private static int worker_num = 5;
// 工作線程
private WorkThread[] workThrads;
// 未處理的任務
private static volatile int finished_task = 0;
// 任務隊列,作為一個緩沖,List線程不安全
private List<Runnable> taskQueue = new LinkedList<Runnable>();
private static ThreadPool threadPool;// 創建具有默認線程個數的線程池
private ThreadPool() {
this(5);
}// 創建線程池,worker_num為線程池中工作線程的個數
private ThreadPool(int worker_num) {
ThreadPool.worker_num = worker_num;
workThrads = new WorkThread[worker_num];
for (int i = 0; i < worker_num; i++) {
workThrads[i] = new WorkThread();
workThrads[i].start();// 開啟線程池中的線程
}
}// 單態模式,獲得一個默認線程個數的線程池
public static ThreadPool getThreadPool() {
return getThreadPool(ThreadPool.worker_num);
}// 單態模式,獲得一個指定線程個數的線程池,worker_num(>0)為線程池中工作線程的個數
// worker_num<=0創建默認的工作線程個數
public static ThreadPool getThreadPool(int worker_num1) {
if (worker_num1 <= 0)
worker_num1 = ThreadPool.worker_num;
if (threadPool == null)
threadPool = new ThreadPool(worker_num1);
return threadPool;
}// 執行任務,其實只是把任務加入任務隊列,什么時候執行有線程池管理器覺定
public void execute(Runnable task) {
synchronized (taskQueue) {
taskQueue.add(task);
taskQueue.notify();
}
}// 批量執行任務,其實只是把任務加入任務隊列,什么時候執行有線程池管理器覺定
public void execute(Runnable[] task) {
synchronized (taskQueue) {
for (Runnable t : task)
taskQueue.add(t);
taskQueue.notify();
}
}// 批量執行任務,其實只是把任務加入任務隊列,什么時候執行有線程池管理器覺定
public void execute(List<Runnable> task) {
synchronized (taskQueue) {
for (Runnable t : task)
taskQueue.add(t);
taskQueue.notify();
}
}// 銷毀線程池,該方法保證在所有任務都完成的情況下才銷毀所有線程,否則等待任務完成才銷毀
public void destroy() {
while (!taskQueue.isEmpty()) {// 如果還有任務沒執行完成,就先睡會吧
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 工作線程停止工作,且置為null
for (int i = 0; i < worker_num; i++) {
workThrads[i].stopWorker();
workThrads[i] = null;
}
threadPool=null;
taskQueue.clear();// 清空任務隊列
}// 返回工作線程的個數
public int getWorkThreadNumber() {
return worker_num;
}// 返回已完成任務的個數,這里的已完成是只出了任務隊列的任務個數,可能該任務并沒有實際執行完成
public int getFinishedTasknumber() {
return finished_task;
}// 返回任務隊列的長度,即還沒處理的任務個數
public int getWaitTasknumber() {
return taskQueue.size();
}// 覆蓋toString方法,返回線程池信息:工作線程個數和已完成任務個數
@Override
public String toString() {
return "WorkThread number:" + worker_num + " finished task number:"
+ finished_task + " wait task number:" + getWaitTasknumber();
}/**
-
內部類,工作線程
*/
private class WorkThread extends Thread {
// 該工作線程是否有效,用于結束該工作線程
private boolean isRunning = true;/*
- 關鍵所在啊,如果任務隊列不空,則取出任務執行,若任務隊列空,則等待
*/
@Override
public void run() {
Runnable r = null;
while (isRunning) {// 注意,若線程無效則自然結束run方法,該線程就沒用了
synchronized (taskQueue) {
while (isRunning && taskQueue.isEmpty()) {// 隊列為空
try {
taskQueue.wait(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!taskQueue.isEmpty())
r = taskQueue.remove(0);// 取出任務
}
if (r != null) {
r.run();// 執行任務
}
finished_task++;
r = null;
}
}
// 停止工作,讓該線程自然執行完run方法,自然結束
public void stopWorker() {
isRunning = false;
}
}
} ``` - 關鍵所在啊,如果任務隊列不空,則取出任務執行,若任務隊列空,則等待
-
- 九種基本數據類型的大小,以及他們的封裝類。
byte 8 Byte
short 16 Short
int 32 Integer
long 64 Long
float 32 Float
double 64 Double
char 16 Char
boolean Boolean
- Switch能否用string做參數?
可以自動轉換為整型的(byte,short,int),String
類型,枚舉類型。
Java中不能做為Switch參數的有boolean,float,double,long
(不能直接轉換為int
啊)。 - equals與==的區別。
1.==是判斷兩個變量或實例是不是指向同一個內存空間
equals是判斷兩個變量或實例所指向的內存空間的值是不是相同
2.==是指對內存地址進行比較
equals()是對字符串的內容進行比較
3.==指引用是否相同
equals()指的是值是否相同 - Object有哪些公用方法?
clone
getClass
toString
finalize
equals
hashCode
wait
notify
notifyAll
- Java的四種引用,強弱軟虛,用到的場景。
見上面
-
Hashcode
的作用。
set和map中的元素無序不重復
哈希算法也稱為散列算法,是將數據依特定算法直接指定到一個地址上。這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode
方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以 直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就調用它的equals
方法與新元素進行比較,相同的話就不存了;不相同,也就是發生了Hash key
相同導致沖突的情況,那么就在這個Hash key
的地方產生一個鏈表,將所有產生相同hashcode
的對象放到這個單鏈表上去,串在一起。 - ArrayList、LinkedList、Vector的區別。
見上面
- String、StringBuffer與StringBuilder的區別。
String
類型和StringBuffer
類型的主要性能區別其實在于 String 是不可變的對象, 因此在每次對String
類型進行改變的時候其實都等同于生成了一個新的String
對象,然后將指針指向新的String
對象
StringBuild(線程不安全) > StringBuffer(線程安全) > String
- Map、Set、List、Queue、Stack的特點與用法。
- HashMap和HashTable的區別。
- HashMap和ConcurrentHashMap的區別,HashMap的底層源碼。
- TreeMap、HashMap、LindedHashMap的區別。
見上面
- Collection包結構,與Collections的區別。
- Collection 是一個集合接口(集合類的一個頂級接口)。它提供了對集合對象進行基本操作的通用接口方法
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set - java.util.Collections 是一個包裝類(工具類/幫助類)。它包含有各種有關集合操作的靜態多態方法。此類不能實例化
- try catch finally,try里有return,finally還執行么?
-
try
語句沒有被執行到,如在try
語句之前就返回了,這樣finally
語句就不會執行,這也說明了finally
語句被執行的必要而非充分條件是:相應的try語句一定被執行到。 - 在try塊中有
System.exit(0)
;這樣的語句,System.exit(0)
;是終止Java虛擬機JVM
的,連JVM
都停止了,所有都結束了,當然finally
語句也不會被執行到。
- Excption與Error包結構。OOM你遇到過哪些情況,SOF你遇到過哪些情況。
Throwable------Error
|
Exception------RuntimeException
Throwable
是 Java 語言中所有錯誤或異常的超類。
Exception
及其子類是Throwable
的一種形式,它指出了合理的應用程序想要捕獲的條件
RuntimeException
是那些可能在 Java 虛擬機正常運行期間拋出的異常的超類。
Error
也是Throwable
的子類。 它用于指示合理的應用程序不應該試圖捕獲的嚴重問題,大多數這樣的錯誤都是異常條件。
Java將可拋出(Throwable)的結構分為三種類型: 被檢查的異常(Checked Exception),運行時異常(RuntimeException)和錯誤(Error)。
OOM
1,OutOfMemoryError異常
除了程序計數器外,虛擬機內存的其他幾個運行時區域都有發生OutOfMemoryError(OOM)
異常的可能,
Java Heap
溢出
一般的異常信息:java.lang.OutOfMemoryError:Java heap spacess
java堆用于存儲對象實例,我們只要不斷的創建對象,并且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象,就會在對象數量達到最大堆容量限制后產生內存溢出異常。
出現這種異常,一般手段是先通過內存映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,重點是確認內存中的對象是否是必要的,先分清是因為內存泄漏(Memory Leak)還是內存溢出(Memory Overflow)。
如果是內存泄漏,可進一步通過工具查看泄漏對象到GC Roots的引用鏈。于是就能找到泄漏對象時通過怎樣的路徑與GC Roots相關聯并導致垃圾收集器無法自動回收。
如果不存在泄漏,那就應該檢查虛擬機的參數(-Xmx與-Xms)的設置是否適當。
2,虛擬機棧和本地方法棧溢出
如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError
異常。
如果虛擬機在擴展棧時無法申請到足夠的內存空間,則拋出OutOfMemoryError
異常
這里需要注意當棧的大小越大可分配的線程數就越少。
3,運行時常量池溢出
異常信息:java.lang.OutOfMemoryError:PermGen space
如果要向運行時常量池中添加內容,最簡單的做法就是使用String.intern()
這個Native
方法。該方法的作用是:如果池中已經包含一個等于此String
的字符串,則返回代表池中這個字符串的String
對象;否則,將此String
對象包含的字符串添加到常量池中,并且返回此String對象的引用。由于常量池分配在方法區內,我們可以通過-XX:PermSize和-XX:MaxPermSize
限制方法區的大小,從而間接限制其中常量池的容量。
4, 方法區溢出
方法區用于存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。
異常信息:java.lang.OutOfMemoryError:PermGen space
方法區溢出也是一種常見的內存溢出異常,一個類如果要被垃圾收集器回收,判定條件是很苛刻的。在經常動態生成大量Class
的應用中,要特別注意這點。 - Java面向對象的三個特征與含義。
封裝、繼承、多態 - Override和Overload的含義去區別。
- Interface與abstract類的區別。
- 接口中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。
- 類可以實現很多個接口,但是只能繼承一個抽象類
- 類如果要實現一個接口,它必須要實現接口聲明的所有方法。但是,類可以不實現抽象類聲明的所有方法,當然,在這種情況下,類也必須得聲明成是抽象的。
- 抽象類可以在不提供接口方法實現的情況下實現接口。
- Java接口中聲明的變量默認都是final的。抽象類可以包含非final的變量。
- Java接口中的成員函數默認是public的。抽象類的成員函數可以是private,protected或者是public。
- Static class 與non static class的區別。
內部靜態類不需要有指向外部類的引用。但非靜態內部類需要持有對外部類的引用 - java多態的實現原理。
- 實現多線程的兩種方法:Thread與Runable。
見上面
- 線程同步的方法:sychronized、lock、reentrantLock等。
見上面
- 鎖的等級:方法鎖、對象鎖、類鎖。
- 寫出生產者消費者模式。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ProducerConsumerPattern {
public static void main(String args[]){
BlockingQueue sharedQueue = new LinkedBlockingQueue();
Thread prodThread = new Thread(new Producer(sharedQueue));
Thread consThread = new Thread(new Consumer(sharedQueue));
prodThread.start();
consThread.start();
}
}
class Producer implements Runnable {
private final BlockingQueue sharedQueue;
public Producer(BlockingQueue sharedQueue) {
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
for(int i=0; i<10; i++){
try {
System.out.println("Produced: " + i);
sharedQueue.put(i);
} catch (InterruptedException ex) {
Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
class Consumer implements Runnable{
private final BlockingQueue sharedQueue;
public Consumer (BlockingQueue sharedQueue) {
this.sharedQueue = sharedQueue;
}
@Override
public void run() {
while(true){
try {
System.out.println("Consumed: "+ sharedQueue.take());
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
- ThreadLocal的設計理念與作用。
- ThreadPool用法與優勢。
- Concurrent包里的其他東西:ArrayBlockingQueue、CountDownLatch等等。
- wait()和sleep()的區別。
- foreach與正常for循環效率對比。
for循環的效率最高 - Java IO與NIO。
- 反射的作用于原理。
- 泛型常用特點,List<String>能否轉為List<Object>。
- 解析XML的幾種方式的原理與特點:DOM、SAX、PULL。
- Java與C++對比。
- Java1.7與1.8新特性。
- 設計模式:單例、工廠、適配器、責任鏈、觀察者等等。
- JNI的使用。
//