Java面試題整理《上》

zy5e05發表於2018-09-20

要找工作啦,在這裡記錄下整理的面試題。Java體系還是很龐大的,我將其分為Java語言部分(JavaSE、JavaEE等官方方面),非Java語言部分(資料庫,WEB前端,redis,框架等技術方面)和專案部分。

一、Java基礎部分

  1. 簡單介紹下Java的跨平臺原理

    不同的作業系統的操作指令集不同,所以做程式開發的時候需要根據不同的作業系統開發程式。比如想要程式支援MacOS、Windows和Linux就要開發三套不同的程式程式碼。這會導致開發成本成倍提升,所以很多程式都只開發了windows版本。這是相對於桌面程式來說的,如果是WEB應用程式就沒有這個煩惱,這也是WEB開發這麼流行的原因。
    Sun公司開發了適用於不同作業系統及位數的JVM虛擬機器來遮蔽系統之間的差異並提供了統一的介面,對於Java程式而言,只需要遵循Java語言規範,就可以在所有的作業系統上執行程式。

  2. Java中int資料佔用幾個位元組?

    int資料佔用4個位元組,這在哪個位數作業系統上都是一樣的,主要是為了跟CPU的字長一致,目的當然是提高處理速度。

  3. Java物件導向有哪些特徵?

    主要有四個特徵:抽象,封裝,繼承和多型。

    抽象的目的是忽略與主題無關的其他資訊,使用abstract關鍵字修飾,規定抽象方法只能為public/protected,被修飾的類不能被例項化,只允許通過繼承的方式來實現。

    封裝的意思就是想讓你看到就讓你看到不想讓你看到就不讓你看到,使用private關鍵字實現,當你需要對屬性進行修改的時候就使用類中的get/set方法,使用public關鍵字。這是出於安全和易用性方面的考慮。

    繼承的意義在於不需要重複造輪子,子類繼承父類就可以得到除了private之外的父類的全部屬性和方法(父類的構造方法除外)。需要知道的是Java只支援單繼承,這是出於對繼承鏈可能會出現過於複雜的情況的設計方案,如果想實現類似C++語言的多繼承,可以使用介面來實現。還需要注意這幾點,如果沒有指定父類,那麼類的直接父類是java.lang.Object;一般繼承會導致重寫,子類有時候會需要重寫父類的方法,在重寫時必須保證方法名和形參列表相同,返回值型別和異常型別子類需要小於父類;訪問許可權,子類需要大於父類。

    多型是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫只有在程式執行期間才會確定,在Java中通過繼承的方式來實現多型,即父類介面引用變數指向子類或實現類的例項物件,這樣程式呼叫的方法在執行期才會動態繫結引用變數所指向的具體例項物件的方法,也就是記憶體里正在執行的物件方法。。比如公司規定十點上班工作,但並不會對程式設計師說你要敲程式碼,並不會對HR說你要檢查郵件這個工作的具體實現。需要注意的是多型是方法的多型而不是屬性的多型,多型是在繼承的基礎上實現的。

  4. 介面和抽象的區別是什麼?

    兩者都是Java物件導向的重要實現。它們都宣告方法而不去實現,本質的區別在於抽象類是一個類,而介面是其他的型別,在OC中都沒有介面這一說,而是使用protocol。抽象類除了不能例項化之外跟普通的類沒有區別,而介面完全不存在方法的實現,不能有構造器,只能使用public訪問修飾符,沒有main方法等。介面提供抽象方法,類通過interface關鍵字對接介面,重寫抽象方法實現對應業務邏輯以此對外提供服務。比如Map接扣作為一個容器就會提供put方法來往容器中填充值,get方法獲取容器中某一個值,size屬性獲取容器大小,remove方法來刪除容器中的值。介面除了做規範之外還是多繼承在Java中的解決方案,另外介面也是各種框架和API的實現,比如RedisTemplate就是封裝了jedis,如果在專案中使用redis,直接通過注入RedisTemplate介面就可以完成對redis的操作。

  5. 已經有基本型別了,為什麼還需要包裝型別呢?

    Java提供了八種基本型別,每一種型別都會有一個對應的包裝型別,比如boolean-Boolean,JVM會在兩者之間自動轉換,這是JDK1.5做的改變。

    Integer i = 1; //自動裝箱,編譯時會呼叫Integer.valueOf(1)

    int j = i; //自動拆箱,編譯時呼叫intValue();

    值得注意的是自動裝箱時系統會建立快取,並將當前資料新增到快取中,有兩個作用,第一是為了緩解使用包裝型別導致資料儲存會略微變慢的問題,第二是解決了包裝型別判斷是否相等的問題。

    Java是一門物件導向的語言,基本資料型別並不具備物件導向的特徵,這會導致資料儲存的問題,例如在處理空值的時候,使用Integer時需要判斷null,使用int的時候需要判斷0,而在資料庫中通常預設值為0。這會導致在資料庫中儲存id的時候,id型別為bigint,當控制類方法的接收值為long而不是Long的話會報錯。使用Long表示類的ID的時候,在需要判斷類是否存在只需要判斷為null就可以了,而且使用包裝型別就可以通過其提供的方法MAX和MIN獲取最大值和最小值等。

  6. 說一下”==”和equals方法究竟有什麼區別?

    ==用於判斷兩個變數是否相等。變數可以分為基本資料型別和引用資料型別,如果是引用資料型別需要比較引用的記憶體首地址,如果是基本資料型別直接比較值。

    equals方法是判斷兩個物件的某些特徵是否一致,通過重寫物件的equals方法。

    如何理解?通過觀察原始碼會發現,equals方法會首先判斷兩個比較值型別是否一致,然後再比較數值或字元,例如Integer型別會自動拆箱為int型別進行比較,String會將字串拆分成字元。

  7. 講一下String和StringBuilder的區別(final)?StringBuffer和StringBuilder的區別?

    java提供了三個類String、StringBuilder和StringBuffer來表示和操作字串。字串即是由多個字元(char)的集合。

    String是內容不可變的字串(private final char value[])

    StringBuilder和StringBuffer繼承自AbstractStringBuilder類(char[] value);

    因此拼接字串的時候:

String:String s = "a"+"b";
StringBuilder sb = new StringBuilder();
sb.apend("a").apend("c")

拼接字串的時候不能使用String進行拼接,要使用StringBuilder和StringBuffer。前者效率高但執行緒不安全,後者效率低但執行緒安全。

  1. 簡單說一下java中的集合

    java中的集合主要分為value和key-value兩種。
    
    儲存值分類list和set,list重複有序,set不可重複無序。並且set根據equals和hashcode判斷,如果物件儲存在set中,則必須重寫這兩個方法。
    
    儲存鍵值在java中是稱之為map,在OC語言中叫字典。
    
  2. List常用的ArrayList和LinkedList的區別和使用場景?

    ArrayList底層使用陣列(private transient Object[] elementData;)
    
    LinkedList底層使用連結串列(transient Node<E> first; transient Node<E> last;)
    
    陣列是一塊連續的記憶體,因此插入和刪除的時候需要移動記憶體。由於有這個特點所以說陣列查詢元素快,插入和刪除刪除慢。
    
    連結串列的原理是在當前元素中存放上一個和下一個元素的地址,查詢時從頭部開始一個個找,因此查詢效率慢,由於做修改的時候不需要做記憶體移動操作,只需要改變引用指向即可完成,所以插入和刪除操作效率高。
    
    不難看出連結串列和陣列是相反的,所以它們的使用場景就呼之欲出了,而由於資料庫操作的特殊性(查詢佔90),所以一般我們會選擇ArrayList做資料儲存的容器。
    
  3. 講一下HashMap和 HashTable的區別?HashTable和ConcurrentHashMap的區別?

    首先HashTable是不可以使用null作為key或者value的,HashTable在儲存資料的時候會返回synchronized。因此可以得出結論HashTable安全但效率不高。
    
    如果想既效率高又安全,可以使用ConcurrentHashMap併發容器的方式,原理是將整個Map分成N個Segment(類似HashTable不加鎖),提供相同的執行緒安全,但是效率提升N倍預設為16倍。
    
  4. 實現一個拷貝檔案的工具類使用位元組流還是字元流?

    位元組流和字元流都可以實現對檔案的拷貝,如果確認不包含例如圖片和音訊這樣特殊的檔案,使用字元流即可,否則應該使用位元組流。
    
  5. 執行緒的幾種實現方式,啟動方式?

    兩種實現方式:繼承Thread類和實現Runnable介面。一般採用實現介面的方式,因為java只支援單繼承。
Thread thread = new Thread(new MyThread());//MyThread類繼承了Thread物件或Runnable介面
thread.setName("xiaoming");//通過設定執行緒名稱來區分執行緒
thread.start();//通過start()方法來啟動執行緒,但實際執行的方法是run方法。run()方法是Thread類和Runnable介面自帶的方法,需要重寫和實現run()。
  1. 執行緒池的作用
  • 執行緒過多的話會導致系統執行緩慢甚至崩潰,所以需要限制執行緒的個數
  • 執行緒池如果每次都建立或者銷燬會導致資源的浪費

什麼是設計模式?常用的設計模式有哪些?

設計模式是前人經驗所得的可以反覆使用,解決特定問題的設計方法。

  • 單例模式是最常見的設計模式之一,它的作用是保證某一例項的唯一性。具體實現就是在類中定義一個例項物件並提供一個公開方法獲取該例項,然後將構造器私有化,如果需要使用該例項的話,只能通過提供的公開方法而不能new出這個類,這樣每次得到的例項就是同一個例項。單例分為懶載入和立即載入兩種模式,懶載入在建立物件的時候就載入例項,立即載入在需要的時候才載入例項。
  • 工廠模式,SpringIoC中的BeanFactory,MyBatis中的SqlSessionFactory就都是工廠模式的實現
  • 代理模式,SpringAOP是通過動態代理實現
  • 觀察者模式,Spring中的listener實現ApplicationListener
  • 模板模式,Spring整合了JdbcTemplate、RedisTemplate、SolrTemplate、JmsTemplate
  • 介面卡模式,SpringMVC中的處理器對映器HandlerMapper

二、J2EE部分

  1. 說一下你對servlet的理解?或者servlet是什麼?

    Java Servlet是使用J2EE服務端程式,後端程式碼通過實現Servlet介面並重寫HTttpServlet的doGet/doPost方法來進行對資料庫和瀏覽器之間的交流,Servlet程式需要執行在支援Java程式的應用伺服器中,比如tomcat,jetty等。

  2. 簡單說一下servlet的生命週期?

    Servlet是一個介面規範,所以有比較明確的生存期定義,介面中的init,service和destory方法進行表述。

  3. Servlet API中forward()與redirect()的區別?

    forward就是轉發,是服務端行為因此只傳送一次請求也不會改變url地址,redirect是重定向,是客戶端行為會改變url地址並且傳送兩次請求

  4. JSP和Servlet有哪些相同點和不同點?

    JSP是Servlet的擴充套件,所有的jsp檔案都會被編譯成一個繼承自HttpServlet的類,因為servlet輸出html比較麻煩,所以設計出jsp。

  5. JSP有哪些內建物件?作用分別是什麼?

    九個內建的物件:

    • request 使用者端請求,此請求會包含來自GET/POST請求的引數
    • response 網頁傳回使用者端的回應
    • pageContext 網頁的屬性是在這裡管理
    • session 與請求有關的會話期
    • application servlet正在執行的內容
    • out 用來傳送回應的輸出
    • config servlet的構架部件
    • page JSP網頁本身
    • exception 針對錯誤網頁,未捕捉的例外

    四大作用域:

    • pageContext 整個page頁面
    • request(HttpServletRequest) service方法
    • session(HttpSession) 第一次呼叫request.getSession()方法時
    • application(ServletContext) 整個WEB應用程式
  6. 說一下Session和Cookie的區別?你在專案中都有哪些地方使用了?

    session和cookie都是HTTP的會話跟蹤技術,是為了解決HTTP無狀態的特性而設計的技術。cookie在客戶端瀏覽器記錄資訊認證身份,session在服務端記錄資訊確認身份。session通過在cookie中存放的sessionId來保證資訊的一致性。

    session和cookie的區別如下

  • 由於cookie資料儲存在瀏覽器中,因此有安全和資料限制的問題,考慮到這種情況應該使用session儲存資料
  • session資料存在伺服器上,當訪問比較多的情況下會耗費伺服器資源,考慮到這種情況應該使用cookie

    購物車是最好的cookie技術實現場景,使用者登入資訊的儲存是最好的session技術實現場景。

    我在做使用者註冊生成簡訊驗證碼和solr非同步刪除索引庫資料,靜態頁面生成的時候使用過jmsTemplate.send()方法,該方法中有一個內部類(new MessageCreator()),此類中接收session引數,然後通過這個session建立訊息例項設定訊息並返回。

  1. HTTP中GET和POST請求的區別
    使用者通過不同的請求方式完成對資源的不同操作,比如PUT請求就是代表對請求資源的增加,DELETE請求就是對請求資源的刪除。為了方便開發,一般我們只使用GET和POST方式就可以了。兩者本質上都是TCP連結,區別在於:
  • get請求時,位址列會顯示請求資訊,以?開頭,多個引數以&連線,而post請求在request body中
  • get請求由於瀏覽器對地址長度的限制而導致傳輸的資料有限,post則沒有這個限制
  • 由於請求資訊會暴露所以get請求會有安全隱患
  • get產生一個TCP資料包,瀏覽器會將http header和data資料一起傳送,等待伺服器響應200並返回資料;post請求產生兩個資料包,瀏覽器會傳送header,等待伺服器響應100 continue,瀏覽器才會傳送data,最後等待伺服器響應200和請求的資料
  • 對於get和post的區別,有一個比較有趣的比喻。get傳遞資料如同寫在臉上,post傳遞資料如同方法肚子裡,臉上自然不能放太多東西也不能放隱私的東西,而肚子裡就無所謂了。


相關文章