java

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系列

  1. ArrayList
    ArrayList以數組實現,允許重復。超出限制時會增加50%的容量(grow()方法中實現,如下所示),每次擴容都底層采用System.arrayCopy()復制到新的數組,因此最好能給出數組大小的預估值。默認第一次插入元素時創建數組的大小為10.
  2. LinkedList
    LinkedList以雙向鏈表實現,允許重復。(如下Node的實現)并保留頭指針和尾指針。鏈表無容量限制,但雙向鏈表本身使用了更多空間,也需要額外的鏈表指針操作。
    按下標訪問元素—get(i)/set(i,e) 要悲劇的遍歷鏈表將指針移動到位(如果i>數組大小的一半,會從末尾移起)。
  3. Vector
    VectorArrayList幾乎是完全相同的,唯一的區別在于Vector是同步類(synchronized),屬于強同步類。Vector每次請求其大小的雙倍空間,而ArrayList每次對size增長50%.
  4. Stack
    Stack繼承自Vector,實現了一個后進先出的堆棧。

ArrayList和LinkedList的區別

  • ArrayList是實現了基于動態數組的數據結構,LinkedList基于鏈表的數據結構。
  • 對于隨機訪問getsetArrayList覺得優于LinkedList,因為LinkedList要移動指針。
  • 對于新增和刪除操作addremoveLinkedList比較占優勢,因為ArrayList要移動數據。

ArrayList和Vector的區別

  • VectorArrayList幾乎是完全相同的,唯一的區別在于Vector是同步類(synchronized),屬于強同步類。因此開銷就比ArrayList要大,訪問要慢。正常情況下,大多數的Java程序員使用ArrayList而不是Vector,因為同步完全可以由程序員自己來控制。
  • Vector每次擴容請求其大小的2倍空間,而ArrayList是1.5倍。
  • Vector還有一個子類Stack.

Map

  1. HashMap
    通過hash的方法,通過putget存儲和獲取對象。存儲對象時,我們將K/V傳給put方法時,它調用hashCode計算hash從而得到bucket位置,進一步存儲,HashMap會根據當前bucket的占用情況自動調整容量(超過Load Factorresize為原來的2倍)。獲取對象時,我們將K傳給get,它調用hashCode計算hash從而得到bucket位置,并進一步調用equals()方法確定鍵值對。如果發生碰撞的時候,Hashmap通過鏈表將產生碰撞沖突的元素組織起來,在Java 8中,如果一個bucket中碰撞沖突的元素超過某個限制(默認是8),則使用紅黑樹來替換鏈表,從而提高速度。
    HashMap的容量(Capacity)是 16,負載因子(load factor0.75
  2. LinkedhashMap
    LinkedHashMapHash表和鏈表的實現,并且依靠著雙向鏈表保證了迭代順序是插入的順序。非線程安全,LinkedHashMap會記錄插入的順序,允許null的鍵值,當key值重復時,后面的會替換前面的。
  3. TreeHash
    紅黑樹實現
  4. HashTable
    HashMap幾乎可以等價于Hashtable,除了HashMap是非synchronized的,并可以接受null
  5. WeakHashMap
    WeakHashMap實現了Map接口,是HashMap的一種實現,它比HashMap多了一個引用隊列.
    博主認真比對過WeakHashMapHashMap的源碼,發現WeakHashMap中方法的實現方式基本和HashMap的一樣,注意“基本”兩個字,除了沒有實現Cloneable和Serializable這兩個標記接口,最大的區別在于在于expungeStaleEntries()這個方法,這個是整個WeakHashMap的精髓:每調用一次expungeStaleEntries()方法,就會在引用隊列中尋找是否有被清楚的key對象,如果有則在table中找到其值,并將value設置為nullnext指針也設置為null,讓GC去回收這些資源。
  6. EnumMap
    EnumMap是專門為枚舉類型量身定做的Map實現。雖然使用其它的Map實現(如HashMap)也能完成枚舉類型實例到值得映射,但是使用EnumMap會更加高效:它只能接收同一枚舉類型的實例作為鍵值,并且由于枚舉類型實例的數量相對固定并且有限,所以EnumMap使用數組來存放與枚舉類型對應的值。這使得EnumMap的效率非常高。EnumMap在內部使用枚舉類型的ordinal()得到當前實例的聲明次序,并使用這個次序維護枚舉類型實例對應值在數組的位置。

HashMapHashTable的區別

  • HashTable 是線程安全的,多個線程可以共享一個Hashtable;而如果沒有正確的同步的話,多個線程是不能共享HashMap的。
  • 另一個區別是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtableenumerator迭代器不是fail-fast的。
  • HashtableHashMap它們兩個內部實現方式的數組的初始大小和擴容的方式。HashTablehash數組默認大小是11,增加的方式是 old*2+1。HashMaphash數組的默認大小是16,而且一定是2的指數。

Set:
Set幾乎都是內部用一個Map來實現, 因為Map里的KeySet就是一個Set,而value是假值,全部使用同一個ObjectSet的特征也繼承了那些內部Map實現的特征。
HashSet
HashSet是基于HashMap來實現的,操作很簡單,更像是對HashMap做了一次“封裝”,而且只使用了HashMap的key來實現各種特性,而HashMapvalue始終都是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先找元素,再執行一個普通的鏈表節點刪除操作。
Segmentrehash 是不加鎖的,它先創建一個新的空數組,接著將元素 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的countmodcount兩次,如果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 數據結構。它提供了可阻塞的puttake方法。如果Queue已經滿了,put方法會被阻塞直到有空間可用;如果Queue是空的,那么take方法會被阻塞,直到有元素可用。Queue的長度可用有限,也可以無限;無限的Queue永遠不會充滿,所以它的put方法永遠不會被阻塞。阻塞隊列支持生產者-消費者設計模式。

BlockingQueue接口的幾個主要的實現類:
  • ArrayBlockingQueue :一個由數組支持的有界隊列。
  • LinkedBlockingQueue:一個由鏈接節點支持的可選有界隊列。
  • PriorityBlockingQueue :一個由優先級堆支持的無界優先級隊列。
  • DelayQueue :一個由優先級堆支持的、基于時間的調度隊列。
  • SynchronousQueue :一個利用 BlockingQueue 接口的簡單聚集(rendezvous)機制。

3. 部分常用集合類的內部實現方式

java線程

1. 線程sleep和wait的區別

Java程序中waitsleep都會造成某種形式的暫停,它們可以滿足不同的需要。wait()方法用于線程間通信,如果等待條件為真且其它線程被喚醒時它會釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當前線程停止執行一段時間,但不會釋放鎖。需要注意的是,sleep()并不會讓線程終止,一旦從休眠中喚醒線程,線程的狀態將會被改變為Runnable,并且根據線程調度,它將得到執行。

3. Thread、Runnable、Callable、Futrue類關系與區別

Thread:
java中可有兩種方式實現多線程,一種是繼承Thread類,一種是實現Runnable接口。但是最終被線程執行的是Runnable,而非ThreadThread僅僅是對于Runnable的包裝。

public class Thread extends Object implements Runnable```
`Runnable`:
它只有一個`run()`函數,用于將耗時操作寫在其中,**該函數沒有返回值**。然后使用某個線程去執行該`runnable`即可實現多線程,`Thread`類在調用`start()`函數后就是執行的是`Runnable`的`run()`函數

public interface Runnable {
public abstract void run();
}```
Callable:
CallableRunnable的功能大致相似,Callable中有一個call()函數,但是call()函數有返回值,而Runnablerun()函數不能將結果返回給客戶程序

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;
      }
      }
      } ```

  1. 九種基本數據類型的大小,以及他們的封裝類。
    byte 8 Byte short 16 Short int 32 Integer long 64 Long float 32 Float double 64 Double char 16 Char boolean Boolean
  2. Switch能否用string做參數?
    可以自動轉換為整型的(byte,short,int),String類型,枚舉類型。
    Java中不能做為Switch參數的有boolean,float,double,long(不能直接轉換為int啊)。
  3. equals與==的區別。
    1.==是判斷兩個變量或實例是不是指向同一個內存空間
    equals是判斷兩個變量或實例所指向的內存空間的值是不是相同
    2.==是指對內存地址進行比較
    equals()是對字符串的內容進行比較
    3.==指引用是否相同
    equals()指的是值是否相同
  4. Object有哪些公用方法?
    clone getClass toString finalize equals hashCode
    wait notify notifyAll
  5. Java的四種引用,強弱軟虛,用到的場景。
    見上面
  6. Hashcode的作用。
    set和map中的元素無序不重復
    哈希算法也稱為散列算法,是將數據依特定算法直接指定到一個地址上。這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以 直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了;不相同,也就是發生了Hash key相同導致沖突的情況,那么就在這個Hash key的地方產生一個鏈表,將所有產生相同hashcode的對象放到這個單鏈表上去,串在一起。
  7. ArrayList、LinkedList、Vector的區別。
    見上面
  8. String、StringBuffer與StringBuilder的區別。
    String 類型和 StringBuffer 類型的主要性能區別其實在于 String 是不可變的對象, 因此在每次對 String類型進行改變的時候其實都等同于生成了一個新的 String對象,然后將指針指向新的 String 對象
    StringBuild(線程不安全) > StringBuffer(線程安全) > String
  9. Map、Set、List、Queue、Stack的特點與用法。
  10. HashMap和HashTable的區別。
  11. HashMap和ConcurrentHashMap的區別,HashMap的底層源碼。
  12. TreeMap、HashMap、LindedHashMap的區別。
    見上面
  13. Collection包結構,與Collections的區別。
  • Collection 是一個集合接口(集合類的一個頂級接口)。它提供了對集合對象進行基本操作的通用接口方法
    ├List
    │├LinkedList
    │├ArrayList
    │└Vector
    │ └Stack
    └Set
  • java.util.Collections 是一個包裝類(工具類/幫助類)。它包含有各種有關集合操作的靜態多態方法。此類不能實例化
  1. try catch finally,try里有return,finally還執行么?
  • try語句沒有被執行到,如在try語句之前就返回了,這樣finally語句就不會執行,這也說明了finally語句被執行的必要而非充分條件是:相應的try語句一定被執行到。
  • 在try塊中有System.exit(0);這樣的語句,System.exit(0);是終止Java虛擬機JVM的,連JVM都停止了,所有都結束了,當然finally語句也不會被執行到。
  1. 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的應用中,要特別注意這點。
  2. Java面向對象的三個特征與含義。
    封裝、繼承、多態
  3. Override和Overload的含義去區別。
  4. Interface與abstract類的區別。
  • 接口中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。
  • 類可以實現很多個接口,但是只能繼承一個抽象類
  • 類如果要實現一個接口,它必須要實現接口聲明的所有方法。但是,類可以不實現抽象類聲明的所有方法,當然,在這種情況下,類也必須得聲明成是抽象的。
  • 抽象類可以在不提供接口方法實現的情況下實現接口。
  • Java接口中聲明的變量默認都是final的。抽象類可以包含非final的變量。
  • Java接口中的成員函數默認是public的。抽象類的成員函數可以是private,protected或者是public。
  1. Static class 與non static class的區別。
    內部靜態類不需要有指向外部類的引用。但非靜態內部類需要持有對外部類的引用
  2. java多態的實現原理。
  3. 實現多線程的兩種方法:Thread與Runable。
    見上面
  4. 線程同步的方法:sychronized、lock、reentrantLock等。
    見上面
  5. 鎖的等級:方法鎖、對象鎖、類鎖。
  6. 寫出生產者消費者模式。
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);
            }
        }
    }
}
  1. ThreadLocal的設計理念與作用。
  2. ThreadPool用法與優勢。
  3. Concurrent包里的其他東西:ArrayBlockingQueue、CountDownLatch等等。
  4. wait()和sleep()的區別。
  5. foreach與正常for循環效率對比。
    for循環的效率最高
  6. Java IO與NIO。
  7. 反射的作用于原理。
  8. 泛型常用特點,List<String>能否轉為List<Object>。
  9. 解析XML的幾種方式的原理與特點:DOM、SAX、PULL。
  10. Java與C++對比。
  11. Java1.7與1.8新特性。
  12. 設計模式:單例、工廠、適配器、責任鏈、觀察者等等。
  13. JNI的使用。

//

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

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,779評論 18 399
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,376評論 11 349
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,144評論 0 62
  • Java SE 基礎: 封裝、繼承、多態 封裝: 概念:就是把對象的屬性和操作(或服務)結合為一個獨立的整體,并盡...
    Jayden_Cao閱讀 2,150評論 0 8
  • 有了晨間日記,你也可以建立自己的大數據庫 提到日記,大家不陌生,小時候都我們都被要求記過。 記得我的第一篇日記是在...
    天行踐閱讀 307評論 0 0