日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java崗 面試考點(diǎn)精講(基礎(chǔ)篇01期)

 蘇心閣 2019-03-07

即將到來(lái)金三銀四人才招聘的高峰期,渴望跳槽的朋友肯定跟我一樣四處找以往的面試題,但又感覺(jué)找的又不完整,在這里我將把我所見(jiàn)到的題目做一總結(jié),并盡力將答案術(shù)語(yǔ)化、標(biāo)準(zhǔn)化。預(yù)祝大家面試順利。

另:如果覺(jué)得本文有用,歡迎點(diǎn)好看或者分享出去!

術(shù)語(yǔ)會(huì)讓你的面試更有說(shuō)服力,讓你感覺(jué)更踏實(shí),建議大家多記背點(diǎn)術(shù)語(yǔ)。

1. 簡(jiǎn)單說(shuō)下什么是跨平臺(tái)

術(shù)語(yǔ):操作系統(tǒng)指令集、屏蔽系統(tǒng)之間的差異

由于各種操作系統(tǒng)所支持的指令集不是完全一致,所以在操作系統(tǒng)之上加個(gè)虛擬機(jī)可以來(lái)提供統(tǒng)一接口,屏蔽系統(tǒng)之間的差異。

2. Java有幾種基本數(shù)據(jù)類型

有八種基本數(shù)據(jù)類型。

數(shù)據(jù)類型字節(jié)默認(rèn)值
byte10
short20
int40
long80
float40.0f
double80.0d
char2'\u0000'
boolean4false

各自占用幾字節(jié)也記一下。

3. 面向?qū)ο筇卣?/h3>

面向?qū)ο蟮木幊陶Z(yǔ)言有封裝、繼承 、抽象、多態(tài)等4個(gè)主要的特征。

  1. 封裝: 把描述一個(gè)對(duì)象的屬性和行為的代碼封裝在一個(gè)模塊中,也就是一個(gè)類中,屬性用變量定義,行為用方法進(jìn)行定義,方法可以直接訪問(wèn)同一個(gè)對(duì)象中的屬性。

  2. 抽象: 把現(xiàn)實(shí)生活中的對(duì)象抽象為類。分為過(guò)程抽象和數(shù)據(jù)抽象

  • 數(shù)據(jù)抽象 -->鳥(niǎo)有翅膀,羽毛等(類的屬性)

  • 過(guò)程抽象 -->鳥(niǎo)會(huì)飛,會(huì)叫(類的方法)

  1. 繼承:子類繼承父類的特征和行為。子類可以有父類的方法,屬性(非private)。子類也可以對(duì)父類進(jìn)行擴(kuò)展,也可以重寫(xiě)父類的方法。缺點(diǎn)就是提高代碼之間的耦合性。

  2. 多態(tài): 多態(tài)是指程序中定義的引用變量所指向的具體類型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定(比如:向上轉(zhuǎn)型,只有運(yùn)行才能確定其對(duì)象屬性)。方法覆蓋和重載體現(xiàn)了多態(tài)性。

4. 為什么要有包裝類型

術(shù)語(yǔ):讓基本類型也具有對(duì)象的特征

基本類型包裝器類型
booleanBoolean
charCharacter
intInteger
byteByte
shortShort
longLong
floatFloat
doubleDouble

為了讓基本類型也具有對(duì)象的特征,就出現(xiàn)了包裝類型(如我們?cè)谑褂眉项愋虲ollection時(shí)就一定要使用包裝類型而非基本類型)因?yàn)槿萜鞫际茄bobject的,這是就需要這些基本類型的包裝器類了。

自動(dòng)裝箱:new Integer(6);,底層調(diào)用:Integer.valueOf(6)

自動(dòng)拆箱: int i = new Integer(6);,底層調(diào)用i.intValue();方法實(shí)現(xiàn)。

Integer i  = 6;
Integer j = 6;
System.out.println(i==j);

答案在下面這段代碼中找:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}
二者的區(qū)別:
  1. 聲明方式不同:基本類型不使用new關(guān)鍵字,而包裝類型需要使用new關(guān)鍵字來(lái)在堆中分配存儲(chǔ)空間;

  2. 存儲(chǔ)方式及位置不同:基本類型是直接將變量值存儲(chǔ)在棧中,而包裝類型是將對(duì)象放在堆中,然后通過(guò)引用來(lái)使用;

  3. 初始值不同:基本類型的初始值如int為0,boolean為false,而包裝類型的初始值為null;

  4. 使用方式不同:基本類型直接賦值直接使用就好,而包裝類型在集合如Collection、Map時(shí)會(huì)使用到。

5. ==和equals區(qū)別

  • ==較的是兩個(gè)引用在內(nèi)存中指向的是不是同一對(duì)象(即同一內(nèi)存空間),也就是說(shuō)在內(nèi)存空間中的存儲(chǔ)位置是否一致。如果兩個(gè)對(duì)象的引用相同時(shí)(指向同一對(duì)象時(shí)),“==”操作符返回true,否則返回flase。

  • equals用來(lái)比較某些特征是否一樣。我們平時(shí)用的String類等的equals方法都是重寫(xiě)后的,實(shí)現(xiàn)比較兩個(gè)對(duì)象的內(nèi)容是否相等。

我們來(lái)看看String重寫(xiě)的equals方法:

它不止判斷了內(nèi)存地址,還增加了字符串是否相同的比較。

public boolean equals(Object anObject) {
    //判斷內(nèi)存地址是否相同
    if (this == anObject) {
        return true;
    }
    // 判斷參數(shù)類型是否是String類型
    if (anObject instanceof String) {
        // 強(qiáng)轉(zhuǎn)
        String anotherString = (String)anObject;
        int n = value.length;
        // 判斷兩個(gè)字符串長(zhǎng)度是否相等
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            // 一一比較 字符是否相同
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

6. String、StringBuffer和StringBuilder區(qū)別

java中String、StringBuffer、StringBuilder是編程中經(jīng)常使用的字符串類,他們之間的區(qū)別也是經(jīng)常在面試中會(huì)問(wèn)到的問(wèn)題?,F(xiàn)在總結(jié)一下,看看他們的不同與相同。

1. 數(shù)據(jù)可變和不可變
  1. String底層使用一個(gè)不可變的字符數(shù)組private final char value[];所以它內(nèi)容不可變。

  2. StringBufferStringBuilder都繼承了AbstractStringBuilder底層使用的是可變字符數(shù)組:char[] value;

2. 線程安全
  • StringBuilder是線程不安全的,效率較高;而StringBuffer是線程安全的,效率較低。

通過(guò)他們的append()方法來(lái)看,StringBuffer是有同步鎖,而StringBuilder沒(méi)有:

@Override
public synchronized StringBuffer append(Object obj) {
    toStringCache = null;
    super.append(String.valueOf(obj));
    return this;
}
@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}
3. 相同點(diǎn)

StringBuilderStringBuffer有公共父類AbstractStringBuilder。

最后,操作可變字符串速度:StringBuilder > StringBuffer > String,這個(gè)答案就顯得不足為奇了。

7. 講一下Java中的集合

  1. Collection下:List系(有序、元素允許重復(fù))和Set系(無(wú)序、元素不重復(fù))

set根據(jù)equals和hashcode判斷,一個(gè)對(duì)象要存儲(chǔ)在Set中,必須重寫(xiě)equals和hashCode方法

  1. Map下:HashMap線程不同步;TreeMap線程同步

  2. Collection系列和Map系列:Map是對(duì)Collection的補(bǔ)充,兩個(gè)沒(méi)什么關(guān)系

8. ArrayList和LinkedList區(qū)別?

之前專門(mén)有寫(xiě)過(guò)ArrayList和LinkedList源碼的文章。

  1. ArrayList是實(shí)現(xiàn)了基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)。

  2. 對(duì)于隨機(jī)訪問(wèn)get和set,ArrayList覺(jué)得優(yōu)于LinkedList,因?yàn)長(zhǎng)inkedList要移動(dòng)指針。

  3. 對(duì)于新增和刪除操作add和remove,LinedList比較占優(yōu)勢(shì),因?yàn)锳rrayList要移動(dòng)數(shù)據(jù)。

面試必會(huì)之ArrayList源碼分析

面試必會(huì)之LinkedList源碼分析

9. ConcurrentModificationException異常出現(xiàn)的原因

public class Test {
    public static void main(String[] args)  {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(2);
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer==2)
                list.remove(integer);
        }
    }
}

執(zhí)行上段代碼是有問(wèn)題的,會(huì)拋出ConcurrentModificationException異常。

原因:調(diào)用list.remove()方法導(dǎo)致modCountexpectedModCount的值不一致。

final void checkForComodification() {
    if (modCount != expectedModCount)
    throw new ConcurrentModificationException();
}

解決辦法:在迭代器中如果要?jiǎng)h除元素的話,需要調(diào)用Iterator類的remove方法。

public class Test {
    public static void main(String[] args)  {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(2);
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            Integer integer = iterator.next();
            if(integer==2)
                iterator.remove();   //注意這個(gè)地方
        }
    }
}

10. HashMap和HashTable、ConcurrentHashMap區(qū)別?

相同點(diǎn):

  1. HashMap和Hashtable都實(shí)現(xiàn)了Map接口

  2. 都可以存儲(chǔ)key-value數(shù)據(jù)

不同點(diǎn):

  1. HashMap可以把null作為key或value,HashTable不可以

  2. HashMap線程不安全,效率高。HashTable線程安全,效率低。

  3. HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。

什么是fail-fast?
就是最快的時(shí)間能把錯(cuò)誤拋出而不是讓程序執(zhí)行。

10.2 如何保證線程安全又效率高?

Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的擴(kuò)展性更好。

ConcurrentHashMap將整個(gè)Map分為N個(gè)segment(類似HashTable),可以提供相同的線程安全,但是效率提升N倍,默認(rèn)N為16。

10.3 我們能否讓HashMap同步?

HashMap可以通過(guò)下面的語(yǔ)句進(jìn)行同步:
Map m = Collections.synchronizeMap(hashMap);

11. 拷貝文件的工具類使用字節(jié)流還是字符流

答案:字節(jié)流

11.1 什么是字節(jié)流,什么是字符流?

字節(jié)流:傳遞的是字節(jié)(二進(jìn)制),

字符流:傳遞的是字符

11.2 答案

我們并不支持下載的文件有沒(méi)有包含字節(jié)流(圖片、影像、音源),所以考慮到通用性,我們會(huì)用字節(jié)流。

12. 線程創(chuàng)建方式

這個(gè)之前自己做過(guò)總結(jié),也算比較全面。

方法一:繼承Thread類,作為線程對(duì)象存在(繼承Thread對(duì)象)

public class CreatThreadDemo1 extends Thread{
    /**
     * 構(gòu)造方法: 繼承父類方法的Thread(String name);方法
     * @param name
     */
    public CreatThreadDemo1(String name){
        super(name);
    }

    @Override
    public void run() {
        while (!interrupted()){
            System.out.println(getName()+'線程執(zhí)行了...');
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        CreatThreadDemo1 d1 = new CreatThreadDemo1('first');
        CreatThreadDemo1 d2 = new CreatThreadDemo1('second');

        d1.start();
        d2.start();

        d1.interrupt();  //中斷第一個(gè)線程
    }
}

常規(guī)方法,不多做介紹了,interrupted方法,是來(lái)判斷該線程是否被中斷。(終止線程不允許用stop方法,該方法不會(huì)施放占用的資源。所以我們?cè)谠O(shè)計(jì)程序的時(shí)候,要按照中斷線程的思維去設(shè)計(jì),就像上面的代碼一樣)。

讓線程等待的方法
  • Thread.sleep(200); //線程休息2ms

  • Object.wait(); //讓線程進(jìn)入等待,直到調(diào)用Object的notify或者notifyAll時(shí),線程停止休眠

方法二:實(shí)現(xiàn)runnable接口,作為線程任務(wù)存在

public class CreatThreadDemo2 implements Runnable {
    @Override
    public void run() {
        while (true){
            System.out.println('線程執(zhí)行了...');
        }
    }

    public static void main(String[] args) {
        //將線程任務(wù)傳給線程對(duì)象
        Thread thread = new Thread(new CreatThreadDemo2());
        //啟動(dòng)線程
        thread.start();
    }
}

Runnable 只是來(lái)修飾線程所執(zhí)行的任務(wù),它不是一個(gè)線程對(duì)象。想要啟動(dòng)Runnable對(duì)象,必須將它放到一個(gè)線程對(duì)象里。

方法三:匿名內(nèi)部類創(chuàng)建線程對(duì)象

public class CreatThreadDemo3 extends Thread{
    public static void main(String[] args) {
        //創(chuàng)建無(wú)參線程對(duì)象
        new Thread(){
            @Override
            public void run() {
                System.out.println('線程執(zhí)行了...');
            }
        }.start();
       //創(chuàng)建帶線程任務(wù)的線程對(duì)象
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println('線程執(zhí)行了...');
            }
        }).start();
        //創(chuàng)建帶線程任務(wù)并且重寫(xiě)run方法的線程對(duì)象
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println('runnable run 線程執(zhí)行了...');
            }
        }){
            @Override
            public void run() {
                System.out.println('override run 線程執(zhí)行了...');
            }
        }.start();
    }

}

創(chuàng)建帶線程任務(wù)并且重寫(xiě)run方法的線程對(duì)象中,為什么只運(yùn)行了Thread的run方法。我們看看Thread類的源碼,


,我們可以看到Thread實(shí)現(xiàn)了Runnable接口,而Runnable接口里有一個(gè)run方法。
所以,我們最終調(diào)用的重寫(xiě)的方法應(yīng)該是Thread類的run方法。而不是Runnable接口的run方法。

方法四:創(chuàng)建帶返回值的線程

public class CreatThreadDemo4 implements Callable {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CreatThreadDemo4 demo4 = new CreatThreadDemo4();

        FutureTask<Integer> task = new FutureTask<Integer>(demo4); //FutureTask最終實(shí)現(xiàn)的是runnable接口

        Thread thread = new Thread(task);

        thread.start();

        System.out.println('我可以在這里做點(diǎn)別的業(yè)務(wù)邏輯...因?yàn)镕utureTask是提前完成任務(wù)');
        //拿出線程執(zhí)行的返回值
        Integer result = task.get();
        System.out.println('線程中運(yùn)算的結(jié)果為:'+result);
    }

    //重寫(xiě)Callable接口的call方法
    @Override
    public Object call() throws Exception {
        int result = 1;
        System.out.println('業(yè)務(wù)邏輯計(jì)算中...');
        Thread.sleep(3000);
        return result;
    }
}

Callable接口介紹:

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

返回指定泛型的call方法。然后調(diào)用FutureTask對(duì)象的get方法得道call方法的返回值。

方法五:定時(shí)器Timer

public class CreatThreadDemo5 {

    public static void main(String[] args) {
        Timer timer = new Timer();

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println('定時(shí)器線程執(zhí)行了...');
            }
        },0,1000);   //延遲0,周期1s

    }
}

方法六:線程池創(chuàng)建線程

public class CreatThreadDemo6 {
    public static void main(String[] args) {
        //創(chuàng)建一個(gè)具有10個(gè)線程的線程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);
        long threadpoolUseTime = System.currentTimeMillis();
        for (int i = 0;i<10;i++){
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+'線程執(zhí)行了...');
                }
            });
        }
        long threadpoolUseTime1 = System.currentTimeMillis();
        System.out.println('多線程用時(shí)'+(threadpoolUseTime1-threadpoolUseTime));
        //銷毀線程池
        threadPool.shutdown();
        threadpoolUseTime = System.currentTimeMillis();
    }

}

方法七:利用java8新特性 stream 實(shí)現(xiàn)并發(fā)

lambda表達(dá)式不懂的,可以看看我的java8新特性文章:

java8-lambda:

https://www.jianshu.com/p/3a08dc78a05f

java8-stream:

https://www.jianshu.com/p/ea16d6712a00

public class CreatThreadDemo7 {
    public static void main(String[] args) {
        List<Integer> values = Arrays.asList(10,20,30,40);
        //parallel 平行的,并行的
        int result = values.parallelStream().mapToInt(p -> p*2).sum();
        System.out.println(result);
        //怎么證明它是并發(fā)處理呢
        values.parallelStream().forEach(p-> System.out.println(p));
    }
}

輸出:

200
40
10
20
30

怎么證明它是并發(fā)處理呢,他們并不是按照順序輸出的 。

文集介紹

該專題分為Java基礎(chǔ)、計(jì)算機(jī)網(wǎng)絡(luò)、操作系統(tǒng)、數(shù)據(jù)結(jié)構(gòu)、算法精讀、數(shù)據(jù)庫(kù)面試題、框架面試題、服務(wù)高可用、分布式事務(wù)、分布式鎖、消息隊(duì)列等部分,盡量將全網(wǎng)的面試題一網(wǎng)打盡,方便大家手機(jī)閱讀和收藏。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多