<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試中會(huì)遇到的 15 個(gè) Java 冷知識(shí),你懂多少?

          共 6512字,需瀏覽 14分鐘

           ·

          2021-02-26 11:47

          往期熱門文章:

          1、一個(gè)比 Spring Boot 快 44 倍的 Java 框架

          2、面試官:如何保障消息100%投遞成功、消息冪等性?

          3、太牛逼了!項(xiàng)目中用了Disruptor之后,性能提升了2.5倍

          4、最常用的分布式 ID 解決方案,都在這里了

          5、這 7 個(gè) Spring Boot 項(xiàng)目夠經(jīng)典!


          來源:sanesee.com/article/15-forgettable-java-question

          通常,在面試中,會(huì)遇到面試官提一些比較“偏冷”的基礎(chǔ)知識(shí),比如基本數(shù)據(jù)類型所占用的字節(jié)數(shù),或者Unicode和UTF-8的區(qū)別之類的問題,這時(shí)很多應(yīng)聘者會(huì)答錯(cuò)。還有在平常編碼的過程中,很多時(shí)候會(huì)用到除法計(jì)算,比如對(duì)一個(gè)長(zhǎng)度為100萬(wàn)的List中的所有元素進(jìn)行除16的操作,那么CPU對(duì)element<<4操作的運(yùn)算會(huì)快于element/16的操作……
          因此,本文對(duì)一些容易被遺忘的基礎(chǔ)知識(shí)進(jìn)行歸納,希望可以幫助廣大程序員輕松應(yīng)對(duì)面試官的基礎(chǔ)技術(shù)問題,以及提升編碼效率。本文適合有一定Java基礎(chǔ)的技術(shù)人員閱讀,部分內(nèi)容對(duì)初學(xué)者來說可能會(huì)比較吃力。
          1.Java中的基本數(shù)據(jù)類型以及所占內(nèi)存大小
          (1)整形
          byte   1字節(jié)
          short   2字節(jié)
          int   4字節(jié)
          long   8字節(jié)
          (2)浮點(diǎn)型
          float   4字節(jié)
          double   8字節(jié)
          (3)字符類型
          char   2字節(jié)(Unicode-16)
          (4)布爾類型
          布爾類型boolean比較特殊,盡管Java虛擬機(jī)定義了boolean類型,但虛擬機(jī)對(duì)boolean類型的支持是有限的,沒有為boolean值單獨(dú)設(shè)計(jì)JVM指令。操作布爾值的表達(dá)式在編譯之后,它使用的是JVM的int數(shù)據(jù)類型,也就是占用4個(gè)字節(jié)。
          JVM也不會(huì)直接支持boolean數(shù)組,boolean數(shù)組在編譯之后,它的元素采用byte數(shù)據(jù)類型,用0表示false,1表示true,也就是boolean數(shù)組的元素只占用一個(gè)字節(jié)。
          2.UTF-8與Unicode的關(guān)系
          Unicode是一個(gè)統(tǒng)一的編碼標(biāo)準(zhǔn),將現(xiàn)有的所有字符進(jìn)行唯一編碼。在第一個(gè)Unicode版本中,使用兩個(gè)字節(jié)(16位)來表示一個(gè)字符,注意這里的字節(jié)并非指的是計(jì)算機(jī)內(nèi)存中的存儲(chǔ)單元,而是一個(gè)數(shù)學(xué)長(zhǎng)度單位而已。然而,一個(gè)Unicode字符在內(nèi)存中存儲(chǔ)所占用的長(zhǎng)度,就需要一個(gè)具體的編碼規(guī)則來實(shí)現(xiàn),比如UTF-8。因此,Unicode只是一個(gè)編碼標(biāo)準(zhǔn),而UTF-8是對(duì)這個(gè)標(biāo)準(zhǔn)的一個(gè)實(shí)現(xiàn),UTF-8規(guī)定了一個(gè)Unicode字符在內(nèi)存中占用的空間(英文和中文所占空間是不同的,有興趣的讀者可以查閱相關(guān)資料)。
          代碼點(diǎn)指的是可以用于對(duì)字符集進(jìn)行編碼的那些數(shù)字,比如在16位的Unicode編碼字符集中,字符“A”的編碼是U+0041,那么0041就是一個(gè)代碼點(diǎn)。
          代碼單元指的是字符所占空間的單元。例如在UTF-32中,一個(gè)代碼單元為32位,一個(gè)字符占用32位,恰好使用一個(gè)代碼單元,這種方式會(huì)耗費(fèi)大量?jī)?nèi)存。在UTF-16中,一個(gè)代碼單元為16位,值 U+0000 至 U+FFFF 編碼對(duì)應(yīng)一個(gè)字符,每個(gè)字符占用一個(gè)代碼單元,但是,對(duì)于超過這個(gè)范圍的那些增補(bǔ)字符的編碼,需要兩個(gè)這樣的單元(即32位)。而在UTF-8中,一個(gè)代碼單元為8位,UTF-8 使用一至四個(gè)字節(jié)的序列對(duì)編碼 Unicode 代碼點(diǎn)進(jìn)行編碼,原理同UTF-32和UTF-16。

          3.String字符串常量
          在Java語(yǔ)言中,一個(gè)String字符串常量對(duì)應(yīng)著一個(gè)String對(duì)象,并且是不可更改和繼承的(因?yàn)镾tring類被final關(guān)鍵字修飾)。Java語(yǔ)言這樣設(shè)計(jì),主要是為了使得字符串常量(注意是字符串常量,字符串變量不符合這里所講的規(guī)則)可以共享,因?yàn)镴VM將字符串常量放入公共的存儲(chǔ)池中,不同的變量可以引用相同的字符串常量。

          以上代碼運(yùn)行結(jié)果為:true。這就說明a和b引用的是同一String對(duì)象。
          4.基本數(shù)據(jù)類型轉(zhuǎn)換規(guī)則
          在雙操作數(shù)運(yùn)算中,會(huì)根據(jù)操作數(shù)類型將低級(jí)的一個(gè)類型轉(zhuǎn)換為高級(jí)的一個(gè)類型。
          1)只要兩個(gè)操作數(shù)中有一個(gè)是double類型的,另一個(gè)將會(huì)被轉(zhuǎn)換成double類型,并且結(jié)果也是double類型;
          2)只要兩個(gè)操作數(shù)中有一個(gè)是float類型的,另一個(gè)將會(huì)被轉(zhuǎn)換成float類型,并且結(jié)果也是float類型;
          3)只要兩個(gè)操作數(shù)中有一個(gè)是long類型的,另一個(gè)將會(huì)被轉(zhuǎn)換成long類型,并且結(jié)果也是long類型;
          4)兩個(gè)操作數(shù)(包括byte、short、int、char)都將會(huì)被轉(zhuǎn)換成int類型,并且結(jié)果也是int類型。
          5.按值調(diào)用與按引用調(diào)用
          按值調(diào)用表示方法接收的是調(diào)用者提供的參數(shù)值。按引用調(diào)用表示方法接收的是調(diào)用者提供的是調(diào)用者提供的參數(shù)地址。Java程序設(shè)計(jì)語(yǔ)言總是按值調(diào)用的。下面是反例代碼:

          以上代碼啟動(dòng)交換a和b所引用的對(duì)象,但實(shí)際編譯執(zhí)行會(huì)發(fā)現(xiàn)沒有成功交換。這也就證明Java不是按引用調(diào)用的,a和b僅代表兩個(gè)Person對(duì)象的值,而不是代表兩個(gè)對(duì)象的引用,在參數(shù)傳遞上與int等基本類型的值沒有區(qū)別。
          6.對(duì)象初始化
          在使用構(gòu)造器初始化對(duì)象時(shí),首先運(yùn)行初始化塊,然后運(yùn)行構(gòu)造器的主題部分。調(diào)用構(gòu)造器的具體初始化步驟如下:
          1)類的所有數(shù)據(jù)域被初始化為默認(rèn)值(0、false或null)。
          2)按照在類中聲明的次序,依次執(zhí)行所有初始化語(yǔ)句和初始化塊。
          3)如果構(gòu)造器第一行調(diào)用了第二個(gè)構(gòu)造器,則執(zhí)行第二個(gè)構(gòu)造器。
          4)執(zhí)行構(gòu)造器的主體。
          類第一次加載的時(shí)候,將會(huì)進(jìn)行靜態(tài)域的初始化。所有的靜態(tài)初始化語(yǔ)句以及靜態(tài)初始化塊都將依照定義的順序進(jìn)行。
          使用super調(diào)用構(gòu)造器的語(yǔ)句必須是子類構(gòu)造器的第一條語(yǔ)句。
          7.數(shù)組
          在Java中,子類數(shù)組的引用可以轉(zhuǎn)換成父類數(shù)組的引用,而不需要采用強(qiáng)制類型轉(zhuǎn)換。
          8.繼承
          在覆蓋一個(gè)方法的時(shí)候,子類方法不能低于父類方法的可見性。即父類方法是protected的,子類覆蓋的方法只能是protected或public的。
          9.final修飾的類
          如果將一個(gè)類聲明為final的,只有其中的方法自動(dòng)成為final,而不包括域。
          10.equals方法
          Object類的equals方法用于檢測(cè)一個(gè)對(duì)象與另一個(gè)對(duì)象是否相等,即判斷兩個(gè)變量的引用是否相同。如果重新定義了equals方法,就必須重新定義hashCode方法,因?yàn)橄蛏⒘斜碇刑砑訑?shù)據(jù)時(shí)會(huì)根據(jù)hashCode和equals方法來確定插入位置。如果x.equals(y)返回true,那么x.hashCode()與y.hashCode()的返回值必須相同。
          由于枚舉值具有固定的實(shí)例,因此直接使用“==”就可以判定兩個(gè)枚舉值是否相同,而不需使用equals方法。
          11.Class類
          JVM會(huì)為每個(gè)加載的類生成一個(gè)Class類型的實(shí)例,用于跟蹤對(duì)象所屬的類,獲取Class類型實(shí)例的方法如下:
          1)Object類中的getClass()方法將會(huì)返回一個(gè)Class類型的實(shí)例。
          2)Class.forName(className)可以返回className指定類的Class實(shí)例。
          3)MyClass.class可以返回MyClass類的Class實(shí)例。
          12.局部類
          在方法中聲明的類稱為局部類(也屬于內(nèi)部類),局部類不僅能夠訪問包含它們的外部類,還可以訪問局部變量。不過,可以被訪問的局部變量必須被聲明為final。
          13.代理
          利用代理可以在運(yùn)行時(shí)創(chuàng)建一個(gè)實(shí)現(xiàn)了一組給定接口的新類,這種功能只有在編譯時(shí)無(wú)法確定需要實(shí)現(xiàn)哪個(gè)接口時(shí)才有必要使用。我們需要提供一個(gè)實(shí)現(xiàn)InvocationHandler接口的類來處理調(diào)用過程:

          14.限定泛型變量
          關(guān)于類型變量限定的問題,一直以來是不少程序員感覺困惑的地方,本條就這個(gè)問題簡(jiǎn)要討論一下。Java泛型一面有以下兩種類型限定的泛型:

          限定類型可以有多個(gè),使用“&”分隔。比如:

          <T super Comparable & Serializable>

          無(wú)論何時(shí)定義一個(gè)泛型類型,都自動(dòng)提供了一個(gè)相應(yīng)的原始類型。程序運(yùn)行時(shí),擦除類型變量,并替換為第一個(gè)限定類型(比如被替換為Comparable),無(wú)限定的變量使用Object。

          SaneseeDemo

          不能用類型參數(shù)代替基本類型。因此沒有SaneseeDemo,只有SaneseeDemo

          不能實(shí)例化參數(shù)化類型的數(shù)組,例如:


          這是因?yàn)閍rray被擦除類型之后,它的類型為SaneseeDemo [],元素類型為SaneseeDemo,則相應(yīng)的原始類型為Object[],那么就可以往里面添加任何類型的元素,也就會(huì)出現(xiàn)類型錯(cuò)誤。

          如果需要使用參數(shù)化類型對(duì)象,只有一種安全而有效的方法:使用ArrayList。

          同時(shí),也不能在靜態(tài)域或方法中引用類型變量,無(wú)法通過編譯,比如:


          因?yàn)轭愋筒脸螅妥優(yōu)樵碱愋蚈bject了。如果它可以正常執(zhí)行,那么任何類型的T最終都會(huì)變?yōu)镺bject,那么不管傳入什么類型的T,最終只能獲取相同的單例,這與我們想要的功能是不一致的。

          不能拋出或捕獲泛型類型的異常。

          Sanesee不是Sanesee的子類,因此不能將Sanesee類型的值賦給Sanesee類型的值。

          不能向<? extends Employee >類型的變量調(diào)用set方法的。假設(shè)它可以執(zhí)行,因?yàn)槌绦驘o(wú)法知道這個(gè)變量的具體類型,它的類型可能是Manager,也可能是Executive,那么就會(huì)出現(xiàn)類型轉(zhuǎn)換錯(cuò)誤。只能向這個(gè)變量調(diào)用get方法,因?yàn)槌绦虬勋@得的值自動(dòng)轉(zhuǎn)換為Employee類型,子類型可以自動(dòng)轉(zhuǎn)換為父類型。

          不能向<? super Employee>類型的變量調(diào)用get方法,因?yàn)槌绦驘o(wú)法知道返回的具體類型,它的類型可能是Person,也有可能是Object。只能調(diào)用set方法,因?yàn)椴还苁莻魅隕mployee還是其子類,都可以成功執(zhí)行。

          總之,帶有super限定的通配符可以向泛型對(duì)象寫入,帶有extends限定的通配符可以從泛型對(duì)象讀取。而Sanesee和Sanesee類型的不同點(diǎn)在于,Sanesee類型擦除以后就是Object了,所以根本無(wú)法使用Object類型的對(duì)象去調(diào)用它,只有將它放在靜態(tài)方法中執(zhí)行一些簡(jiǎn)單的操作。

          15.多線程

          當(dāng)對(duì)一個(gè)線程調(diào)用interupt方法時(shí),線程的中斷狀態(tài)將被置位。每個(gè)線程都具有一個(gè)boolean類型的中斷標(biāo)志,通過它來判斷線程是否被中斷:

          Thread.currentThread().isInterupted()

          線程的run方法不能拋出任何受檢異常,而受檢異常會(huì)導(dǎo)致程序終止。然而,不需要使用catch語(yǔ)句來處理可以被傳播的異常。相反,就在線程死亡之前,異常被傳遞到一個(gè)用于未捕獲異常的處理器。可以使用setUncaughtExceptionHandler為任何線程安裝一個(gè)處理器。

          可以調(diào)用ReentrantLock的lock和unlock方法獲取鎖或解除鎖,也可以調(diào)用條件對(duì)象Condition(由ReentrantLock的newCondition方法獲取)的await和singal實(shí)現(xiàn)等待或通知功能。兩種方式的不同點(diǎn)在于,lock獲取到的鎖,會(huì)等到程序執(zhí)行結(jié)束調(diào)用unlock時(shí)才會(huì)釋放,哪怕正在執(zhí)行耗時(shí)比較長(zhǎng)的任務(wù),或者處于等待狀態(tài)。而Condition在需要等待的地方調(diào)用await方法,進(jìn)入等待集,當(dāng)鎖可用時(shí),該線程繼續(xù)保持阻塞狀態(tài),直到另一個(gè)線程調(diào)用同一條件上的singalAll方法為止(singal方法可以隨機(jī)解除一個(gè)線程的阻塞狀態(tài))。然而,最好不使用Lock/Condition或synchronized關(guān)鍵字,可以使用java.util.concurrent包中的任何一種機(jī)制,它會(huì)為你處理所有的加鎖。如果一定得使用關(guān)鍵字,優(yōu)先使用synchronized,這樣可以減少代碼的數(shù)量,其次才是Lock/Condition。

          ThreadLocal類型可以使得每個(gè)線程擁有自己的獨(dú)立的變量。volatile類型為實(shí)例域的訪問提供了一種免鎖機(jī)制,可以使得線程每次都可以訪問到最新的值(volatile變量不能保證原子性)。

          ReentrantReadWriteLock類適合讀數(shù)據(jù)多而寫數(shù)據(jù)少的情形:

          ReentrantReadWriteLock.readLock();//多個(gè)線程共享,排斥寫

          ReentrantReadWriteLock.writeLock();//單個(gè)線程使用,排斥讀寫

          官方建議放棄使用stop和suspend方法,是因?yàn)閟top強(qiáng)制終止一個(gè)線程是極不安全的操作,而suspend本身容易導(dǎo)致死鎖。

          在阻塞隊(duì)列中,生產(chǎn)者向隊(duì)列中插入元素,消費(fèi)者向隊(duì)列獲取元素。當(dāng)隊(duì)列為空時(shí),消費(fèi)者線程會(huì)被阻塞;當(dāng)隊(duì)列慢時(shí),生產(chǎn)者線程將被阻塞。LinkedBlockingQueue可以不限容量,而ArrayBlockingQueue需要指定容量。PriorityBlockingQueue是一個(gè)帶有優(yōu)先級(jí)的隊(duì)列,DelayQueue需要在指定延遲慢之后才能移除元素。LinkedTransferQueue的transfer(item)方法允許生產(chǎn)者線程等待,直到消費(fèi)者準(zhǔn)備就緒并移除這個(gè)item元素。

          java.util.concurrent包提供了Map、集合等的并發(fā)實(shí)現(xiàn),ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet和ConcurrentLinkedQueue,允許并發(fā)訪問數(shù)據(jù)結(jié)構(gòu)。

          任何集合類型可以通過使用同步包裝器變成線程安全的(當(dāng)然最好使用java.util.concurrent包中定義的集合,因?yàn)樗鼈兘?jīng)過了精心的設(shè)計(jì)):

          Listlist = Collections.synchronizedList(new ArrayList);

          Map<K, V> map = Collections.synchronizedMap(new HashMap<K, V>());

          Runnable封裝了一個(gè)異步運(yùn)行的任務(wù),可以看做沒有參數(shù)和返回值的異步方法。Callable與Runnable類似,但它有返回值。

          Executors是一個(gè)線程執(zhí)行器,用于管理線程的創(chuàng)建和執(zhí)行,使用它可以創(chuàng)

          建多種線程池,常見線程池如下:

          Executors.newCachedThreadPool:必要時(shí)創(chuàng)建新線程,空閑線程會(huì)保留60秒。

          Executors.newFixedThreadPool:創(chuàng)建固定容量的線程池。

          Executors.newSingleThreadPool:創(chuàng)建只有一個(gè)線程的線程池。

          Executors.newScheduledThreadPool:用于預(yù)定指定的線程池。

          最近熱文閱讀:

          1、一個(gè)比 Spring Boot 快 44 倍的 Java 框架
          2、面試官:如何保障消息100%投遞成功、消息冪等性?
          3、太牛逼了!項(xiàng)目中用了Disruptor之后,性能提升了2.5倍
          4、最常用的分布式 ID 解決方案,都在這里了
          5、這 7 個(gè) Spring Boot 項(xiàng)目夠經(jīng)典!
          6、用 Java 擼了一款 SSH 客戶端
          7、處理 Exception 的幾種實(shí)踐,很優(yōu)雅,被很多團(tuán)隊(duì)采納!
          8、一致性協(xié)議算法-2PC、3PC、Paxos、Raft、ZAB、NWR詳解
          9、這款I(lǐng)DEA插件刷爆了朋友圈,網(wǎng)友:一定是女朋友送的~
          10、@Autowire和@Resource注解使用的正確姿勢(shì),別再用錯(cuò)的了!!

          關(guān)注公眾號(hào),你想要的Java都在這里

          瀏覽 42
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国际精品久久久 | 青娱乐爱爱视频 | 日韩精品在线观看高清 | 台湾高清无码视频在线观看 | 日本xxxx在线 |