面試整理-Java綜合高級篇(吐血整理)

Java面試總結(jié)

  • 交流或更多內(nèi)容請關(guān)注我的公眾號:nezha_blog
  • 我的技術(shù)博客:https://nezha.github.io
微信公眾號

1.你用過哪些集合類?

大公司最喜歡問的Java集合類面試題
40個Java集合面試問題和答案
java.util.Collections 是一個包裝類。它包含有各種有關(guān)集合操作的靜態(tài)多態(tài)方法。
java.util.Collection 是一個集合接口。它提供了對集合對象進(jìn)行基本操作的通用接口方法。

Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap


ArrayList、HashMap、TreeMap和HashTable類提供對元素的隨機(jī)訪問。

線程安全

Vector
HashTable(不允許插空值)

非線程安全

ArrayList
LinkedList
HashMap(允許插入空值)
HashSet
TreeSet
TreeMap(基于紅黑樹的Map實現(xiàn))

2.你說說 arraylist 和 linkedlist 的區(qū)別?

ArrayList和LinkedList兩者都實現(xiàn)了List接口,但是它們之間有些不同。
(1)ArrayList是由Array所支持的基于一個索引的數(shù)據(jù)結(jié)構(gòu),所以它提供對元素的隨機(jī)訪問
(2)與ArrayList相比,在LinkedList中插入、添加和刪除一個元素會更快
(3)LinkedList比ArrayList消耗更多的內(nèi)存,因為LinkedList中的每個節(jié)點(diǎn)存儲了前后節(jié)點(diǎn)的引用

3.HashMap 底層是怎么實現(xiàn)的?還有什么處理哈希沖突的方法?

處理哈希沖突的方法:

解決HashMap一般沒有什么特別好的方式,要不擴(kuò)容重新hash要不優(yōu)化沖突的鏈表結(jié)構(gòu)

1.開放定地址法-線性探測法
2.開放定地址法-平方探查法
3.鏈表解決-可以用紅黑樹提高查找效率

image.png

HashMap簡介
HashMap 是一個散列表,它存儲的內(nèi)容是鍵值對(key-value)映射。
HashMap 繼承于AbstractMap,實現(xiàn)了Map、Cloneable、java.io.Serializable接口。
HashMap 的實現(xiàn)不是同步的,這意味著它不是線程安全的,但可以用 Collections的synchronizedMap方法使HashMap具有線程安全的能力。它的key、value都可以為null。此外,HashMap中的映射不是有序的。
HashMap 的實例有兩個參數(shù)影響其性能:“初始容量” 和 “加載因子”。初始容量默認(rèn)是16。默認(rèn)加載因子是 0.75, 這是在時間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時也增加了查詢成本.
HashMap是數(shù)組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實現(xiàn)的,當(dāng)鏈表長度太長(默認(rèn)超過8)時,鏈表就轉(zhuǎn)換為紅黑樹.

image.png

Java8系列之重新認(rèn)識HashMap
功能實現(xiàn)-方法

  1. 確定哈希桶數(shù)組索引位置 :這里的Hash算法本質(zhì)上就是三步:取key的hashCode值、高位運(yùn)算、取模運(yùn)算。
方法一:
static final int hash(Object key) {   //jdk1.8 & jdk1.7
     int h;
     // h = key.hashCode() 為第一步 取hashCode值
     // h ^ (h >>> 16)  為第二步 高位參與運(yùn)算
     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
方法二:
static int indexFor(int h, int length) {  //jdk1.7的源碼,jdk1.8沒有這個方法,但是實現(xiàn)原理一樣的
     return h & (length-1);  //第三步 取模運(yùn)算
}
  1. 分析HashMap的put方法


    image.png
  1. 擴(kuò)容機(jī)制:原來的兩倍

4.熟悉什么算法,還有說說他們的時間復(fù)雜度?

經(jīng)典排序算法總結(jié)與實現(xiàn)

image.png

5.ArrayList和Vector的底層代碼和他們的增長策略,它們是如何進(jìn)行擴(kuò)容的?

ArrayList 默認(rèn)數(shù)組大小是10,其中ensureCapacity擴(kuò)容,trimToSize容量調(diào)整到適中,擴(kuò)展后數(shù)組大小為((原數(shù)組長度*1.5)與傳遞參數(shù)中較大者.
Vector的擴(kuò)容,是可以指定擴(kuò)容因子,同時Vector擴(kuò)容策略是:1.原來容量的2倍,2.原來容量+擴(kuò)容參數(shù)值。


詳細(xì)內(nèi)容可以配合閱讀源碼

6.jvm 原理。程序運(yùn)行區(qū)域劃分

問:Java運(yùn)行時數(shù)據(jù)區(qū)域?
回答:包括程序計數(shù)器、JVM棧、本地方法棧、方法區(qū)、堆
問:方法區(qū)里存放什么?
本地方法棧:和jvm棧所發(fā)揮的作用類似,區(qū)別是jvm棧為jvm執(zhí)行java方法(字節(jié)碼)服務(wù),而本地方法棧為jvm使用的native方法服務(wù)。
JVM棧:局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口。
方法區(qū):用于存儲已被虛擬機(jī)加載的類信息,常量、靜態(tài)變量、即時編譯器編譯后的代碼等。
堆:存放對象實例。

7.minor GC 與 Full GC,分別什么時候會觸發(fā)? 。分別采用哪種垃圾回收算法?簡單介紹算法

GC(或Minor GC):收集 生命周期短的區(qū)域(Young area)。
Full GC (或Major GC):收集生命周期短的區(qū)域(Young area)和生命周期比較長的區(qū)域(Old area)對整個堆進(jìn)行垃圾收集。
新生代通常存活時間較短基于Copying算法進(jìn)行回收,將可用內(nèi)存分為大小相等的兩塊,每次只使用其中一塊;當(dāng)這一塊用完了,就將還活著的對象復(fù)制到另一塊上,然后把已使用過的內(nèi)存清理掉。在HotSpot里,考慮到大部分對象存活時間很短將內(nèi)存分為Eden和兩塊Survivor,默認(rèn)比例為8:1:1。代價是存在部分內(nèi)存空間浪費(fèi),適合在新生代使用;
老年代新生代不同,老年代對象存活的時間比較長、比較穩(wěn)定,因此采用標(biāo)記(Mark)算法來進(jìn)行回收,所謂標(biāo)記就是掃描出存活的對象,然后再進(jìn)行回收未被標(biāo)記的對象,回收后對用空出的空間要么進(jìn)行合并、要么標(biāo)記出來便于下次進(jìn)行分配,總之目的就是要減少內(nèi)存碎片帶來的效率損耗。
在執(zhí)行機(jī)制上JVM提供了串行GC(Serial MSC)、并行GC(Parallel MSC)和并發(fā)GC(CMS)。

Minor GC ,F(xiàn)ull GC 觸發(fā)條件

  • Minor GC觸發(fā)條件:當(dāng)Eden區(qū)滿時,觸發(fā)Minor GC。

  • Full GC觸發(fā)條件:

  • (1)調(diào)用System.gc時,系統(tǒng)建議執(zhí)行Full GC,但是不必然執(zhí)行

  • (2)老年代空間不足

  • (3)方法去空間不足

  • (4)通過Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存

  • (5)由Eden區(qū)、From Space區(qū)向To Space區(qū)復(fù)制時,對象大小大于To Space可用內(nèi)存,則把該對象轉(zhuǎn)存到老年代,且老年代的可用內(nèi)存小于該對象大小

8.HashMap 實現(xiàn)原理

在java編程語言中,最基本的結(jié)構(gòu)就是兩種,一個是數(shù)組,另外一個是模擬指針(引用),所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個基本結(jié)構(gòu)來構(gòu)造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數(shù)據(jù)結(jié)構(gòu),即數(shù)組和鏈表的結(jié)合體。

9.java.util.concurrent 包下使用過哪些

1.阻塞隊列 BlockingQueue( ArrayBlockingQueue, DelayQueue, LinkedBlockingQueue, SynchronousQueue,LinkedTransferQueue,LinkedBlockingDeque)
2.ConcurrentHashMap
3.Semaphore--信號量
4.CountDownLatch--閉鎖
5.CyclicBarrier--柵欄
6.Exchanger--交換機(jī)
7.Executor->ThreadPoolExecutor,ScheduledThreadPoolExecutor

Semaphore semaphore = new Semaphore(1);  
//critical section  
semaphore.acquire();  
...  
semaphore.release();

8.鎖 Lock--ReentrantLock,ReadWriteLock,Condition,LockSupport

Lock lock = new ReentrantLock();  
lock.lock();  
//critical section  
lock.unlock();

10.concurrentMap 和 HashMap 區(qū)別

1.hashMap可以有null的鍵,concurrentMap不可以有
2.hashMap是線程不安全的,在多線程的時候需要Collections.synchronizedMap(hashMap),ConcurrentMap使用了重入鎖保證線程安全。
3.在刪除元素時候,兩者的算法不一樣。
ConcurrentHashMapHashtable主要區(qū)別就是圍繞著鎖的粒度以及如何鎖,可以簡單理解成把一個大的HashTable分解成多個,形成了鎖分離。

11.信號量是什么,怎么使用?volatile關(guān)鍵字是什么?

信號量-semaphore:荷蘭著名的計算機(jī)科學(xué)家Dijkstra 于1965年提出的一個同步機(jī)制。是在多線程環(huán)境下使用的一種設(shè)施, 它負(fù)責(zé)協(xié)調(diào)各個線程, 以保證它們能夠正確、合理的使用公共資源。
整形信號量:表示共享資源狀態(tài),且只能由特殊的原子操作改變整型量。
同步與互斥:同類進(jìn)程為互斥關(guān)系(打印機(jī)問題),不同進(jìn)程為同步關(guān)系(消費(fèi)者生產(chǎn)者)。


使用volatile關(guān)鍵字是解決同步問題的一種有效手段。 java volatile關(guān)鍵字預(yù)示著這個變量始終是“存儲進(jìn)入了主存”。更精確的表述就是每一次讀一個volatile變量,都會從主存讀取,而不是CPU的緩存。同樣的道理,每次寫一個volatile變量,都是寫回主存,而不僅僅是CPU的緩存。
Java 保證volatile關(guān)鍵字保證變量的改變對各個線程是可見的。

image.png

12.阻塞隊列了解嗎?怎么使用

阻塞隊列 (BlockingQueue)是Java util.concurrent包下重要的數(shù)據(jù)結(jié)構(gòu),BlockingQueue提供了線程安全的隊列訪問方式:當(dāng)阻塞隊列進(jìn)行插入數(shù)據(jù)時,如果隊列已滿,線程將會阻塞等待直到隊列非滿;從阻塞隊列取數(shù)據(jù)時,如果隊列已空,線程將會阻塞等待直到隊列非空。并發(fā)包下很多高級同步類的實現(xiàn)都是基于BlockingQueue實現(xiàn)的。

image.png

image.png

以ArrayBlockingQueue為例,我們先來看看代碼:

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

put方法的實現(xiàn)可以看出,它先獲取了鎖,并且獲取的是可中斷鎖,然后判斷當(dāng)前元素個數(shù)是否等于數(shù)組的長度,如果相等,則調(diào)用notFull.await()進(jìn)行等待,當(dāng)被其他線程喚醒時,通過enqueue(e)方法插入元素,最后解鎖。

/**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
private void enqueue(E x) {
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length) putIndex = 0;
    count++;
    notEmpty.signal();
}

插入成功后,通過notEmpty喚醒正在等待取元素的線程。

13.Java中的NIO,BIO,AIO分別是什么?

IO的方式通常分為幾種,同步阻塞的BIO、同步非阻塞的NIO、異步非阻塞的AIO

1.BIO,同步阻塞式IO,簡單理解:一個連接一個線程.BIO方式適用于連接數(shù)目比較小且固定的架構(gòu),這種方式對服務(wù)器資源要求比較高,并發(fā)局限于應(yīng)用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。

在JDK1.4之前,用Java編寫網(wǎng)絡(luò)請求,都是建立一個ServerSocket,然后,客戶端建立Socket時就會詢問是否有線程可以處理,如果沒有,要么等待,要么被拒絕。即:一個連接,要求Server對應(yīng)一個處理線程。

2.NIO,同步非阻塞IO,簡單理解:一個請求一個線程.NIO方式適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu),比如聊天服務(wù)器,并發(fā)局限于應(yīng)用中,編程比較復(fù)雜,JDK1.4開始支持。

NIO本身是基于事件驅(qū)動思想來完成的,其主要想解決的是BIO的大并發(fā)問題: 在使用同步I/O的網(wǎng)絡(luò)應(yīng)用中,如果要同時處理多個客戶端請求,或是在客戶端要同時和多個服務(wù)器進(jìn)行通訊,就必須使用多線程來處理。也就是說,將每一個客戶端請求分配給一個線程來單獨(dú)處理。這樣做雖然可以達(dá)到我們的要求,但同時又會帶來另外一個問題。由于每創(chuàng)建一個線程,就要為這個線程分配一定的內(nèi)存空間(也叫工作存儲器),而且操作系統(tǒng)本身也對線程的總數(shù)有一定的限制。如果客戶端的請求過多,服務(wù)端程序可能會因為不堪重負(fù)而拒絕客戶端的請求,甚至服務(wù)器可能會因此而癱瘓。

3.AIO,異步非阻塞IO,簡單理解:一個有效請求一個線程.AIO方式使用于連接數(shù)目多且連接比較長(重操作)的架構(gòu),比如相冊服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜,JDK7開始支持。

14.類加載機(jī)制是怎樣的

JVM中類的裝載是由ClassLoader和它的子類來實現(xiàn)的,Java ClassLoader是一個重要的Java運(yùn)行時系統(tǒng)組件。它負(fù)責(zé)在運(yùn)行時查找和裝入類文件的類。
類加載的五個過程:加載、驗證、準(zhǔn)備、解析、初始化。

從類被加載到虛擬機(jī)內(nèi)存中開始,到卸御出內(nèi)存為止,它的整個生命周期分為7個階段,加載(Loading)、驗證(Verification)、準(zhǔn)備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸御(Unloading)。其中驗證、準(zhǔn)備、解析三個部分統(tǒng)稱為連接。

15.什么是冪等性

所謂冪等,簡單地說,就是對接口的多次調(diào)用所產(chǎn)生的結(jié)果和調(diào)用一次是一致的。
那么我們?yōu)槭裁葱枰涌诰哂袃绲刃阅??設(shè)想一下以下情形:

  • 在App中下訂單的時候,點(diǎn)擊確認(rèn)之后,沒反應(yīng),就又點(diǎn)擊了幾次。在這種情況下,如果無法保證該接口的冪等性,那么將會出現(xiàn)重復(fù)下單問題。
  • 在接收消息的時候,消息推送重復(fù)。如果處理消息的接口無法保證冪等,那么重復(fù)消費(fèi)消息產(chǎn)生的影響可能會非常大。

16.有哪些 JVM 調(diào)優(yōu)經(jīng)驗

Jvm參數(shù)總結(jié):http://linfengying.com/?p=2470

參數(shù) 作用
-Xmx 堆大小的最大值。當(dāng)前主流虛擬機(jī)的堆都是可擴(kuò)展的
-Xms 堆大小的最小值??梢栽O(shè)置成和 -Xmx 一樣的值
-Xmn 新生代的大小。現(xiàn)代虛擬機(jī)都是“分代”的,因此堆空間由新生代和老年代組成。新生代增大,相應(yīng)地老年代就減小。Sun官方推薦新生代占整個堆的3/8
-Xss 每個線程的堆棧大小。該值影響一臺機(jī)器能夠創(chuàng)建的線程數(shù)上限
-XX:MaxPermSize= 永久代的最大值。永久代是 HotSpot 特有的,HotSpot 用永久代來實現(xiàn)方法區(qū)
-XX:PermSize= 永久代的最小值??梢栽O(shè)置成和 -XX:MaxPermSize 一樣的值
-XX:SurvivorRatio= Eden 和 Survivor 的比值?;凇皬?fù)制”的垃圾收集器又會把新生代分為一個 Eden 和兩個 Survivor,如果該參數(shù)為8,就表示 Eden 占新生代的80%,而兩個 Survivor 各占10%。默認(rèn)值為8
-XX:PretenureSizeThreshold= 直接晉升到老年代的對象大小。大于這個參數(shù)的對象將直接在老年代分配。默認(rèn)值為0,表示不啟用
-XX:HandlePromotionFailure= 是否允許分配擔(dān)保失敗。在 JDK 6 Update 24 后該參數(shù)已經(jīng)失效。
-XX:MaxTenuringThreshold= 對象晉升到老年代的年齡。對象每經(jīng)過一次 Minor GC 后年齡就加1,超過這個值時就進(jìn)入老年代。默認(rèn)值為15
-XX:MaxDirectMemorySize= 直接內(nèi)存的最大值。對于頻繁使用 nio 的應(yīng)用,應(yīng)該顯式設(shè)置該參數(shù),默認(rèn)值為0

內(nèi)存參數(shù)

參數(shù) 作用
-Xmx 堆大小的最大值。當(dāng)前主流虛擬機(jī)的堆都是可擴(kuò)展的
-Xms 堆大小的最小值??梢栽O(shè)置成和 -Xmx 一樣的值
-Xmn 新生代的大小?,F(xiàn)代虛擬機(jī)都是“分代”的,因此堆空間由新生代和老年代組成。新生代增大,相應(yīng)地老年代就減小。Sun官方推薦新生代占整個堆的3/8
-Xss 每個線程的堆棧大小。該值影響一臺機(jī)器能夠創(chuàng)建的線程數(shù)上限
-XX:MaxPermSize= 永久代的最大值。永久代是 HotSpot 特有的,HotSpot 用永久代來實現(xiàn)方法區(qū)
-XX:PermSize= 永久代的最小值??梢栽O(shè)置成和 -XX:MaxPermSize 一樣的值
-XX:SurvivorRatio= Eden 和 Survivor 的比值?;凇皬?fù)制”的垃圾收集器又會把新生代分為一個 Eden 和兩個 Survivor,如果該參數(shù)為8,就表示 Eden 占新生代的80%,而兩個 Survivor 各占10%。默認(rèn)值為8
-XX:PretenureSizeThreshold= 直接晉升到老年代的對象大小。大于這個參數(shù)的對象將直接在老年代分配。默認(rèn)值為0,表示不啟用
-XX:HandlePromotionFailure= 是否允許分配擔(dān)保失敗。在 JDK 6 Update 24 后該參數(shù)已經(jīng)失效。
-XX:MaxTenuringThreshold= 對象晉升到老年代的年齡。對象每經(jīng)過一次 Minor GC 后年齡就加1,超過這個值時就進(jìn)入老年代。默認(rèn)值為15
-XX:MaxDirectMemorySize= 直接內(nèi)存的最大值。對于頻繁使用 nio 的應(yīng)用,應(yīng)該顯式設(shè)置該參數(shù),默認(rèn)值為0
垃圾收集器 參數(shù) 備注
Serial(新生代) -XX:+UseSerialGC 虛擬機(jī)在 Client 模式下的默認(rèn)值,打開此開關(guān)后,使用 Serial + Serial Old 的收集器組合。Serial 是一個單線程的收集器
ParNew(新生代) -XX:+UseParNewGC 強(qiáng)制使用 ParNew,打開此開關(guān)后,使用 ParNew + Serial Old 的收集器組合。ParNew 是一個多線程的收集器,也是 server 模式下首選的新生代收集器
-XX:ParallelGCThreads= 垃圾收集的線程數(shù)
Parallel Scavenge(新生代) -XX:+UseParallelGC 虛擬機(jī)在 Server 模式下的默認(rèn)值,打開此開關(guān)后,使用 Parallel Scavenge + Serial Old 的收集器組合
-XX:MaxGCPauseMillis= 單位毫秒,收集器盡可能保證單次內(nèi)存回收停頓的時間不超過這個值。
-XX:GCTimeRatio= 總的用于 gc 的時間占應(yīng)用程序的百分比,該參數(shù)用于控制程序的吞吐量
-XX:+UseAdaptiveSizePolicy 設(shè)置了這個參數(shù)后,就不再需要指定新生代的大小(-Xmn)、 Eden 和 Survisor 的比例(-XX:SurvivorRatio)以及晉升老年代對象的年齡(-XX:PretenureSizeThreshold)了,因為該收集器會根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況自動調(diào)整。當(dāng)然前提是先設(shè)置好前兩個參數(shù)。
Serial Old(老年代) Serial Old 是 Serial 的老年代版本,主要用于 Client 模式下的老生代收集,同時也是 CMS 在發(fā)生 Concurrent Mode Failure 時的后備方案
Parallel Old(老年代) -XX:+UseParallelOldGC 打開此開關(guān)后,使用 Parallel Scavenge + Parallel Old 的收集器組合。Parallel Old 是 Parallel Scavenge 的老年代版本,在注重吞吐量和 CPU 資源敏感的場合,可以優(yōu)先考慮這個組合
CMS(老年代) -XX:+UseConcMarkSweepGC 打開此開關(guān)后,使用 ParNew + CMS 的收集器組合。
-XX:CMSInitiatingOccupancyFraction= CMS 收集器在老年代空間被使用多少后觸發(fā)垃圾收集
-XX:+UseCMSCompactAtFullCollection 在完成垃圾收集后是否要進(jìn)行一次內(nèi)存碎片整理
-XX:CMSFullGCsBeforeCompaction= 在進(jìn)行若干次垃圾收集后才進(jìn)行一次內(nèi)存碎片整理

GC參數(shù)

垃圾收集器 參數(shù) 備注
Serial(新生代) -XX:+UseSerialGC 虛擬機(jī)在 Client 模式下的默認(rèn)值,打開此開關(guān)后,使用 Serial + Serial Old 的收集器組合。Serial 是一個單線程的收集器
ParNew(新生代) -XX:+UseParNewGC 強(qiáng)制使用 ParNew,打開此開關(guān)后,使用 ParNew + Serial Old 的收集器組合。ParNew 是一個多線程的收集器,也是 server 模式下首選的新生代收集器
-XX:ParallelGCThreads= 垃圾收集的線程數(shù)
Parallel Scavenge(新生代) -XX:+UseParallelGC 虛擬機(jī)在 Server 模式下的默認(rèn)值,打開此開關(guān)后,使用 Parallel Scavenge + Serial Old 的收集器組合
-XX:MaxGCPauseMillis= 單位毫秒,收集器盡可能保證單次內(nèi)存回收停頓的時間不超過這個值。
-XX:GCTimeRatio= 總的用于 gc 的時間占應(yīng)用程序的百分比,該參數(shù)用于控制程序的吞吐量
-XX:+UseAdaptiveSizePolicy 設(shè)置了這個參數(shù)后,就不再需要指定新生代的大?。?Xmn)、 Eden 和 Survisor 的比例(-XX:SurvivorRatio)以及晉升老年代對象的年齡(-XX:PretenureSizeThreshold)了,因為該收集器會根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況自動調(diào)整。當(dāng)然前提是先設(shè)置好前兩個參數(shù)。
Serial Old(老年代) Serial Old 是 Serial 的老年代版本,主要用于 Client 模式下的老生代收集,同時也是 CMS 在發(fā)生 Concurrent Mode Failure 時的后備方案
Parallel Old(老年代) -XX:+UseParallelOldGC 打開此開關(guān)后,使用 Parallel Scavenge + Parallel Old 的收集器組合。Parallel Old 是 Parallel Scavenge 的老年代版本,在注重吞吐量和 CPU 資源敏感的場合,可以優(yōu)先考慮這個組合
CMS(老年代) -XX:+UseConcMarkSweepGC 打開此開關(guān)后,使用 ParNew + CMS 的收集器組合。
-XX:CMSInitiatingOccupancyFraction= CMS 收集器在老年代空間被使用多少后觸發(fā)垃圾收集
-XX:+UseCMSCompactAtFullCollection 在完成垃圾收集后是否要進(jìn)行一次內(nèi)存碎片整理
-XX:CMSFullGCsBeforeCompaction= 在進(jìn)行若干次垃圾收集后才進(jìn)行一次內(nèi)存碎片整理

附圖:可以配合使用的收集器組合

image.png

上面有7中收集器,分為兩塊,上面為新生代收集器,下面是老年代收集器。如果兩個收集器之間存在連線,就說明它們可以搭配使用。

參數(shù) 作用
-verbose:class 打印類加載過程
-XX:+PrintGCDetails 發(fā)生垃圾收集時打印 gc 日志,該參數(shù)會自動帶上 -verbose:gc 和 -XX:+PrintGC
-XX:+PrintGCDateStamps / -XX:+PrintGCTimeStamps 打印 gc 的觸發(fā)事件,可以和 -XX:+PrintGC 和 -XX:+PrintGCDetails 混用
-Xloggc:<path> gc 日志路徑
-XX:+HeapDumpOnOutOfMemoryError 出現(xiàn) OOM 時 dump 出內(nèi)存快照用于事后分析
-XX:HeapDumpPath= 堆轉(zhuǎn)儲快照的文件路徑

其他參數(shù)

參數(shù) 作用
-verbose:class 打印類加載過程
-XX:+PrintGCDetails 發(fā)生垃圾收集時打印 gc 日志,該參數(shù)會自動帶上 -verbose:gc 和 -XX:+PrintGC
-XX:+PrintGCDateStamps / -XX:+PrintGCTimeStamps 打印 gc 的觸發(fā)事件,可以和 -XX:+PrintGC 和 -XX:+PrintGCDetails 混用
-Xloggc:<path> gc 日志路徑
-XX:+HeapDumpOnOutOfMemoryError 出現(xiàn) OOM 時 dump 出內(nèi)存快照用于事后分析
-XX:HeapDumpPath= 堆轉(zhuǎn)儲快照的文件路徑

17.分布式 CAP 了解嗎?

一致性(Consistency)
可用性(Availability)
分區(qū)容忍性(Partition tolerance)

18.Java中HashMap的key值要是為類對象則該類需要滿足什么條件?

需要同時重寫該類的hashCode()方法和它的equals()方法。

當(dāng)程序試圖將一個 key-value 對放入 HashMap 中時,程序首先根據(jù)該 key 的 hashCode() 返回值決定該 Entry 的存儲位置:如果兩個 Entry 的 key 的 hashCode() 返回值相同,那它們的存儲位置相同。如果這兩個 Entry 的 key 通過 equals 比較返回 true,新添加 Entry 的 value 將覆蓋集合中原有 Entry 的 value,但 key 不會覆蓋。如果這兩個 Entry 的 key 通過 equals 比較返回 false,新添加的 Entry 將與集合中原有 Entry 形成 Entry 鏈,而且新添加的 Entry 位于 Entry 鏈的頭部——具體說明繼續(xù)看 addEntry() 方法的說明。

19.java 垃圾回收會出現(xiàn)不可回收的對象嗎?怎么解決內(nèi)存泄露問題?怎么定位問題源?

一般不會有不可回收的對象,因為現(xiàn)在的GC會回收不可達(dá)內(nèi)存。

20.終止線程有幾種方式?終止線程標(biāo)記變量為什么是 valotile 類型?

1.線程正常執(zhí)行完畢,正常結(jié)束
2.監(jiān)視某些條件,結(jié)束線程的不間斷運(yùn)行
3.使用interrupt方法終止線程

在定義exit時,使用了一個Java關(guān)鍵字volatile,這個關(guān)鍵字的目的是使exit同步,也就是說在同一時刻只能由一個線程來修改exit的值

21.用過哪些并發(fā)的數(shù)據(jù)結(jié)構(gòu)? cyclicBarrier 什么功能?信號量作用?數(shù)據(jù)庫讀寫阻塞怎么解決

  • 主要有鎖機(jī)制,然后基于CAS的concurrent包。
  • CyclicBarrier的字面意思是可循環(huán)使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組線程到達(dá)一個屏障(也可以叫同步點(diǎn))時被阻塞,直到最后一個線程到達(dá)屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續(xù)干活。CyclicBarrier默認(rèn)的構(gòu)造方法是CyclicBarrier(int parties),其參數(shù)表示屏障攔截的線程數(shù)量,每個線程調(diào)用await方法告訴CyclicBarrier我已經(jīng)到達(dá)了屏障,然后當(dāng)前線程被阻塞。
    CountDownLatch的計數(shù)器只能使用一次。而CyclicBarrier的計數(shù)器可以使用reset() 方法重置。
  • Semaphore(信號量)是用來控制同時訪問特定資源的線程數(shù)量,它通過協(xié)調(diào)各個線程,以保證合理的使用公共資源。很多年以來,我都覺得從字面上很難理解Semaphore所表達(dá)的含義,只能把它比作是控制流量的紅綠燈,比如XX馬路要限制流量,只允許同時有一百輛車在這條路上行使,其他的都必須在路口等待,所以前一百輛車會看到綠燈,可以開進(jìn)這條馬路,后面的車會看到紅燈,不能駛?cè)隭X馬路,但是如果前一百輛中有五輛車已經(jīng)離開了XX馬路,那么后面就允許有5輛車駛?cè)腭R路,這個例子里說的車就是線程,駛?cè)腭R路就表示線程在執(zhí)行,離開馬路就表示線程執(zhí)行完成,看見紅燈就表示線程被阻塞,不能執(zhí)行。

22.關(guān)于抽象類和接口的關(guān)系

簡言之抽象類是一種功能不全的類,接口只是一個抽象方法聲明和靜態(tài)不能被修改的數(shù)據(jù)的集合,兩者都不能被實例化。
從某種意義上說,接口是一種特殊形式的抽象類,在java語言中抽象類表示的是一種繼承關(guān)系,一個類只能繼承繼承一個抽象類,而一個類卻可以實現(xiàn)多個接口。在許多情況下,接口確實可以代替抽象類,如果你不需要刻意表達(dá)屬性上的繼承的話。

23.堆內(nèi)存和棧內(nèi)存的區(qū)別

寄存器:JVM內(nèi)部虛擬寄存器,存取速度非???,程序不可控制。
:保存局部變量的值包括:1.保存基本數(shù)據(jù)類型的值;2.保存引用變量,即堆區(qū)對象的引用(指針)。也可以用來保存加載方法時的幀。
:用來存放動態(tài)產(chǎn)生的數(shù)據(jù),比如new出來的對象。注意創(chuàng)建出來的對象只包含屬于各自的成員變量,并不包括成員方法。因為同一個類的對象擁有各自的成員變量,存儲在各自的堆中,但是他們共享該類的方法,并不是每創(chuàng)建一個對象就把成員方法復(fù)制一次。
常量池:JVM為每個已加載的類型維護(hù)一個常量池,常量池就是這個類型用到的常量的一個有序集合。包括直接常量(基本類型,String)和對其他類型、方法、字段的符號引用(1)。池中的數(shù)據(jù)和數(shù)組一樣通過索引訪問。由于常量池包含了一個類型所有的對其他類型、方法、字段的符號引用,所以常量池在Java的動態(tài)鏈接中起了核心作用。常量池存在于堆中。
代碼段:用來存放從硬盤上讀取的源程序代碼。
數(shù)據(jù)段:用來存放static修飾的靜態(tài)成員(在java中static的作用就是說明該變量,方法,代碼塊是屬于類的還是屬于實例的)。

image.png

24.關(guān)于Java文件的內(nèi)部類的解釋?匿名內(nèi)部類是什么?如何訪問在其外面定義的變量?

java中的內(nèi)部類總結(jié)
靜態(tài)內(nèi)部類不能訪問外部類非靜態(tài)的成員

25.關(guān)于重載和重寫的區(qū)別

重載是overload,是一個類中同方法名的不同具體實現(xiàn)。然后重寫是override,是子類重寫父類中的方法。

26.String、StringBuffer與StringBuilder之間區(qū)別

1.三者在執(zhí)行速度方面的比較:StringBuilder > StringBuffer > String

String:字符串常量
StringBuffer:字符串變量
StringBuilder:字符串變量

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

27.運(yùn)行時異常與一般異常有何異同?常見異常

Java提供了兩類主要的異常:runtime exception和checked exception
常見異常:NullPointerException、IndexOutOfBoundsException、ClassNotFoundException,IllegalArgumentException,ClassCastException(數(shù)據(jù)類型轉(zhuǎn)換異常)

28.error和exception有什么區(qū)別?

error 表示恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題。比如說內(nèi)存溢出。不可能指望程序能處理這樣的情況。
exception表示一種設(shè)計或?qū)崿F(xiàn)問題。也就是說,它表示如果程序運(yùn)行正常,從不會發(fā)生的情況。

29.Java異常處理機(jī)制

image.png

1.捕獲異常:try、catch 和 finally
2.拋出異常
2.1. throws拋出異常

methodname throws Exception1,Exception2,..,ExceptionN  
{  }  

30.java中有幾種方法可以實現(xiàn)一個線程?

Java多線程學(xué)習(xí)(吐血超詳細(xì)總結(jié))
40個Java多線程問題總結(jié)


1.class Thread1 extends Thread{},然后重寫run方法
2.class Thread2 implements Runnable{},然后重寫run方法
3.class Thread3 implements Callable<Integer>{},然后new FutureTask(thread3),再用new Thread(future)封裝。

class Thread1 extends Thread {
    private String name;
    public Thread1(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "運(yùn)行--->>>" + i);
        }
    }
    
    public static void main(String[] args) {
        Thread1 mTh11=new Thread1("A");
        Thread1 mTh12=new Thread1("B");
        mTh1.start();
        mTh2.start();
    }
}


class Thread2 implements Runnable {
    private String name;
    private int count = 15;
    public Thread2() {
    }
    public Thread2(String name) {
        this.name = name;
    }
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "運(yùn)行  :  " + count--);
        }
    }
    public static void main(String[] args) {
        Thread2 mTh2 = new Thread2();
        new Thread(mTh2, "C").start();
        new Thread(mTh2, "D").start();
    }
}


class MyCallableThread implements Callable<Integer>{
        public Integer call() throws Exception {
        int i = 0;
        for(;i<100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
        return i;
    }
    
    public static void main(String[] args) {
        MyCallableThread mct = new MyCallableThread();
        FutureTask<Integer> ft = new FutureTask<Integer>(mct);
        for(int i = 0;i < 100;i++)
        {
            System.out.println(Thread.currentThread().getName()+" 的循環(huán)變量i的值"+i);
            if(i==20)
            {
                new Thread(ft,"有返回值的線程").start();
            }
        }
        try
        {
            System.out.println("子線程的返回值:"+ft.get());
        } catch (InterruptedException e)
        {
            e.printStackTrace();
        } catch (ExecutionException e)
        {
            e.printStackTrace();
        }
    }
}

如果一個類繼承Thread,則不適合資源共享。但是如果實現(xiàn)了Runable接口的話,則很容易的實現(xiàn)資源共享。

31.Java中常用的類,包,接口。

class: 'Date','System','Calender','Math','ArrayList','HashMap'
package: 'java.lang','java.util','java.io','java.sql','java.net'
interface: 'Collection','Map','List','Runnable','Callable'

32.java在處理線程同步時,常用方法有:

1、synchronized關(guān)鍵字。
2、Lock顯示加鎖。
3、信號量Semaphore。
4、CAS算法
5、concurrent包

33.Spring IOC/AOP?

回答了IOC/DI、AOP的概念。
AOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向?qū)ο缶幊蹋┑难a(bǔ)充和完善。
OOP引入封裝、繼承和多態(tài)性等概念來建立一種對象層次結(jié)構(gòu),用以模擬公共行為的一個集合。當(dāng)我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。
也就是說,OOP允許你定義從上到下的關(guān)系,但并不適合定義從左到右的關(guān)系。例如日志功能。日志代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關(guān)系。
對于其他類型的代碼,如安全性、異常處理和透明的持續(xù)性也是如此。這種散布在各處的無關(guān)的代碼被稱為橫切(cross-cutting)代碼,
在OOP設(shè)計中,它導(dǎo)致了大量代碼的重復(fù),而不利于各個模塊的重用。
依賴注入(Dependency Injection)和控制反轉(zhuǎn)(Inversion of Control)是同一個概念。
當(dāng)某個角色(可能是一個Java實例,調(diào)用者)需要另一個角色(另一個Java實例,被調(diào)用者)的協(xié)助時,在傳統(tǒng)的程序設(shè)計過程中,通常由調(diào)用者來創(chuàng)建被調(diào)用者的實例。
但在Spring里,創(chuàng)建被調(diào)用者的工作不再由調(diào)用者來完成,因此稱為控制反轉(zhuǎn);創(chuàng)建被調(diào)用者 實例的工作通常由Spring容器來完成,然后注入調(diào)用者,因此也稱為依賴注入。
不管是依賴注入,還是控制反轉(zhuǎn),都說明Spring采用動態(tài)、靈活的方式來管理各種對象。對象與對象之間的具體實現(xiàn)互相透明。
在理解依賴注入之前,看如下這個問題在各種社會形態(tài)里如何解決:一個人(Java實例,調(diào)用者)需要一把斧子(Java實例,被調(diào)用者)。

34.對JVM的垃圾回收的認(rèn)識?

垃圾回收器的作用是查找和回收(清理)無用的對象。以便讓JVM更有效的使用內(nèi)存。

35.進(jìn)程與線程的區(qū)別,及其通信方式

線程與進(jìn)程的區(qū)別及其通信方式
區(qū)別
1.一個程序至少有一個進(jìn)程,一個進(jìn)程至少有一個線程.
2.進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元,而多個線程共享內(nèi)存
3.線程是進(jìn)程的一個實體,是CPU調(diào)度和分派的基本單位

  • 進(jìn)程間通信
1.管道(Pipe)及有名管道(named pipe)
2.信號(Signal)
3.消息隊列(Message)
4.共享內(nèi)存
5.信號量(semaphore)
6.套接口(Socket)

36.JVM如何GC,新生代,老年代,持久代,都存儲哪些東西?

JVM的GC算法有:引用計數(shù)器算法,根搜索方法

新生成的對象首先都是放在年輕代的。年輕代的目標(biāo)就是盡可能快速的收集掉那些生命周期短的對象。

在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認(rèn)為年老代中存放的都是一些生命周期較長的對象。

持久代主要存放的是Java類的類信息

37.JVM分為哪些區(qū),每一個區(qū)干嘛的?

問:Java運(yùn)行時數(shù)據(jù)區(qū)域?
回答:包括程序計數(shù)器、JVM棧、本地方法棧、方法區(qū)、堆
問:方法區(qū)里存放什么?
本地方法棧:和jvm棧所發(fā)揮的作用類似,區(qū)別是jvm棧為jvm執(zhí)行java方法(字節(jié)碼)服務(wù),而本地方法棧為jvm使用的native方法服務(wù)。
JVM棧:局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口。
方法區(qū):用于存儲已被虛擬機(jī)加載的類信息,常量、靜態(tài)變量、即時編譯器編譯后的代碼等。
堆:存放對象實例。

38.GC用的引用可達(dá)性分析算法中,哪些對象可作為GC Roots對象?

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象;
  • 方法區(qū)中類靜態(tài)屬性引用的對象;
  • 方法區(qū)中常量引用的對象;
  • 本地方法棧中JNI(即一般說的Native方法)引用的對象

39.用什么工具調(diào)試程序?jmap、jstack,JConsole,用過嗎?

虛擬機(jī)性能監(jiān)控與調(diào)優(yōu)實戰(zhàn)--博客

40.線程池用過嗎?

線程池--并發(fā)編程網(wǎng) - ifeve.com

線程池(Thread Pool)對于限制應(yīng)用程序中同一時刻運(yùn)行的線程數(shù)很有用。因為每啟動一個新線程都會有相應(yīng)的性能開銷,每個線程都需要給棧分配一些內(nèi)存等等。

我們可以把并發(fā)執(zhí)行的任務(wù)傳遞給一個線程池,來替代為每個并發(fā)執(zhí)行的任務(wù)都啟動一個新的線程。只要池里有空閑的線程,任務(wù)就會分配給一個線程執(zhí)行。在線程池的內(nèi)部,任務(wù)被插入一個阻塞隊列(Blocking Queue ),線程池里的線程會去取這個隊列里的任務(wù)。當(dāng)一個新任務(wù)插入隊列時,一個空閑線程就會成功的從隊列中取出任務(wù)并且執(zhí)行它。

41.操作系統(tǒng)如何進(jìn)行分頁調(diào)度?--要考LRU

1.最講置換原則-OPT
2.先進(jìn)先出原則-FIFO
3.最近最少使用置換算法-LRU
4.時鐘置換算法

//擴(kuò)展一下LinkedHashMap這個類,讓他實現(xiàn)LRU算法
class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{
    //定義緩存的容量
    private int capacity;
    private static final long serialVersionUID = 1L;
    //帶參數(shù)的構(gòu)造器
    LRULinkedHashMap(int capacity){
        //調(diào)用LinkedHashMap的構(gòu)造器,傳入以下參數(shù)
        super(16,0.75f,true);
        //傳入指定的緩存最大容量
        this.capacity=capacity;
    }
    //實現(xiàn)LRU的關(guān)鍵方法,如果map里面的元素個數(shù)大于了緩存最大容量,則刪除鏈表的頂端元素
    @Override
    public boolean removeEldestEntry(Map.Entry<K, V> eldest){
        System.out.println(eldest.getKey() + "=" + eldest.getValue());
        return size()>capacity;
    }
}

42.講講LinkedHashMap

Java8 LinkedHashMap工作原理及實現(xiàn)

LinkedHashMap是通過哈希表和鏈表實現(xiàn)的,它通過維護(hù)一個鏈表來保證對哈希表迭代時的有序性,而這個有序是指鍵值對插入的順序。

LinkedHashMap 的大致實現(xiàn)如下圖所示,當(dāng)然鏈表和哈希表中相同的鍵值對都是指向同一個對象,這里把它們分開來畫只是為了呈現(xiàn)出比較清晰的結(jié)構(gòu)。

image.png

LinkedHashMap是Hash表和鏈表的實現(xiàn),并且依靠著雙向鏈表保證了迭代順序是插入的順序。

三個重點(diǎn)實現(xiàn)的函數(shù)

在HashMap中提到了下面的定義:

// Callbacks to allow LinkedHashMap post-actions
//1.把當(dāng)前節(jié)點(diǎn)e移至鏈表的尾部。因為使用的是雙向鏈表,所以在尾部插入可以以O(shè)(1)的時間復(fù)雜度來完成。并且只有當(dāng)accessOrder設(shè)置為true時,才會執(zhí)行這個操作。在HashMap的putVal方法中,就調(diào)用了這個方法。
void afterNodeAccess(Node<K,V> p) { }
//2.afterNodeInsertion方法是在哈希表中插入了一個新節(jié)點(diǎn)時調(diào)用的,它會把鏈表的頭節(jié)點(diǎn)刪除掉,刪除的方式是通過調(diào)用HashMap的removeNode方法。通過afterNodeInsertion方法和afterNodeAccess方法,是不是就可以簡單的實現(xiàn)一個基于最近最少使用(LRU)的淘汰策略了?當(dāng)然,我們還要重寫removeEldestEntry方法,因為它默認(rèn)返回的是false。
void afterNodeInsertion(boolean evict) { }
//3.這個方法是當(dāng)HashMap刪除一個鍵值對時調(diào)用的,它會把在HashMap中刪除的那個鍵值對一并從鏈表中刪除,保證了哈希表和鏈表的一致性。
void afterNodeRemoval(Node<K,V> p) { }

LinkedHashMap繼承于HashMap,因此也重新實現(xiàn)了這3個函數(shù),顧名思義這三個函數(shù)的作用分別是:節(jié)點(diǎn)訪問后、節(jié)點(diǎn)插入后、節(jié)點(diǎn)移除后做一些事情。

43.線程同步與阻塞的關(guān)系?同步一定阻塞嗎?阻塞一定同步嗎?,同步和異步有什么區(qū)別?

同步與非同步:主要是保證互斥的訪問臨界資源的情況
阻塞與非阻塞:主要是從 CPU 的消耗上來說的

44.int與Integer的區(qū)別,分別什么場合使用

1、Integer是int提供的封裝類,而int是Java的基本數(shù)據(jù)類型
2、Integer默認(rèn)值是null,而int默認(rèn)值是0;
3、聲明為Integer的變量需要實例化,而聲明為int的變量不需要實例化;
4、Integer是對象,用一個引用指向這個對象,而int是基本類型,直接存儲數(shù)值。

int是基本數(shù)據(jù)類型,Integer是包裝類,類似HashMap這樣的結(jié)構(gòu)必須使用包裝類,因為包裝類繼承自O(shè)bject,都需要實現(xiàn)HashCode,所以可以使用在HashMap這類數(shù)據(jù)結(jié)構(gòu)中。

45.RPC的詳細(xì)過程

RPC主要的重點(diǎn)有:
動態(tài)代理,主要是invoke反射原理
序列化,使用Thrift的效率高
通信方式,使用NettyNIO能提高效率
服務(wù)發(fā)現(xiàn),使用zookeeper可以實現(xiàn)

  • 1)服務(wù)消費(fèi)方(client)調(diào)用以本地調(diào)用方式調(diào)用服務(wù);
  • 2)client stub接收到調(diào)用后負(fù)責(zé)將方法、參數(shù)等組裝成能夠進(jìn)行網(wǎng)絡(luò)傳輸?shù)南Ⅲw;
  • 3)client stub找到服務(wù)地址,并將消息發(fā)送到服務(wù)端;
  • 4)server stub收到消息后進(jìn)行解碼;
  • 5)server stub根據(jù)解碼結(jié)果調(diào)用本地的服務(wù);
  • 6)本地服務(wù)執(zhí)行并將結(jié)果返回給server stub;
  • 7)server stub將返回結(jié)果打包成消息并發(fā)送至消費(fèi)方;
  • 8)client stub接收到消息,并進(jìn)行解碼;
  • 9)服務(wù)消費(fèi)方得到最終結(jié)果。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,872評論 11 349
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,912評論 0 11
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,824評論 18 399
  • Java SE 基礎(chǔ): 封裝、繼承、多態(tài) 封裝: 概念:就是把對象的屬性和操作(或服務(wù))結(jié)合為一個獨(dú)立的整體,并盡...
    Jayden_Cao閱讀 2,259評論 0 8
  • 六頂思考帽子: 一、我了解了什么? 1、關(guān)于帽子的定義: 白色思考帽:白色是中立而客觀的。代表著事實和資訊。 紅色...
    做自己的思想家閱讀 4,611評論 0 2

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