Java篇

1.為什么要使用線程池

避免頻繁地創(chuàng)建和銷毀線程,達到線程對象的重用。另外,使用線程池還可以根據(jù)項目靈活地控制并發(fā)的數(shù)目。然后新建線程會浪費性能。

2.java中用到的線程調(diào)度算法是什么

搶占式。一個線程用完CPU之后,操作系統(tǒng)會根據(jù)線程優(yōu)先級、線程饑餓情況等數(shù)據(jù)算出一個總的優(yōu)先級并分配下一個時間片給某個線程執(zhí)行。

3.Thread.sleep(0)的作用是什么

由于Java采用搶占式的線程調(diào)度算法,因此可能會出現(xiàn)某條線程常常獲取到CPU控制權(quán)的情況,為了讓某些優(yōu)先級比較低的線程也能獲取到CPU控制權(quán),可以使用Thread.sleep(0)手動觸發(fā)一次操作系統(tǒng)分配時間片的操作,這也是平衡CPU控制權(quán)的一種操作。

4.什么是CAS [http://www.itdecent.cn/p/bab16d7c83a2]

CAS,全稱為Compare and Swap,即比較-替換。假設(shè)有三個操作數(shù):內(nèi)存值V、舊的預(yù)期值A(chǔ)、要修改的值B,當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時,才會將內(nèi)存值修改為B并返回true,否則什么都不做并返回false。當(dāng)然CAS一定要volatile變量配合,這樣才能保證每次拿到的變量是主內(nèi)存中最新的那個值,否則舊的預(yù)期值A(chǔ)對某條線程來說,永遠是一個不會變的值A(chǔ),只要某次CAS操作失敗,永遠都不可能成功

5.什么是樂觀鎖和悲觀鎖

樂觀鎖:樂觀鎖認為競爭不總是會發(fā)生,因此它不需要持有鎖,將比較-替換這兩個動作作為一個原子操作嘗試去修改內(nèi)存中的變量,如果失敗則表示發(fā)生沖突,那么就應(yīng)該有相應(yīng)的重試邏輯。

悲觀鎖:悲觀鎖認為競爭總是會發(fā)生,因此每次對某資源進行操作時,都會持有一個獨占的鎖,就像synchronized,不管三七二十一,直接上了鎖就操作資源了。

  • synchronized是悲觀鎖,這種線程一旦得到鎖,其他需要鎖的線程就掛起的情況就是悲觀鎖。
  • CAS操作的就是樂觀鎖,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。
5.1 Java當(dāng)中有哪幾種鎖

1.自旋鎖: 自旋鎖在JDK1.6之后就默認開啟了?;谥暗挠^察,共享數(shù)據(jù)的鎖定狀態(tài)只會持續(xù)很短的時間,為了這一小段時間而去掛起和恢復(fù)線程有點浪費,所以這里就做了一個處理,讓后面請求鎖的那個線程在稍等一會,但是不放棄處理器的執(zhí)行時間,看看持有鎖的線程能否快速釋放。為了讓線程等待,所以需要讓線程執(zhí)行一個忙循環(huán)也就是自旋操作。在jdk6之后,引入了自適應(yīng)的自旋鎖,也就是等待的時間不再固定了,而是由上一次在同一個鎖上的自旋時間及鎖的擁有者狀態(tài)來決定

2.偏向鎖: 在JDK1.之后引入的一項鎖優(yōu)化,目的是消除數(shù)據(jù)在無競爭情況下的同步原語。進一步提升程序的運行性能。 偏向鎖就是偏心的偏,意思是這個鎖會偏向第一個獲得他的線程,如果接下來的執(zhí)行過程中,該鎖沒有被其他線程獲取,則持有偏向鎖的線程將永遠不需要再進行同步。偏向鎖可以提高帶有同步但無競爭的程序性能,也就是說他并不一定總是對程序運行有利,如果程序中大多數(shù)的鎖都是被多個不同的線程訪問,那偏向模式就是多余的,在具體問題具體分析的前提下,可以考慮是否使用偏向鎖。

3.輕量級鎖: 為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了“偏向鎖”和“輕量級鎖”,所以在Java SE1.6里鎖一共有四種狀態(tài),無鎖狀態(tài),偏向鎖狀態(tài),輕量級鎖狀態(tài)和重量級鎖狀態(tài),它會隨著競爭情況逐漸升級。鎖可以升級但不能降級,意味著偏向鎖升級成輕量級鎖后不能降級成偏向鎖

5.2 synchronized和ReentrantLock的區(qū)別

synchronized是和if、else、for、while一樣的關(guān)鍵字,ReentrantLock是類,這是二者的本質(zhì)區(qū)別。既然ReentrantLock是類,那么它就提供了比synchronized更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock比synchronized的擴展性體現(xiàn)在幾點上: (1)ReentrantLock可以對獲取鎖的等待時間進行設(shè)置,這樣就避免了死鎖 (2)ReentrantLock可以獲取各種鎖的信息 (3)ReentrantLock可以靈活地實現(xiàn)多路通知 另外,二者的鎖機制其實也是不一樣的:ReentrantLock底層調(diào)用的是Unsafe的park方法加鎖,synchronized操作的應(yīng)該是對象頭中mark word.

功能 synchronized ReentrantLock
鎖獲取超時 不支持 支持
獲取鎖響應(yīng)中斷 不支持 支持
是否手動釋放
5.3 為什么wait,nofity和nofityAll這些方法不放在Thread類當(dāng)中

一個很明顯的原因是JAVA提供的鎖是對象級的而不是線程級的,每個對象都有鎖,通過線程獲得。如果線程需要等待某些鎖那么調(diào)用對象中的wait()方法就有意義了。如果wait()方法定義在Thread類中,線程正在等待的是哪個鎖就不明顯了。簡單的說,由于wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類中因為鎖屬于對象。

5.4怎么喚醒一個阻塞的線程

如果線程是因為調(diào)用了wait()、sleep()或者join()方法而導(dǎo)致的阻塞,可以中斷線程,并且通過拋出InterruptedException來喚醒它;如果線程遇到了IO阻塞,無能為力,因為IO是操作系統(tǒng)實現(xiàn)的,Java代碼并沒有辦法直接接觸到操作系統(tǒng)。

5.5 什么是多線程的上下文切換

多線程的上下文切換是指CPU控制權(quán)由一個已經(jīng)正在運行的線程切換到另外一個就緒并等待獲取CPU執(zhí)行權(quán)的線程的過程。

6.可以創(chuàng)建Volatile數(shù)組嗎?

Java 中可以創(chuàng)建 volatile類型數(shù)組,不過只是一個指向數(shù)組的引用,而不是整個數(shù)組。如果改變引用指向的數(shù)組,將會受到volatile 的保護,但是如果多個線程同時改變數(shù)組的元素,volatile標示符就不能起到之前的保護作用了

7.poll()方法和remove()方法區(qū)別?

poll() 和 remove() 都是從隊列中取出一個元素,但是 poll() 在獲取元素失敗的時候會返回空,但是 remove() 失敗的時候會拋出異常。

7.1 volatile類型變量提供什么保證?

volatile 主要有兩方面的作用:1.避免指令重排2.可見性保證.例如,JVM 或者 JIT為了獲得更好的性能會對語句重排序,但是 volatile 類型變量即使在沒有同步塊的情況下賦值也不會與其他語句重排序。 volatile 提供 happens-before 的保證,確保一個線程的修改能對其他線程是可見的。某些情況下,volatile 還能提供原子性,如讀 64 位數(shù)據(jù)類型,像 long 和 double 都不是原子的(低32位和高32位),但 volatile 類型的 double 和 long 就是原子的.

7.2 volatile能使得一個非原子操作變成原子操作嗎?

一個典型的例子是在類中有一個 long 類型的成員變量。如果你知道該成員變量會被多個線程訪問,如計數(shù)器、價格等,你最好是將其設(shè)置為 volatile。為什么?因為 Java 中讀取 long 類型變量不是原子的,需要分成兩步,如果一個線程正在修改該 long 變量的值,另一個線程可能只能看到該值的一半(前 32 位)。但是對一個 volatile 型的 long 或 double 變量的讀寫是原子。
一種實踐是用 volatile 修飾 long 和 double 變量,使其能按原子類型來讀寫。double 和 long 都是64位寬,因此對這兩種類型的讀是分為兩部分的,第一次讀取第一個 32 位,然后再讀剩下的 32 位,這個過程不是原子的,但 Java 中 volatile 型的 long 或 double 變量的讀寫是原子的。volatile 修復(fù)符的另一個作用是提供內(nèi)存屏障(memory barrier),例如在分布式框架中的應(yīng)用。簡單的說,就是當(dāng)你寫一個 volatile 變量之前,Java 內(nèi)存模型會插入一個寫屏障(write barrier),讀一個 volatile 變量之前,會插入一個讀屏障(read barrier)。意思就是說,在你寫一個 volatile 域時,能保證任何線程都能看到你寫的值,同時,在寫之前,也能保證任何數(shù)值的更新對所有線程是可見的,因為內(nèi)存屏障會將其他所有寫的值更新到緩存。
[

](https://github.com/closedevice/interview-about/blob/master/java/java-questions.md#volatile類型變量提供什么保證)

8.LinkedHashMap和PriorityQueue的區(qū)別

PriorityQueue 是一個優(yōu)先級隊列,保證最高或者最低優(yōu)先級的的元素總是在隊列頭部,但是 LinkedHashMap 維持的順序是元素插入的順序。當(dāng)遍歷一個 PriorityQueue 時,沒有任何順序保證,但是 LinkedHashMap 課保證遍歷順序是元素插入的順序。

9.WeakHashMap與HashMap的區(qū)別是什么?

WeakHashMap 的工作與正常的 HashMap 類似,但是使用弱引用作為 key,意思就是當(dāng) key 對象沒有任何引用時,key/value 將會被回收。

10.ArrayList和LinkedList的區(qū)別?

最明顯的區(qū)別是 ArrrayList底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,支持隨機訪問,而 LinkedList 的底層數(shù)據(jù)結(jié)構(gòu)是雙向循環(huán)鏈表,不支持隨機訪問。使用下標訪問一個元素,ArrayList 的時間復(fù)雜度是 O(1),而 LinkedList 是 O(n)。

11.ArrayList和Array有什么區(qū)別?

Array可以容納基本類型和對象,而ArrayList只能容納對象。
Array是指定大小的,而ArrayList大小是固定的

12.ArrayList和HashMap默認大小?

在 Java 7 中,ArrayList 的默認大小是 10 個元素,HashMap 的默認大小是16個元素(必須是2的冪)。這就是 Java 7 中 ArrayList 和 HashMap 類的代碼片段

private static final int DEFAULT_CAPACITY = 10;
//擴容是百分之50吧
 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
 
 //from HashMap.java JDK 7
 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
13.如何打印數(shù)組內(nèi)容

你可以使用 Arrays.toString() 和 Arrays.deepToString() 方法來打印數(shù)組。由于數(shù)組沒有實現(xiàn) toString() 方法,所以如果將數(shù)組傳遞給 System.out.println() 方法,將無法打印出數(shù)組的內(nèi)容,但是 Arrays.toString() 可以打印每個元素。

14.LinkedList的是單向鏈表還是雙向?

雙向循環(huán)列表,具體實現(xiàn)自行查閱源碼.

15.TreeMap是實現(xiàn)原理

采用紅黑樹實現(xiàn),具體實現(xiàn)自行查閱源碼.

16.遍歷ArrayList時如何正確移除一個元素

該問題的關(guān)鍵在于面試者使用的是 ArrayList 的 remove() 還是 Iterator 的 remove()方法。這有一段示例代碼,是使用正確的方式來實現(xiàn)在遍歷的過程中移除元素,而不會出現(xiàn) ConcurrentModificationException 異常的示例代碼。

/**  
 * 使用增強的for循環(huán)  
 * 在循環(huán)過程中從List中刪除非基本數(shù)據(jù)類型以后,繼續(xù)循環(huán)List時會報ConcurrentModificationException  
 */    
public void listRemove() {    
    List<Student> students = this.getStudents();    
    for (Student stu : students) {    
        if (stu.getId() == 2)     
            students.remove(stu);    
    }    
}    


 * 像這種使用增強的for循環(huán)對List進行遍歷刪除,但刪除之后馬上就跳出的也不會出現(xiàn)異常  
 */    
public void listRemoveBreak() {    
    List<Student> students = this.getStudents();    
    for (Student stu : students) {    
        if (stu.getId() == 2) {    
            students.remove(stu);    
            break;    
        }    
    }    
}
/**  
 * 這種不使用增強的for循環(huán)的也可以正常刪除和遍歷,  
 * 這里所謂的正常是指它不會報異常,但是刪除后得到的  
 * 數(shù)據(jù)不一定是正確的,這主要是因為刪除元素后,被刪除元素后  
 * 的元素索引發(fā)生了變化。假設(shè)被遍歷list中共有10個元素,當(dāng)  
 * 刪除了第3個元素后,第4個元素就變成了第3個元素了,第5個就變成  
 * 了第4個了,但是程序下一步循環(huán)到的索引是第4個,  
 * 這時候取到的就是原本的第5個元素了。  
 */    
public void listRemove2() {    
    List<Student> students = this.getStudents();    
    for (int i=0; i<students.size(); i++) {    
        if (students.get(i).getId()%3 == 0) {    
            Student student = students.get(i);    
            students.remove(student);    
        }    
    }    
}    
/**  
 * 使用Iterator的方式可以順利刪除和遍歷  
 */    
public void iteratorRemove() {    
    List<Student> students = this.getStudents();    
    System.out.println(students);    
    Iterator<Student> stuIter = students.iterator();    
    while (stuIter.hasNext()) {    
        Student student = stuIter.next();    
        if (student.getId() % 2 == 0)    
            stuIter.remove();//這里要使用Iterator的remove方法移除當(dāng)前對象,如果使用List的remove方法,則同樣會出現(xiàn)ConcurrentModificationException    
    }    
    System.out.println(students);    
} 
17.什么是ArrayMap?它和HashMap有什么區(qū)別?

ArrayMap是Android SDK中提供的,非Android開發(fā)者可以略過. ArrayMap是用兩個數(shù)組來模擬map,更少的內(nèi)存占用空間,更高的效率. 具體參考這篇文章:ArrayMap VS HashMap

HashMap

Java庫里的HashMap其實是一個連續(xù)的鏈表數(shù)組,通過讓key計算hash值后插入對應(yīng)的index里。當(dāng)hash值發(fā)生碰撞時,可以采用線性探測,二次hash,或者后面直接變成鏈表的結(jié)構(gòu)來避免碰撞。因為hash的值不是連續(xù)的,所以hashmap實際需要占用的大小會比它實際能裝的item的容量要大。

Paste_Image.png

他用兩個數(shù)組來模擬Map,第一個數(shù)組存放存放item的hash值,第二數(shù)組是把key,value連續(xù)的存放在數(shù)組里,通過先算hash在第一個數(shù)組里找到它的hash index,根據(jù)這個index在去第二個數(shù)組里找到這個key-value。

在這里,在第一個數(shù)組里查找hash index的方法當(dāng)然是用二分查找啦(binary search)。

Paste_Image.png

這個數(shù)據(jù)結(jié)構(gòu)的設(shè)計就做到了,有多個item我就分配多少內(nèi)存,做到了memory的節(jié)約。并且因為數(shù)據(jù)結(jié)構(gòu)是通過數(shù)組組織的,所以遍歷的時候可以用index直接遍歷也是很方便的有沒有!但是缺點也很明顯,查找達不到HashMap O(1)的查找時間。

當(dāng)要存儲的對象較少的時候(1000以下的時候)可以考慮用ArrayMap來減少內(nèi)存的占用。

18.HashMap的實現(xiàn)原理

1 HashMap概述: HashMap是基于哈希表的Map接口的非同步實現(xiàn)。此實現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恒久不變。
2 HashMap的數(shù)據(jù)結(jié)構(gòu): 在java編程語言中,最基本的結(jié)構(gòu)就是兩種,一個是數(shù)組,另外一個是模擬指針(引用),所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個基本結(jié)構(gòu)來構(gòu)造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。

當(dāng)我們往Hashmap中put元素時,首先根據(jù)key的hashcode重新計算hash值,根絕hash值得到這個元素在數(shù)組中的位置(下標),如果該數(shù)組在該位置上已經(jīng)存放了其他元素,那么在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放入鏈尾.如果數(shù)組中該位置沒有元素,就直接將該元素放到數(shù)組的該位置上.

需要注意Jdk 1.8中對HashMap的實現(xiàn)做了優(yōu)化,當(dāng)鏈表中的節(jié)點數(shù)據(jù)超過八個之后,該鏈表會轉(zhuǎn)為紅黑樹來提高查詢效率,從原來的O(n)到O(logn)

19 如何處理線程并發(fā)?

1.synchronized關(guān)鍵字和Lock并發(fā)鎖:主要解決多線程共享數(shù)據(jù)同步問題。
2.ThreadLocal主要解決多線程中數(shù)據(jù)因并發(fā)產(chǎn)生不一致
ps:也可以使用信號量的方式Semaphore

ThreadLocal與synchronized有本質(zhì)的區(qū)別:
synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal為每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的并不是同一個對象,這樣就隔離了多個線程對數(shù)據(jù)的數(shù)據(jù)共享。而Synchronized卻正好相反,它用于在多個線程間通信時能夠獲得數(shù)據(jù)共享。

20.SimpleDateFormat是線程安全的嗎?

非常不幸,DateFormat 的所有實現(xiàn),包括 SimpleDateFormat 都不是線程安全的,因此你不應(yīng)該在多線程序中使用,除非是在對外線程安全的環(huán)境中使用,如 將 SimpleDateFormat 限制在 ThreadLocal 中。如果你不這么做,在解析或者格式化日期的時候,可能會獲取到一個不正確的結(jié)果。

22.簡述JVM內(nèi)存分配

1.基本數(shù)據(jù)類型比如變量和對象的引用都是在棧分配的
2.堆內(nèi)存用來存放由new創(chuàng)建的對象和數(shù)組
3.類變量(static修飾的變量),程序在一加載的時候就在堆中為類變量分配內(nèi)存,堆中的內(nèi)存地址存放在棧中
4.實例變量:當(dāng)你使用java關(guān)鍵字new的時候,系統(tǒng)在堆中開辟并不一定是連續(xù)的空間分配給變量,是根據(jù)零散的堆內(nèi)存地址,通過哈希算法換算為一長串?dāng)?shù)字以表征這個變量在堆中的"物理位置”,實例變量的生命周期--當(dāng)實例變量的引用丟失后,將被GC(垃圾回收器)列入可回收“名單”中,但并不是馬上就釋放堆中內(nèi)存
5.局部變量: 由聲明在某方法,或某代碼段里(比如for循環(huán)),執(zhí)行到它的時候在棧中開辟內(nèi)存,當(dāng)局部變量一但脫離作用域,內(nèi)存立即釋放

25.集合類總結(jié)
Paste_Image.png
26.雙親委托模型

Java中ClassLoader的加載采用了雙親委托機制,采用雙親委托機制加載類的時候采用如下的幾個步驟:

1.當(dāng)前ClassLoader首先從自己已經(jīng)加載的類中查詢是否此類已經(jīng)加載,如果已經(jīng)加載則直接返回原來已經(jīng)加載的類。

2.每個類加載器都有自己的加載緩存,當(dāng)一個類被加載了以后就會放入緩存,等下次加載的時候就可以直接返回了。

3.當(dāng)前classLoader的緩存中沒有找到被加載的類的時候,委托父類加載器去加載,父類加載器采用同樣的策略,首先查看自己的緩存,然后委托父類的父類去加載,一直到bootstrp ClassLoader.

當(dāng)所有的父類加載器都沒有加載的時候,再由當(dāng)前的類加載器加載,并將其放入它自己的緩存中,以便下次有加載請求的時候直接返回

27.HTTP的特點?

1.支持客戶/服務(wù)器模式。
2.簡單快速:客戶向服務(wù)器請求服務(wù)時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST。每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同。由于HTTP協(xié)議簡單,使得HTTP服務(wù)器的程序規(guī)模小,因而通信速度很快。
3.靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對象。正在傳輸?shù)念愋陀蒀ontent-Type加以標記。
4.無連接:無連接的含義是限制每次連接只處理一個請求。服務(wù)器處理完客戶的請求,并收到客戶的應(yīng)答后,即斷開連接。采用這種方式可以節(jié)省傳輸時間。
5.無狀態(tài):HTTP協(xié)議是無狀態(tài)協(xié)議。無狀態(tài)是指協(xié)議對于事務(wù)處理沒有記憶能力。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大。另一方面,在服務(wù)器不需要先前信息時它的應(yīng)答就較快。

區(qū)別:

  1. http和https用的端口也不一樣,前者是80,后者是443。
    2.在網(wǎng)絡(luò)模型中,HTTP 工作于應(yīng)用層,而 HTTPS 工作在傳輸層
    3.HTTP 無需加密,而 HTTPS 對傳輸?shù)臄?shù)據(jù)進行加密
    4.HTTP 無需證書,而 HTTPS 需要認證證書
    5.HTTP 的 URL 以 http:// 開頭,而 HTTPS 的 URL 以 https:// 開頭
    6.Http的速度要比Https快
28.String、StringBuilder、StringBuffer 的區(qū)別,StringBuffer 是如何實現(xiàn)線程安全的?

1.三者在執(zhí)行速度方面的比較:StringBuilder > StringBuffer > String
2.String <(StringBuffer,StringBuilder)的原因
String:字符串常量
StringBuffer:字符串變量
StringBuilder:字符串變量

每當(dāng)用String操作字符串時,實際上是在不斷的創(chuàng)建新的對象,而原來的對象就會變?yōu)槔唬牵没厥盏?br> 而StringBuffer與StringBuilder就不一樣了,他們是字符串變量,是可改變的對象,每當(dāng)我們用它們對字符串做操作時,實際上是在一個對象上操作的,這樣就不會像String一樣創(chuàng)建一些而外的對象進行操作了,當(dāng)然速度就快了。

當(dāng)我們在字符串緩沖去被多個線程使用是,JVM不能保證StringBuilder的操作是安全的,雖然他的速度最快,但是可以保證StringBuffer是可以正確操作的。當(dāng)然大多數(shù)情況下就是我們是在單線程下進行的操作,所以大多數(shù)情況下是建議用StringBuilder而不用StringBuffer的,就是速度的原因。

對于三者使用的總結(jié):
1.如果要操作少量的數(shù)據(jù)用 = String
2.單線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = StringBuilder
3.多線程操作字符串緩沖區(qū) 下操作大量數(shù)據(jù) = StringBuffer

29.你平常是怎么進行加密的?MD5 加密是可逆的嗎?
  1. Rsa 1024 公鑰加密私鑰簽名
  2. Md5加密
    MD5 加密是不可逆的。只有暴力破解,用彩虹表破解一些常用的原文。就可以2+5=7 但是7 可以是1+6;3+4,
    Md5是非對稱性加密,存在碰撞性,但是想找到兩個不同數(shù)據(jù),一樣MD5值得可能性非常小。
    對稱加密包括DES和AES
    非對稱加密用的最多的就是Rsa
30.接口與抽象類的區(qū)別?static 方法可以被覆蓋嗎?為什么?

1.接口能多實現(xiàn),抽象類不能多繼承
2.抽象類中可以有具體的實現(xiàn)方法和成員變量,接口中只有抽象方法和static的數(shù)據(jù)。
3.抽象類就想一個模板,用來捕捉子類的通用特性,接口是一個抽象方法的集合
4.抽象類是對一種事物的抽象,即對類抽象,而接口是對行為的抽象。
抽象類是對整個類整體進行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進行抽象。舉個簡單的例子,飛機和鳥是不同類的事物,但是它們都有一個共性,就是都會飛。那么在設(shè)計的時候,可以將飛機設(shè)計為一個類Airplane,將鳥設(shè)計為一個類Bird,但是不能將 飛行 這個特性也設(shè)計為類,因此它只是一個行為特性,并不是對一類事物的抽象描述。此時可以將 飛行 設(shè)計為一個接口Fly,包含方法fly( ),然后Airplane和Bird分別根據(jù)自己的需要實現(xiàn)Fly這個接口。然后至于有不同種類的飛機,比如戰(zhàn)斗機、民用飛機等直接繼承Airplane即可,對于鳥也是類似的,不同種類的鳥直接繼承Bird類即可。從這里可以看出,繼承是一個 "是不是"的關(guān)系,而 接口 實現(xiàn)則是 "有沒有"的關(guān)系。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而接口實現(xiàn)則是有沒有、具備不具備的關(guān)系,比如鳥是否能飛(或者是否具備飛行這個特點),能飛行則可以實現(xiàn)這個接口,不能飛行就不實現(xiàn)這個接口。

static方法不能被覆蓋。
重寫”只能適用于可觀察的實例方法.不能用于靜態(tài)方法和final、private.對于靜態(tài)方法,只能隱藏。一方面這是Java的規(guī)定
關(guān)于靜態(tài)方法為什么不能被重寫的一點思考以及overload的一些坑。

31.創(chuàng)建線程的方式,他們有什么區(qū)別?知道線程池嗎?說說對線程池的理解?
32.你了解過 Java 的四種引用嗎?分別代表什么含義,他們有什么區(qū)別?
33.Java 中關(guān)于 equals 和 hashcode 的理解?

equals()相等的兩個對象,hashcode()一定相等,equals()不相等的兩個對象,卻并不能證明他們的hashcode()不相等。換句話說,equals()方法不相等的兩個對象,hashCode()有可能相等。(我的理解是由于哈希碼在生成的時候產(chǎn)生沖突造成的).
舉個通俗的例子

在這里hashCode就好比字典里每個字的索引,equals()好比比較的是字典里同一個字下的不同詞語。就好像在字典里查“自”這個字下的兩個詞語“自己”、“自發(fā)”,如果用equals()判斷查詢的詞語相等那么就是同一個詞語,比如equals()比較的兩個詞語都是“自己”,那么此時hashCode()方法得到的值也肯定相等;如果用equals()方法比較的是“自己”和“自發(fā)”這兩個詞語,那么得到結(jié)果是不想等,但是這兩個詞都屬于“自”這個字下的詞語所以在查索引時相同,即:hashCode()相同。如果用equals()比較的是“自己”和“他們”這兩個詞語的話那么得到的結(jié)果也是不同的,此時hashCode() 得到也是不同的

34.關(guān)于 Java 中深拷貝和淺拷貝的區(qū)別?

淺拷貝是指拷貝對象時僅僅拷貝對象本身(包括對象中的基本變量),而不拷貝對象包含的引用指向的對象。深拷貝不僅拷貝對象本身,而且拷貝對象包含的引用指向的所有對象。舉例來說更加清楚:對象A1中包含對B1的引用,B1中包含對C1的引用。淺拷貝A1得到A2,A2 中依然包含對B1的引用,B1中依然包含對C1的引用。深拷貝則是對淺拷貝的遞歸,深拷貝A1得到A2,A2中包含對B2(B1的copy)的引用,B2 中包含對C2(C1的copy)的引用。

35.簡單的說下 Java 的垃圾回收?
36.了解過 Java 的集合嗎?說說 HashMap 的底層實現(xiàn)原理?ArrayList 和 LinkedList 的區(qū)別?Java 集合中哪些是線程安全的?

了解過。Hashmap底層是鏈表加數(shù)組的方式

37.如何實現(xiàn)對象的排序?

對象的排序 首先判斷這個對是否有可比較性,比如是不是實現(xiàn)了comparable ,如果沒有實現(xiàn) 可以用compartor 比較器去實現(xiàn)對象之間的比較,然后 實現(xiàn)內(nèi)部方法compareTo 進行排序。

總結(jié)一下,兩種比較器Comparable和Comparator,后者相比前者有如下優(yōu)點:

1、如果實現(xiàn)類沒有實現(xiàn)Comparable接口,又想對兩個類進行比較(或者實現(xiàn)類實現(xiàn)了Comparable接口,但是對compareTo方法內(nèi)的比較算法不滿意),那么可以實現(xiàn)Comparator接口,自定義一個比較器,寫比較算法

2、實現(xiàn)Comparable接口的方式比實現(xiàn)Comparator接口的耦合性 要強一些,如果要修改比較算法,要修改Comparable接口的實現(xiàn)類,而實現(xiàn)Comparator的類是在外部進行比較的,不需要對實現(xiàn)類有任何修 改。從這個角度說,其實有些不太好,尤其在我們將實現(xiàn)類的.class文件打成一個.jar文件提供給開發(fā)者使用的時候。實際上實現(xiàn)Comparator 接口的方式后面會寫到就是一種典型的策略模式。

38.知道 ThreadLocal 嗎?說說對它的理解?
39.在你寫代碼的過程中有使用過設(shè)計模式嗎?你知道哪些?為什么要這樣用,能解決什么問題?

build模式,觀察這模式。單例模式,工廠模式(比如環(huán)境變量 sit uat product env) 原型模式、策略模式

40.了解注解嗎?了解反射嗎?為什么要使用反射?

了解。一般注解和放射都在一塊使用,我曾經(jīng)寫過一個AOC框架,用來減少findviewByid的查找,

41.數(shù)據(jù)結(jié)構(gòu)中常用排序算法?

冒泡,基本排序,都得會

42.對asyncTask 的理解

一個進程里面所有AsyncTask對象都共享同一個SerialExecutor對象。

從execute里面就能看出,異步任務(wù)runable被放到了ArrayDeque對象mTasks中,然后通過scheduleNext()來從mTasks里面得到一個任務(wù)去一個后臺線程執(zhí)行。
在一個異步任務(wù)執(zhí)行后,再次調(diào)用scheduleNext來執(zhí)行下一個任務(wù)(run函數(shù))。
所以,很清楚,其實SerialExecutor是一個一個執(zhí)行任務(wù)的,而所有的AsyncTask對象又共享同一個SerialExecutor對象(靜態(tài)成員)。

如果想要執(zhí)行并行操作,傳入自定義的Excetor

其實內(nèi)部維護了一個線程池。

43. jvm 的gc那些事。

1.復(fù)制法
2.標記壓縮
3.標記清除法
4.分代法則用了兩種。

44.現(xiàn)在有T1、T2、T3三個線程,你怎樣保證T2在T1執(zhí)行完后執(zhí)行,T3在T2執(zhí)行完后執(zhí)行?

使用Tread.join() 方法。通過源碼可以看出 會檢測當(dāng)前線程是否是活躍的,如果是的話就會一直等待著。

  public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
45.2)在Java中Lock接口比synchronized塊的優(yōu)勢是什么?你需要實現(xiàn)一個高效的緩存,它允許多個用戶讀,但只允許一個用戶寫,以此來保持它的完整性,你會怎樣去實現(xiàn)它?

在多線程環(huán)境并存在大量競爭的情況下,synchronized的用時迅速上升,而lock卻依然保存不變或增加很少。
Lock是用CAS來實現(xiàn)的
JDK 1.6以上synchronized也改用CAS來實現(xiàn)了,所以兩者性能差不多
Lock提供的功能豐富點,synchronized的使用簡單點

46.java 怎么避免死鎖?又如何解決死鎖?
Thread 1:
  lock A 
  lock B

Thread 2:
   wait for A
   lock C (when A locked)

Thread 3:
   wait for A
   wait for B
   wait for C

1.注意加鎖的順序。
如果一個線程(比如線程3)需要一些鎖,那么它必須按照確定的順序獲取鎖。它只有獲得了從順序上排在前面的鎖之后,才能獲取后面的鎖。

例如,線程2和線程3只有在獲取了鎖A之后才能嘗試獲取鎖C(譯者注:獲取鎖A是獲取鎖C的必要條件)。因為線程1已經(jīng)擁有了鎖A,所以線程2和3需要一直等到鎖A被釋放。然后在它們嘗試對B或C加鎖之前,必須成功地對A加了鎖。

按照順序加鎖是一種有效的死鎖預(yù)防機制。但是,這種方式需要你事先知道所有可能會用到的鎖(譯者注:并對這些鎖做適當(dāng)?shù)呐判?,但總有些時候是無法預(yù)知的。
2.加鎖的時限。
另外一個可以避免死鎖的方法是在嘗試獲取鎖的時候加一個超時時間,這也就意味著在嘗試獲取鎖的過程中若超過了這個時限該線程則放棄對該鎖請求。若一個線程沒有在給定的時限內(nèi)成功獲得所有需要的鎖,則會進行回退并釋放所有已經(jīng)獲得的鎖,然后等待一段隨機的時間再重試。這段隨機的等待時間讓其它線程有機會嘗試獲取相同的這些鎖,并且讓該應(yīng)用在沒有獲得鎖的時候可以繼續(xù)運行(譯者注:加鎖超時后可以先繼續(xù)運行干點其它事情,再回頭來重復(fù)之前加鎖的邏輯)。

這種機制存在一個問題,在Java中不能對synchronized同步塊設(shè)置超時時間。你需要創(chuàng)建一個自定義鎖,或使用Java5中java.util.concurrent包下的工具。寫一個自定義鎖類不復(fù)雜,但超出了本文的內(nèi)容。后續(xù)的Java并發(fā)系列會涵蓋自定義鎖的內(nèi)容。

47.為什么要用線程池?

1.CPU中執(zhí)行上下文的切換,導(dǎo)致CPU中的「指令流水線(Instruction Pipeline)」的中斷和CPU緩存的失效。
2.如果線程太多,線程切換的時間會比線程執(zhí)行的時間要長,嚴重浪費了CPU資源。
3.對于共享資源的競爭(鎖)會導(dǎo)致線程切換開銷急劇增加。
線程池能更好的維護線程之間的工作切換,

48.
49.
50.
51.
52.
53.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,815評論 11 349
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,299評論 0 14
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,899評論 0 11
  • 本文出自 Eddy Wiki ,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 1,224評論 0 16
  • 一段失敗的關(guān)系就像討厭的不合腳的鞋,當(dāng)我為了美好的明天努力奔跑時,鞋子不跟腳,一會兒崴腳一會兒頂腳,讓我跑得力...
    柒色斐然閱讀 176評論 0 0

友情鏈接更多精彩內(nèi)容