1. 程式人生 > >【面試】JAVA程式設計師麵霸之初級知識

【面試】JAVA程式設計師麵霸之初級知識

該系列文章也是來自於一篇CSDN的gitchat,將其中的答案補全,本篇是最簡單的初級知識。

1,面向物件和麵向過程的區別和聯絡。
    網上有個蓋澆飯和蛋炒飯的例子比較好。
    面向過程是蛋炒飯,混在一起,一個一個炒。
    面向物件是蓋澆飯,飯和菜分開,想要換掉飯或者菜都可以,需要啥加啥,需要啥方法,或者啥其他物件就加上,靈活性高,也更抽象。
    面向物件是高度抽象化,面向過程是一種自頂向下的過程。
    
2,物件和類的關係。
    物件是類的一個具體。它是一個實實在在存在的東西。
    物件是有真實的儲存空間的,類沒有,是抽象的。
    
3,Java的記憶體佈局是怎樣的。另外一篇文章有
    JVM執行的時候會自動分配方法區和堆,然後每遇到一個執行緒,為之分配程式計數器、虛擬機器棧、本地方法棧,終止時,後面三個也會釋放
    (1)方法區:常量、靜態變數、類的方法程式碼(變數名,方法名,訪問許可權,返回值等等)
    (2)堆:唯一一個程式設計師可以管理的記憶體區域。幾乎所有的物件例項都在這裡建立,因此該區域經常發生垃圾回收操作
    (3)程式計數器: 當前執行緒執行的位元組碼的位置指示器。
    (4)虛擬機器棧(棧記憶體):儲存區域性變數、基本資料型別變數以及堆記憶體中某個物件的引用變數
    (5)本地方法棧 :為JVM提供使用native 方法的服務
    
4,Java中的工作記憶體之間是怎樣進行通訊的。
    JAVA每一個執行緒都有自己的工作記憶體,執行緒對變數的所有操作(讀取、賦值)都必須在工作記憶體中進行,而不能直接讀寫主記憶體中的變數。
    執行緒間變數值的傳遞均需要在主記憶體來完成。
    主記憶體與工作記憶體之間的具體互動協議,有八種操作:鎖定、解鎖、讀取、載入、使用、賦值、儲存、寫入
    JMM對上述的互動指令有約束。總之,通過主記憶體進行執行緒通訊與互動。

5,堆和棧是什麼關係,主要放什麼東西。
    棧:一些基本型別的變數和物件的引用變數;超過變數的作用域後,被JAVA釋放。
    堆:new建立的物件和陣列;由Java虛擬機器的自動垃圾回收器來管理

6,Java中安全機制是什麼。
    (1)類裝載器,對Java的沙箱起作用:防止惡意程式碼區干涉善意的程式碼,守護了被信任的程式碼的邊界,將程式碼歸於某類(稱為保護域),該類確定了程式碼可以進行哪種操作
    (2)Class檔案檢查器:保證程式的健壯性。包括Class檔案的結構檢查、型別資料的語義檢查、位元組碼驗證、符號引用的驗證。
    (3)內建的安全特性:型別安全的引用轉換;結構化的記憶體訪問(無指標演算法);自動垃圾手機(不必顯式地釋放被分配的記憶體);陣列邊界檢查;空引用檢查。

7,String類的修飾符是什麼,為什麼是它。
    final。為了“效率” 和 “安全性” 的緣故。若 String允許被繼承, 由於它的高度被使用率, 可能會降低程式的效能
    這種類是非常底層的,和作業系統交流頻繁的,呼叫的作業系統本地的API,這就是著名的“本地方法呼叫”。
    那麼如果這種類可以被繼承的話,
    如果我們再把它的方法重寫了,往作業系統內部寫入一段具有惡意攻擊性質的程式碼什麼的,這不就成了核心病毒了麼? 
    
8,重寫和過載的區別和意義。
    (1)都是JAVA多型性的不同表現。重寫體現的是子類與父類之間的多型性表現。過載體現的是一個類中多型性一種表現。
    (2)區別在於前者實現的是編譯時的多型性,而後者實現的是執行時的多型性。
        過載發生在一個類中,同名的方法如果有不同的引數列表(引數型別不同、引數個數不同或者二者都不同)則視為過載;
        重寫發生在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的引數列表,有相容的返回型別,比父類被重寫方法更好訪問,不能比父類被重寫方法宣告更多的異常(里氏代換原則)。
        過載對返回型別沒有特殊的要求,不能根據返回型別進行區分。
    
    (3)重寫多型性起作用,對呼叫被過載過的方法可以大大減少程式碼的輸入量,同一個方法名只要往裡面傳遞不同的引數就可以擁有不同的功能或返回值。
        重寫,使用多型是為了避免在父類裡大量過載引起程式碼臃腫且難於維護
    
9,Final、Finally和Finalize的區別。
    (1)final修飾類,不能被繼承。
        修飾方法,若父類中final方法的訪問許可權為private,將導致子類中不能直接繼承該方法
        因此,此時可以在子類中定義相同方法名的函式,此時不會與重寫final的矛盾,而是在子類中重新地定義了新方法。
        final成員變量表示常量,只能被賦值一次,賦值後其值不再改變。
    (2)finally,只有try執行完畢才會執行,如果還沒執行就異常了不會執行try,更不會執行finally了
        第二種情況,try裡面有System.exit (0),終止JAVA虛擬機器的執行。或者Kill,interrrupted
        易錯點,如果try,catch,finally都有return語句,finally會撤銷之前的return,以他為準。
    (3)Finalize,每個物件都有,被回收的時候呼叫,一般不用自己呼叫,而且容易出問題,不推薦。
    
10,Static程式碼塊、普通程式碼塊和構造程式碼塊之間的呼叫順序,以及一些常用場景。
(1)靜態程式碼塊是隨著類的載入而載入,而構造程式碼塊和構造方法都是隨著物件的建立而載入
(2)構造程式碼塊:直接在類中定義且沒有加static關鍵字的程式碼塊稱為{}構造程式碼塊。
    構造程式碼塊在建立物件時被呼叫,每次建立物件都會被呼叫,並且構造程式碼塊的執行次序優先於類建構函式。
(3)普通程式碼塊就是方法,比如main函式裡面的直接用{}包著的程式碼。
(4)場景:
    構造程式碼塊的呼叫時機:每生成一個物件就會被呼叫一次,而且優先於建構函式被呼叫.
    靜態程式碼塊的呼叫時機:在類載入到記憶體的時候呼叫一次!
    現在基本不用構造程式碼塊了,也不推薦。
    
11,StringBudiler和StringBuffer的區別和聯絡。
    (1)執行緒安全與不安全:string的物件是不可變的,安全。StringBuffer也安全,主要方法都加了synchronized。
    安全不安全導致了速度不同,由慢到快:String<StringBuffer<StringBuilder
    舉例:String s8 = s6+s7;
    string最慢,因為底層使用StringBuilder首先初始化s6,在用append方法合併s7的字串cd,在tostring新物件引用給s8.
    經常要操作字串的情況下:如果字串不改就用final string。如果可以改變,多執行緒使用StringBuffer,其他用StringBuilder
    (2)String s1= "abc";"abc"放在常量池。
    String s3 = new String("abc");"abc"常量池,string物件放在堆中(new String("abc")),物件引用s3放在棧中
    
12,繪製容器繼承關係圖。
(1)LIST:可以按照序號訪問。ArrayList、linkedlist
(2)SET:HashSet、LinkedHashSet、TreeSet
(3)QUEUE:PriorityQueue

    說白了,HashSet就是限制了功能的HashMap,LinkedHashSet也是如此,treeset也是treemap
    資料不重複,底層是依賴hashmap的key值直接替代了新的value值,只不過key值沒變罷了。

13,Collections和Collection的區別和聯絡。
(1)Collection 是一個集合介面(集合類的一個頂級介面)。它提供了對集合物件進行基本操作的通用介面方法。
     Collection介面的意義是為各種具體的集合提供了最大化的統一操作方式,其直接繼承介面有List與Set。
     Collections則是集合類的一個工具類/幫助類,其中提供了一系列靜態方法,用於對集合中元素進行排序、搜尋以及執行緒安全等各種操作。
     比如,排序,混排,反轉,拷貝等等
(2)Collection使用,比如a.add(),remove(),isempty(),size(),contains()
     Collections使用,比如Collections.sort(list);
     
14,ArrayList和Vector的區別和聯絡。
(1)Vector的方法都是同步的(Synchronized),是執行緒安全的,而ArrayList的方法不是,由於執行緒的同步必然要影響效能,因此,ArrayList的效能比Vector好。 
(2)當Vector或ArrayList中的元素超過它的初始大小時,Vector會將它的容量翻倍,而ArrayList只增加50%的大小,這樣,ArrayList就有利於節約記憶體空間。

15,Set和Map有聯絡嗎。
    看起來,set的實現是依賴map的key值的不重複,來達到set不重複的目的。
(1)set分為hashSet和treeSet,前者無序,無重複,後者實現了sortset介面,二叉樹進行排序
    list有arraylist和linkedList,arraylist有個兄弟vector,見上一條。linkedlist鏈路的,增刪改查方便。查詢用arraylist,其他用linkedlist
(2)map是鍵值對.

    兩者關係,就是map種的Keys或者values可以生成set和Collection.
    Map中元素,可以將key序列、value序列單獨抽取出來。
    使用keySet()抽取key序列,將map中的所有keys生成一個Set。
    使用values()抽取value序列,將map中的所有values生成一個Collection。
    
16,HashMap和HashTable的區別和聯絡。
    HashMap和Hashtable,執行緒安全ConcurrentHashMap結合了兩者並且鎖是細粒度的,16個桶,只鎖一個
    一般來說,Hashtable效率低,而且基本不太維護了,已經被棄用
    ConcurrentHashMap結合兩者,多執行緒可以使用,並引入了分段鎖,每一把鎖用於鎖容器其中一部分資料,
    執行緒安全,防止髒資料和死鎖。
    
17,型別擦除是什麼意思。
(1)泛型資訊只存在於程式碼編譯階段,在進入 JVM 之前,與泛型相關的資訊會被擦除掉,專業術語叫做型別擦除。
    Java的泛型機制是在編譯級別實現的。編譯器生成的位元組碼在執行期間並不包含泛型的型別資訊。
    在編譯之後,List<Object>和List<String>將變成List,Object和String型別資訊對於JVM來說是不可見的。
(2)型別擦除可以讓泛型相容JDK1.5版本之前的版本。

18,HashSet和TreeSet的原理。
(1)HashSet的工作原理;計算物件的hashcode後,集合中查詢是否包含雜湊值相同的元素.有的話,挨個equals對比,都是false的話,插入資料
(2)TreeSet需要排序。二叉樹排序,int,string這種基礎型別可以直接排序,但是自定義的需要implement Comparable,重寫compareTo()方法

19,陣列和字串誰有Length方法,誰有Length屬性。
    陣列是length屬性,字串有Length的方法。
    陣列a.length
    str.length()
    
20,能比較清楚地簡述各個集合類的特點及適用場合。摘自https://blog.csdn.net/qq_22118507/article/details/51576319
(1)執行緒安全集合類與非執行緒安全集合類 
    LinkedList、ArrayList、HashSet是非執行緒安全的,Vector是執行緒安全的;
    HashMap是非執行緒安全的,HashTable是執行緒安全的;
    StringBuilder是非執行緒安全的,StringBuffer是執行緒安全的。
    
(2)ArrayList與LinkedList的區別和適用場景
    Arraylist地址連續,記憶體裡連著放的,所以查詢效率較高,插入和刪除效率低
    LinkedList基於連結串列的資料結構,地址是任意的,不需要連續的地址,新增和刪除佔優勢。專門用於操作表頭和表尾元素,可以當作堆疊、佇列和雙向佇列使用。
    
(3)ArrayList與Vector的區別和適用場景
    Vector是多執行緒安全的,有synchronized進行修飾,所以導致效率比ArrayList低很多。
    如果集合中的元素的數目大於目前集合陣列的長度時,在集合中使用資料量比較大的資料,用Vector有一定的優勢。
    因為Vector可以設定增長因子,所以在集合中使用資料量比較大的資料,用Vector有一定的優勢。
    
(4)HashSet與Treeset的適用場景
    HashSet是基於Hash演算法實現的,其效能通常都優於TreeSet。
    為快速查詢而設計的Set,我們通常都應該使用HashSe。
    在我們需要排序的功能時,我們才使用TreeSet。
    
(5)HashMap與TreeMap、HashTable的區別及適用場景
    HashMap是非同步的,效率上比HashTable要高。HashMap允許空鍵值,而HashTable不允許。
    HashMap:適用於Map中插入、刪除和定位元素。 一般不怎麼用HashTable。
    Treemap:適用於按自然順序或自定義順序遍歷鍵(key)。 
    
21,執行緒的幾個狀態。
(1)新建狀態,暫未呼叫start()之前
(2)就緒狀態,呼叫start()之後。建立執行緒執行的系統資源,並排程執行緒執行run()方法。
    當start()方法返回後,執行緒就處於就緒狀態。不一定立即呼叫run()方法,執行緒還必須同其他執行緒競爭CPU時間,只有獲得CPU時間才可以執行執行緒。
    一個時刻只有一個執行緒處於執行狀態。
(3)執行狀態。
    執行緒排程程式從可執行池中選擇一個執行緒作為當前執行緒時執行緒所處的狀態。這也是執行緒進入執行狀態的唯一一種方式。
    當執行緒獲得CPU時間後,它才進入執行狀態,真正開始執行run()方法。
(4)阻塞狀態。
    執行緒仍舊是活的,但是當前沒有條件執行。有機會還可以繼續執行,或者直接變成就緒狀態。
    怎麼進入阻塞呢?sleep、呼叫一個在I/O上被阻塞的操作、試圖得到一個鎖,而該鎖正被其他執行緒持有、等待某個觸發條件
    等於是暫時讓出CPU,這時其他處於就緒狀態的執行緒就可以獲得CPU時間,進入執行狀態。
(5)死亡狀態。
    ①run方法正常退出而自然死亡;
    ②一個未捕獲的異常終止了run方法而使執行緒猝死;
    
    isAlive判斷是否或者,true是執行或阻塞,false是就緒或者死亡。

相關推薦

no