java基礎(chǔ)面試題總結(jié)(2)—— JDK基礎(chǔ)

JAVA SE基礎(chǔ)

1.ArrayList、LinkedList、Vector的特性及存儲(chǔ)性能(持續(xù)更新)

  • ArrayList和Vector都繼承了AbstractList,前者線程不安全,后者線程安全
  • ArrayList基于數(shù)組結(jié)構(gòu)實(shí)現(xiàn),查找速度快,插入和刪除速度慢,LinkedList則相反,因?yàn)槠涫腔陔p向鏈表實(shí)現(xiàn)
  • ArrayList通過(guò)實(shí)現(xiàn)AbstractList,能夠隨機(jī)訪問(wèn),而LinkedList實(shí)現(xiàn)的是AbstractSequentialList,僅能順次訪問(wèn)

2.HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap(持續(xù)更新)

  • HashMap線程不安全,Hashtable對(duì)每個(gè)操作都進(jìn)行同步,線程安全;前者可以存在一個(gè)null的key,value可以為null,后者不能為null

3.簡(jiǎn)述JVM內(nèi)存結(jié)構(gòu)中的heap和stack(持續(xù)更新)

  • heap即堆內(nèi)存,存放對(duì)象數(shù)據(jù),自動(dòng)增加容量,存取較慢,線程共享
  • stack即棧內(nèi)存,存放方法的局部變量、基本數(shù)據(jù)類型、對(duì)象引用、方法調(diào)用登,線程獨(dú)占

4.GC是什么? 為什么要有GC?

  • GC是Garbage Collection的縮寫,即垃圾回收
  • 這里所謂的垃圾,指的是那些不再被使用的對(duì)象,JVM的垃圾回收機(jī)制使得開發(fā)人員從無(wú)聊、容易犯錯(cuò)的手動(dòng)釋放內(nèi)存資源的過(guò)程中解放出來(lái)。
  • 開發(fā)人員可以更加專注的進(jìn)行業(yè)務(wù)功能的開發(fā),而資源回收的工作交由更加專業(yè)的垃圾回收機(jī)制自動(dòng)完成

5.關(guān)于String的知識(shí)點(diǎn)

  1. String s = new String("xyz"); 創(chuàng)建了幾個(gè)String Object? :
    創(chuàng)建了2個(gè)String對(duì)象,首先傳入的"xyz"是一個(gè)String對(duì)象,然后new的過(guò)程又創(chuàng)建了一個(gè)String對(duì)象

6.abstract的方法是否可以是static的?是否可以是synchronized的?

  • 不能是static的:抽象方法是不能分配內(nèi)存的,而static的方法在類加載時(shí)就已經(jīng)分配內(nèi)存,所以不能共存
  • 不能是synchronized的:方法同步的時(shí)候需要獲取該方法所屬實(shí)例對(duì)象的同步鎖,但是abstract的方法是沒(méi)有所屬實(shí)例對(duì)象的,所以無(wú)法synchronized

7.lock與Synchronize的區(qū)別?lock的基本使用方法及特性(持續(xù)更新)

  • Lock是一個(gè)接口,需要進(jìn)行同步操作時(shí),可實(shí)例化一個(gè)Lock(ReentrantLock),當(dāng)前線程即占有這個(gè)Lock對(duì)象鎖,而不像Synchronized那樣需要制定持有某個(gè)特定的對(duì)象鎖,這樣能夠避免Synchronized容易出現(xiàn)的死鎖情況
  • 線程無(wú)法自動(dòng)釋放Lock,需要手動(dòng)unlock(通常在finally)中,因此如果不手動(dòng)釋放的話也會(huì)造成死鎖
  • Lock對(duì)象通過(guò).lock()方法讓線程占有鎖,也可以通過(guò)lock.tryLock(long timeout, TimeUnit unit)方法來(lái)指定獲取鎖的時(shí)間,如果超時(shí)則返回false,放棄獲取鎖(也就放棄執(zhí)行某同步方法)
  • Lock實(shí)現(xiàn)同步的方式也是CAS機(jī)制,ReentrantLock中執(zhí)行l(wèi)ock()操作的是內(nèi)部抽象類Sync的實(shí)現(xiàn),ReentrantLock實(shí)例化時(shí)默認(rèn)是采用非公平鎖(NonfairSync)這個(gè)實(shí)現(xiàn):
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

可以看出,首先采用CAS機(jī)制來(lái)修改對(duì)象頭中的鎖標(biāo)志位,CAS機(jī)制有三個(gè)重要參數(shù):內(nèi)存位置(V)、預(yù)期原值(A)和新值(B), 其中0就是期望的標(biāo)志位原值A(chǔ),1就是期望的標(biāo)志位新值B;最終會(huì)調(diào)用一個(gè)native方法compareAndSwapInt()來(lái)使用CPU的CAS機(jī)制進(jìn)行CAS操作,來(lái)不斷嘗試獲取鎖

  • Lock的CAS機(jī)制是一種典型的樂(lè)觀鎖機(jī)制,可以避免線程進(jìn)入阻塞狀態(tài)造成線程上下文切換降低性能;但是鎖競(jìng)爭(zhēng)太激烈的話,反而會(huì)造成性能低下;
  • Lock的Condition對(duì)象用法:使用Condition對(duì)象可以實(shí)現(xiàn)傳統(tǒng)的wait()和notify()的目的,用Condition實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 阻塞棧,用于存放Mantou對(duì)象
 */
public class SyncStack {
    volatile int index = 0;//棧內(nèi)當(dāng)前Mantou數(shù)量,需保證線程可見
    Lock lock = new ReentrantLock();//初始化鎖
    Condition condition = lock.newCondition();//初始化Condition對(duì)象用于線程間通信
    Mantou[] mantous;

    public SyncStack(int size) {
        //初始化棧內(nèi)容器的大小
        mantous = new Mantou[size];
    }

    /**
     * 將Mantou放入棧中,每放一個(gè),index就增加一個(gè),然后將等待池中的線程喚醒
     * 執(zhí)行該方法前若檢測(cè)若index已滿則執(zhí)行await,執(zhí)行push()的線程進(jìn)入Lock的等待池
     * @param mantou
     */
    public void push(Mantou mantou){
        //獲取同步鎖
        lock.lock();
        try{
            while(index == this.mantous.length){
                condition.await();
            }
            this.mantous[index] = mantou;
            index++;
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    /**
     * 將棧頂?shù)腗antou拿出來(lái),每拿一個(gè),index就減少一個(gè),然后將等待池中的線程喚醒
     * 執(zhí)行該方法前若檢測(cè)index為空則執(zhí)行await,執(zhí)行g(shù)et()的線程進(jìn)入Lock等待池
     * @return
     */
    public Mantou get(){
        lock.lock();
        try{
            while(index == 0){
                //設(shè)置等待時(shí)間,一旦超時(shí)就返回false,退出該方法
                if(!condition.await(30, TimeUnit.SECONDS)){
                    return null;
                }
            }
            index--;
            condition.signalAll();
            return this.mantous[index];
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return null;
    }
}
public class Mantou {
    int id;
    String owner;
    public Mantou(int id, String owner){
        this.id = id;
        this.owner = owner;
    }

    @Override
    public String toString() {
        return owner + "的" +String.valueOf(id);
    }
}
/**
 * 生產(chǎn)者線程,持續(xù)調(diào)用push方法向阻塞棧放入Mantou對(duì)象
 */
public class Producer implements Runnable{
    SyncStack syncStack;
    public Producer(SyncStack syncStack) {
        this.syncStack = syncStack;
    }
    @Override
    public void run() {
        //持續(xù)放入8個(gè)Mantou
        for(int i = 0; i<8; i++){
            Mantou mantou = new Mantou(i, Thread.currentThread().getName());
            syncStack.push(mantou);
            System.out.println(Thread.currentThread().getName()+":生產(chǎn)了" + mantou + "號(hào)饅頭!??!");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
/**
 * 消費(fèi)者線程,持續(xù)調(diào)用get方法從阻塞棧取出Mantou對(duì)象
 */
public class Consumer implements Runnable{
    SyncStack syncStack;
    public Consumer(SyncStack syncStack) {
        this.syncStack = syncStack;
    }
    @Override
    public void run() {
        Mantou mantou;
        //一旦獲取Mantou超時(shí),則退出
        while((mantou = syncStack.get())!=null) {
            System.out.println(Thread.currentThread().getName() + ":拿到了" + mantou + "號(hào)饅頭?。。?);
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + ":靠!居然沒(méi)有了!艸!走了!");
    }
}

測(cè)試:

    public static void main(String[] args){
        SyncStack syncStack = new SyncStack(10);
        Consumer consumer = new Consumer(syncStack);
        Producer producer = new Producer(syncStack);
        Thread consumerThread1 = new Thread(consumer);
        Thread consumerThread2 = new Thread(consumer);
        Thread consumerThread3 = new Thread(consumer);
        Thread producerThread1 = new Thread(producer);
        Thread producerThread2 = new Thread(producer);
        consumerThread1.setName("消費(fèi)者1");
        consumerThread2.setName("消費(fèi)者2");
        consumerThread3.setName("消費(fèi)者3");
        producerThread1.setName("生產(chǎn)者甲");
        producerThread2.setName("生產(chǎn)者已");
        producerThread1.start();
        producerThread2.start();
        consumerThread1.start();
        consumerThread2.start();
        consumerThread3.start();

跟傳統(tǒng)的wait和notifyAll方式大同小異

8. 反射中Class.forName()和ClassLoader.loadClass()的區(qū)別

反射中,Class.forName()和ClassLoader的方法loadClass()都可以通過(guò)類名加載類并返回類的Class對(duì)象,但是兩者有一些區(qū)別:

  • Class.forName()實(shí)際調(diào)用的是forName0(className, true, ClassLoader.getClassLoader(caller), caller),這個(gè)過(guò)程默認(rèn)將進(jìn)行類加載->鏈接->初始化這一系列過(guò)程
  • ClassLoader的方法loadClass()實(shí)際調(diào)用的是ClassLoader.loadClass(className,false)這個(gè)方法,第二個(gè)參數(shù)表示不進(jìn)行鏈接及初始化,僅僅進(jìn)行類加載
  • 所有如果加載某個(gè)類需要進(jìn)行鏈接及初始化操作,就需要調(diào)用Class.forName()這個(gè)方法來(lái)獲取Class對(duì)象
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,904評(píng)論 0 11
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,740評(píng)論 18 399
  • 如果我能夠如此幸運(yùn),希望你能早點(diǎn)來(lái)到我身邊陪伴我每一天。 如果你能夠早點(diǎn)遇見我,希望我是最好的我,你也是最好的你。...
    O習(xí)慣遠(yuǎn)距離閱讀 275評(píng)論 0 1
  • 拋(打油詩(shī)) 誰(shuí)家女嬌娃, 高樓拋絲襪。 以為你是誰(shuí), 天女來(lái)散花?
    老爸的雜拌兒糖閱讀 1,025評(píng)論 26 50
  • 清晨,我推開四葉窗, 絲縷陽(yáng)光灑滿了房間的角落, 陽(yáng)臺(tái)上的植物破土冒尖, 麻雀慵懶地梳著行頭, 清風(fēng)拂面,我笑了。...
    刺魚兒閱讀 547評(píng)論 0 3

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