Java面試整理《上》

一、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傳遞數據如同方法肚子裏,臉上自然不能放太多東西也不能放隱私的東西,而肚子裏就無所謂了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章