1. 程式人生 > >Java後臺開發常見面試題

Java後臺開發常見面試題

實現接口 isa 異常 hashtable 唯一索引 完成 queue 是不是 index

  • 八種基本數據類型的大小,以及他們的封裝類

        整數型:        byte    1個字節    -128~127                    封裝類:Byte
            short   2個字節        -32768~32767                        Short
            Int     4個字節        -2147483648~2147483647              Integer
            long    8個字節        -2的63方~2的63次方-1             Long
    
        浮點型:        float   4個字節        單精度                             Float
                        Double  8個字節        雙精度                                 Double
    
        布爾類型:   boolean 4個字節        true或false                          Boolean
    
        字符類型:   char        2個字節                                        Character
  • 引用數據類型:
    分為3種,類、接口和數組

  • Switch能否用String做參數

            在jdk7以前,switch只支持byte、int、short、char或者對應的包裝類和枚舉。
  • equals和==的區別

            a)  對象類型不同 equals是超類Object的方法,而==是操作符
    
            b)  比較類型不同 equals用來檢測兩個對象是否相同,即兩個對象的內容是否相等,==比較引用數據類型和基本數據類型時具有不同的功能。==比較的是變量(棧)內存中存放的對象的內存地址,用來判斷兩個對象的地址是否相同,即是否指向同一對象,比較的是真正意義上的指針操作,而equals用來比較的是兩個對象的內容是否相同,適用於所有對象。
    
            c)  註意:如果沒有對該對象進行覆蓋的話,調用的仍然是超類Object的方法,而Object中的equals方法返回的是==的判斷。
  • 自動拆裝箱和常量池

            a)  Java自動將原始數據類型值轉換成對應的對象,比如將int類型的變量轉換成Integer類型,自動裝箱時調用valueOf將原始數據類型轉換成對應的對象。
    
            b)  反之,將Integer對象裝換成int類型值,這個過程叫拆箱,自動拆箱通過調用類似intValue、doubleValue這類的方法將對象轉換成對應的原始數據類型。
    
            c)  Java中的常量池,實際上分為兩種形態:靜態常量池和運行時常量池。
                i.  靜態常量池:即.*class文件中的常量池,class文件中的常量池不僅僅包含字符串,還包含類、方法的信息,占用class文件絕大部分空間。
                ii. 而運行時常量池:則是jvm虛擬機在完成類裝載過程後,將class文件中的常量池載入到內存中,並保存在方法區中,我們常說的常量池就是指方法區中的運行時常量池。
  • Object中有哪些公用方法?

        a)  Clone:實現對象的淺復制,只有實現了cloneable接口才可以調用此方法,否則會拋出CloneNotSupportedException異常。
    
        b)  Equals:在Object中和==是一樣的,子類一般需要重寫此方法。
    
        c)  Hashcode:該方法用於哈希查找,重寫了equals方法一般都要重寫hashcode方法,這個方法在一些具有哈希功能的collection中用到。
    
        d)  getClass:獲得運行時的類型。
    
        e)  wait:是當前線程等待該對象的鎖,當前線程必須是該對象的擁有者,也就是說具有該對象的鎖!
    
        f)  Notify:喚醒在對象上等待的某個線程。
    
        g)  notifyAll:喚醒該對象上等待的所有線程。
    
        h)  toString:轉換成字符串,一般子類都要重寫此方法,否則打印句柄。
  • Java的四種引用,強弱軟虛。

        a)  強引用:最常見,把一個對象賦給引用數據類型則為強引用。如果內存中不足,java虛擬機將會跑出OutOfMemoryError錯誤,從而將程序異常停止強引用的對象是不可以gc回收的,不可以隨意回收具有強引用的對象來解決內存不足的問題。在java中,強引用是一種默認的狀態,除非Java虛擬機停止工作。
    
        b)  軟引用:如果一個對象具有軟引用,內存空間足夠,垃圾回收就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序繼續使用。軟引用用來實現內存敏感的高速緩存,比如網頁緩存或圖片緩存,使用軟引用能防止內存泄露,增強程序的健壯性。
    
        c)  弱引用:用來描述非必需對象的,當jvm進行垃圾回收的時候,無論內存是否充足,都會回收被弱引用關聯的對象。
    
        d)  虛引用:他不影響對象的生命周期,如果一個對象與虛引用關聯,則跟沒有與之關聯一樣,在任何時候都可能被垃圾回收器回收。
  • hashcode的作用

        比較兩個對象是否相等,重寫的equals方法一般比較全面,比較復雜,效率比較低,而采用hashcode方法進行對比,只需要生成一個hashcode進行比較就可以了!
  • Hashmap中的hashcode的作用

        a)  Hashcode的存’用於查找的快捷性,如hashtable、hashmap等,hashcode是在散列結構中確定對象的地址。
    
        b)  如果兩個對象相同,就是適用equals方法,那麽這兩個對象的hashcode一定要相同。
    
        c)  如果對象的equals方法被重寫,那麽對象的hashcode也盡量重寫,並且產生hashcode使用的對象,一定要和equals放法使用的一致,否則會違反上面的第二點。
    
        d)  兩個對象的hashcode相同,並不代表這兩個對象就相同,也就是不一定適用equals方法,只能說明這兩個對象在散列存儲結構中,如hashtable,他們“存放在同一個籃子裏”。
  • 為什麽重載hashcode方法?

            一般不需要重載hashcode方法,只有當類放在hshtable、hashmap、hashset等hash結構的集合時,才會重載hashcode。就hashmap來說,好比hashmap就是一個大內存塊,裏面有許多小內存塊,小內存裏面就是一系列的對象,可以利用hashcode查找小內存塊,,所以當equals相等時,hashcode必需相等,而且如果是Object對象,必須重載hashcode和equals方法。
  • Arraylist、linkedlist和vector的區別?

        a)  Arraylist:底層數據結構是數組,查詢快、增刪慢,線程不安全。
    
        b)  Liskedlist;底層數據結構是鏈表,查詢慢、增刪塊,線程不安全。
    
        c)  Vector:底層是數組,查詢慢、增刪慢,線程安全。
  • String、stringbuffer與stringbulder的區別?

        a)  String是不可變的對象,因此每次對string類型進行改變的時候,就等於生成了一個新的對象,然後蔣指針指向一個新的string的對象,因此經常改變內容的字符串最好不用string,因為每次生成對象都會對系統性能產生影響,特別是當內存中無引用對象過多時,jvm的gc就會開始工作,那麽速度一定會非常慢。
    
        b)  而stringbuffer結果就完成不一樣了,每次結果都會對stringbuffer本省進行操作,而不是生成新的對象,再改變對象的引用。是線程安全的。
    
        c)  Stringbuildere是jdk5以後新增的,其用法和stringbuffer完全一致,但它是線程不安全的,在單線程中是最佳的,因為不需要維護線程的安全。
  • Map、set、list、queue、stack的特點與用法。

        a)  Map是鍵值對,鍵key是唯一不能重復的,一個鍵對應一個值,值可以重復,treemap可以保證順序,hashmap不保證順序,即是無序的,map可以把key和value單獨抽取出來,其中keyset()方法可以將所存的key抽取成一個set。而valuses方法可以將map中所有的value抽取成一個集合。
    
        b)  Set:不包含重復元素,且最多包含一個null元素,只能用iterater實現單向遍歷, set沒有同步方法。
    
        c)  List:有序的可重復集合,可以在任何位置增加和刪除元素。用Iterator實現單向遍歷,也可以用listIterator實現是雙向遍歷。
    
        d)  Queue:遵從先進先出原則,使用時盡量避免add()和remove()方法,而只是使用offer()來添加元素,使用poll來移除元素,它的優點是可以通過返回值來判斷是否成功,LinkedList實現Queue接口,Queue通常不允許插入null元素。
    
        e)  Stack:遵從先進後出原則,stack繼承自vector,它通過五個操作對類vector進行擴展,允許將向量視為堆棧,它提供push和pop操作,以及取堆棧頂點的peek()方法,測試堆棧是否為空的empty()方法等。
    
        f)  用法:如果涉及堆棧、隊列等操作,建議使用list,對於快速插入和刪除元素,建議使用linkedlist,如果,快速隨機訪問元素,建議使用ArrayList。
  • Hashmap和hashtable的區別?

    a) 都是map接口的實現類,都是基於hash表的實現類。

    b) Hashmap集合線程不安全的類,不同步,執行效率高,允許鍵和值是null。

    c) Hashtable集合是線程安全的類,同步,執行效率低,不允許鍵和值為null。

  • Jdk7和jdk8中的hashmap的實現。

        a)  Jdk7:hashmap底層維護一個數組,數組中的每一項都是一個entry,我們向hashmap中放置的對象實際上存儲在該數組中,map中的key和value則以entry的形式存放在數組中,而這個key放在數組的哪一個位置上,是通過key的hashcode來計算的。
    
        b)  Jdk8:采用(位桶+鏈表)紅黑樹的方式,也是非線程安全的。
  • Hashmap和hashConcurrentHashmap的區別,hashmap的底層源碼。

            Hashmap是線程非安全的,效率比較高,hashtable和ConcurrentHashmap是線程安全的,效率比hashmap差一點,但ConcurrentHashmap采用了更高級的分段鎖機制,具體可以理解為把hashmap拆分為n個小的hashtable,根據key。Hashcode()來決定把key放到哪個hashtable中,在concurrenthashmap中,就是把map分為n個segment,put和get時,都是key.hashcode()算出放到哪個segment中。
  • 接口和繼承的區別?接口內可以定義常量嗎?繼承可以繼承父類的那些東西?

        a)  區別:
            i.  標識符不同,interface和extends
            ii. 接口支持多繼承,而不支持繼承的繼承
            iii.    接口中只能定義全局變量和抽象變量,而繼承中可以定義屬性、方法、常量、變量等。
            iv. 某接口被實現,在類中一定要實現接口所有的方法,而繼承只需要用哪一個就調用哪一個。
    
        b)  接口不可以定義常量。
    
        c)  繼承可以繼承父類所有的東西(成員方法、成員變量、包括私有)。
  • 如何修改父類中以private關鍵字修飾的變量?

        如果父類中有public的set方法,就可以通過set方法修改父類中以private修改的變量。
  • Java中public、private 、protect、default的區別?

        a)  Public:java中訪問限制最寬的修飾符,即公共的,被修飾的類、屬性、方法允許跨類訪問,甚至可以跨包訪問。
    
        b)  Private:是java中訪問限制最窄的修飾符,被private修飾的類、屬性、方法只能被本類的對象進行訪問,其子類不能訪問,更不允許跨包訪問。
    
        c)  Protec:介於public和private之間的一種訪問修飾符,一般稱受保護的,被其修飾的類、方法、屬性只能被本類和子類進行訪問,即使子類不在同一個包下。
    
        d)  Default:意為默認的,即不加修飾符,該模式下只能同一個包下進行訪問。
  • 數據庫鎖的問題?如何上鎖?是不是行鎖?

        a)  當多個用戶同時對數據庫進行操作時,會帶來數據不一致的問題,所以鎖主要是用於多用戶環境下保證數據庫完整性和一致性.
    
        b)  鎖分類:從數據庫系統來看:排它鎖、悲觀鎖、更新鎖
        從程序員角度來看:一種是樂觀鎖,一種是悲觀鎖。
        i.  悲觀鎖:很悲觀,每次去拿數據的時候,都以為別人會修改,所以在每次拿數據的時候,都會上鎖,這樣別人拿這個數據就會block,直到它合鎖。具有強烈的排他性和獨占性,悲觀鎖的實現依靠數據庫提供的機制,也只有數據庫底層提供的機制才能保證數據訪問的排他性。傳統的關系型數據庫用到了很多這同樣的機制,比如行鎖、表鎖、讀鎖、寫鎖等,都是在操作前加上鎖。
        ii. 樂觀鎖:很樂觀,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。悲觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,像數據庫如果提供類似於write—condition機制的其實都是提供的樂觀鎖。
  • c) 按作用性質分:

    i.  共享鎖:也叫讀鎖,用於所有只讀操作,不能同時增刪改,可以查。
    例如:select * from 表 lock in share mode;
    
        ii. 排它鎖:也叫讀鎖,表示對數據進行寫操作,一個事務對象施加了排它鎖,其他事務就不能加鎖了。
    例如:查詢時加排它鎖,別人不能加共享鎖和排它鎖。
    Select * from 表 for update;
            僅允許一個事務封鎖此表,其他事務必須等到此鎖被釋放才能訪問。
            排它鎖(x鎖)一直到事務結束才能釋放。
    iii.    更新鎖:允許其他事務讀,但不允許在施加x鎖和u鎖,當要被讀取的對象要被更新的時候,則升級為x鎖,防止死鎖,如果一個數據在修改前直接申請更新鎖,在修改時再升級為排它鎖,就可以避免死鎖。

    d) 按範圍分:

    i.  行鎖:鎖的範圍是行級別,數據能夠確定哪些行需要鎖的情況下使用行鎖(inodb),如果在不知道會影響到哪些數據的時候就會使用表鎖
    例如:一個用戶表有主鍵id和birthday。
    Update …where id=?  行鎖
    Update … where birthday=?   表鎖
    
    ii. 表鎖:鎖的範圍是整張表。 MyISAM

    22.事務的隔離性

    a)  隔離性級別越低,並發性越好,但數據庫的一致性就越差。
    隔離級別越高,並發性越差,但數據庫的一致性高。
    
    b)  由低到高
    讀未提交<讀提交<可重復讀(默認)<序列化讀
    
    c)  錯誤的級別由低到高:
    臟讀、不可重復讀、幻讀
    臟讀:兩個事物,一個事務先修改,另一個事務讀,結果是修改前的結果。
    不可重復讀:兩個事物,一個先讀是一個結果,一個後修改,再讀,又是一個結果。
    幻讀:第一個事務表中有10、20、30、40幾個部門,第二個事務插入表中50的部門,然後提交,第一個事務插入50部門,主鍵沖突。

    23.能否用一個sql語句解決庫存判斷問題(非查詢語句)。

    用if語句:if(exper1,exper2,exper3)
            如果exper1的值是true,則返回是exper2的值,如果exper1的值是false,則返回exper3的值。
    例如:id   name        number
                1       蘋果      300
                2       梨           100
    Update fruit set number=if(number>200,number,0)where if=’1’;
    即如果蘋果的數量大於200,就不變,否則,number改為0,即就可以判斷內存是否充足。

    24.紅黑樹

    a)  特性:
    
    i.  每個節點都是黑色或者紅色。
    ii. 根節點是黑色。
    iii.    定義null為黑色。
    iv. 如果某個子節點是紅色,那麽它的兩個兒子都是黑色,且父節點一定是黑色。
    v.  對於任意節點,它到葉子節點的每一條路徑都包含相同數目的黑色節點
    性質5稱之為黑高。

    b) 相對平衡:

    i.  若H(left)>=H(right),則H(left)=2*H(right)+1
    ii. 但BH(left)=BH(right),H(left)<H(right)同理。

    c) 在調整節點p之前,必需保證p的左子樹left、右子樹right都已經是rbt。

    i.  多個子問題成立->某個總問題成立
    ii. 插入調整:刪除調整均是由底向上

    d) Rbt的插入調整(默認是紅色)

    i. 無需調整

    1. X為根節點,將x由紅染黑
    2. 父親節點是黑色

    ii. 僅僅考慮父親節點p是紅色,由於性質4,爺爺節點必定是黑色,分為3中:

    1.  Case1:y為黑色,x可左可右;p、y染黑,g染紅;x回溯至g
    2.  Case2:y為黑色,x為右孩子,左旋p,x指向p,轉為case3
    3.  Case3:y為黑色,x為左孩子,p染黑,g染紅,右旋g結束。
    Rbt的插入調整最多2次
    右旋轉:逆時針旋轉兩個節點,使父親節點被右孩子取代,而自己變成左孩子。
    左孩子:順時針旋轉兩個子節點,使父親節點被左孩子取代,自己變成右孩子。

    25.Session是什麽?和cookie的區別?

    a)  Cookie通過客戶端記錄信息確認身份,session是通過服務端的信息確認身份。
    b)  客戶端瀏覽器訪問服務器的時候,服務端把客戶端的信息以某種形式記錄在服務器上,這就是session,用戶與服務器建立連接的同時,服務器自動分配一個sessionid。
    c)  區別:cookie不×××全,別人可以分析本地存在的cookie並進行cookie欺騙,考慮到安全應當使用session。
    1. 有哪些排序算法?說一下堆排序?時間復雜度是多少?

      a)  直接插入排序:第一個元素已經排序,第二個與第一個元素進行比較,第一個大,第一個則與第二個交換位置,第三個分別於第一個和第二個比較,以此類推。
      時間復雜度:O(n*n)
      
      b)  希爾排序:按步長grep進行分組,然後將每組元素利用直接插入排序的方法進行排序;每一次結束後再將步長grep減半,循環上述操作,直到步長grep=1,利用直接插入排序,完成排序。
      時間復雜度:O(log n)
      
      c)  簡單選擇排序:首先在未排序序列中找到最小(或最大)的元素,放在排序序列的起始位置,然後再從未排序序列中找到最小(最大)的元素,放在已排序序列的後面。
      時間復雜度:O(n*n)
      
      d)  堆排序:堆排序過程就是將待排序序列構造成一個堆,選出堆中最大的移走,再把剩下的整成堆,找出最大的在移走,重復直至有序。
      i.  每次將根節點與左右節點最大的進行交換,直到根節點最大,然後把根節點放在最後一個位置,然後再次執行循環,找到最大值放在長度-1的位置。
      ii. 時間復雜度:O(n log n)
      
      e)  冒泡排序:每次比較兩個元素,把小的放在前面。
      時間復雜度:O(n*n)
      
      f)  快速排序:把一個序列分為兩個子序列,步驟可分為:
      i.  從數列中選出一個元素,作為基準。
      ii. 重新排序數列,所有比基準序列小的元素放在基準前面,所有比基準大的元素放在基準後面,相同的放在任意一邊,在這個分區結束後,該基準處於中間位置。
      iii.    遞歸將小於基準的子序列和大於基準的子序列排序。
      iv. 即:先對大序列進行排序,大序列分為兩個子序列,然後遞歸調用方法對這兩個序列進行排序。
      
      g)  歸並排序:將兩個或兩個以上的有序表合並成一個新的有序表,即把待排序序列分為若幹個子序列,每個子序列都是有序的,然後再把整個序列合並成整體有序序列。
      時間復雜度:O(nlogn)
      
      h)  基數排序:將所有待比較的數(正整數統一為同樣的數位長度),數位數不足的前面補0,然後從低位開始,依次進行一次排序,這個序列從最低位排序一直到最高位排序完成以後,數列將變成一個有序序列。
      時間復雜度:O(d*(n+r))
      D為位數,r為基數,n為數據個數

    27.Statement和preparestatement的區別?

    a)  代碼的可讀性和可維護性preparestatement更好。
    b)  Preparestatement盡最大可能提高性能。
    c)  提高安全性,preparestatement防止sql註入。

    28.NIO和IO到底有什麽區別?有什麽關系?

    a)  NIO是以塊的方式處理數據,但是IO是以最基礎的字節流的形式去寫入和讀出的,肯定NIO的效率比IO的效率高出好多。
    b)  NIO不是和IO一樣用Ouputstream和Inputstream輸入流形式來處理數據,但是基於這種流的形式,而是采用通道和緩沖流的形式來處理數據的。
    c)  NIO通道可以是雙向的,IO中的流只能是單向的。
    d)  還有就是NIO的緩沖區(其實也是一個字符數組)還可以進行分片,可以建立只讀緩沖區、直接緩沖區和間接緩沖區,只讀緩沖區很明顯就字面意思,直接緩沖區是為了加快I/O速度,而以一種特殊的方式分配其內存的緩沖區。

    29.數據庫索引的分類,索引底層的實現,說一下b+樹,b-樹?
    a) 索引的作用:

    i.  提高查詢速度
    ii. 確保數據的唯一性
    iii.    可以加快表與表之間的連接,實現表和表之間的完整性。
    iv. 使用分組和排序字句進行數據檢查時,可以減少分組和排序的時間。
    v.  全文檢索字段進行搜索優化。

    b) 分類;

    i.  主鍵索引(PRIMAY_KEY):確保數據記錄的唯一性,一個表只有一個。
    ii. 唯一索引(UNIQUE):避免一個表中某些數據列中的值重復。可以有多個。
    iii.    常規索引(INDEX):快速定位特定數據。
    iv. 全文索引(FULLTEXT):快速定位特定數據,只能用於MyISAM類型的數據表。

    c) 索引底層實現:把平衡樹當做數據表默認的索引數據結構,平衡樹也就你、b+tree或者b-tree。

    d) B-tree:適用於外查找的樹,是平衡樹的多叉樹。

    i.  一個m階b樹是一顆平衡的m路搜索樹,它或者是空樹,或者滿足下列性質:
    
    1.  定義任意非葉子節點最多有m個兒子,且m>=2;
    2.  根節點的兒子數[2,m];
    3.  除根節點以外的葉子節點的兒子數{m/2,m};
    4.  每個節點存放m/2-1(向上取整)和至多m-1個關鍵字(至少2個)。
    5.  非葉子節點的關鍵字個數=指向兒子的指針個數-1;
    6.  非葉子節點的關鍵字:k[1]、k{2}…k[m-1],且k{i}<k{i+1}。
    7.  非葉子節點的指針:p{1} 、p{2} 、p{3}、 p{4} …p{m},其中p[1】指向小於k[1]的子樹,p[m]指向關鍵字屬於k{i}和k{i+1}之間的子樹。
    8.  所有子樹節點位於同一層。

    ii. B-樹的特性:

    1.  關鍵字集合分布在整棵樹中。
    2.  任何一個關鍵字出現且只出現一個節點中。
    3.  搜索可能在非葉子節點結束。
    4.  其搜索性能等價於在在關鍵字全集中做一次二分查找。
    5.  自動層次控制。

    e) B+樹:

        i.  B+樹的定義:
            1.  其定義與b-樹基本相同,除了:
            2.  非葉子節點的子樹指針與關鍵字個數相同。
            3.  非葉子節點的子樹指針p[i],指向關鍵字屬於k[i],k[i+1]的子樹。
            4.  為所有關鍵字增加一個鍵指針。
            5.  所有關鍵字在葉子節點出現。
    
        ii. B+樹的特性:
    
    1.  所有關鍵字都出現葉子節點的鏈表中(稠密索引)且鏈表中的關鍵字恰好是有序的。
    2.  不可能在非葉子節點命中。
    3.  非葉子節點相當於葉子節點的索引(稀疏索引),葉子節點相當於存儲數據(關鍵字)的數據層。
    4.  更適合文件索引系統。

    Java後臺開發常見面試題