日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java面试题-基础篇(万字总结,带答案,面试官问烂,跳槽必备)

發布時間:2023/12/10 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java面试题-基础篇(万字总结,带答案,面试官问烂,跳槽必备) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

👀個人主頁: Java李小立
后面會持續更新java面試專欄,請持續關注
如果文章對你有幫助、歡迎關注、點贊、收藏(一鍵三連??????)

面試寶典列表(持續更新):

序號內容鏈接地址
1Java基礎篇(點擊跳轉)java面試寶典-基礎篇
2Java集合框架篇(點擊跳轉)java面試寶典-集合框架篇
3Java多線程篇(點擊跳轉)java面試寶典- 多線程篇
4JVM篇待分享
5Spring篇待分享
6Mybatis篇待分享
7SpringcCloud篇待分享
8Redis篇待分享
9Mysql篇待分享
10dubbo篇待分享
11zookeeper篇待分享
12kafka篇待分享
13RocketMq篇待分享
14Nacos篇待分享

(一)Java基礎

1.1.Java歷史簡述

  • 1991 年Sun公司的James Gosling詹姆斯?高斯林)等人開始開發名稱為 Oak
    的語言,希望專攻計算機在家電產品上的嵌入式應用(如電視機頂盒、面包烤箱、移動電話等)。
  • 1995年將Oak語言更名為Java;
  • 2009年,甲骨文公司宣布收購Sun公司。

1.2. Java語言的特點

  • 面向對象(封裝,繼承,多態);
  • 平臺無關性( Java 虛擬機實現平臺無關性,一次編譯,到處運行);
  • 簡單易學(與C語言的面向過程相比,Java的面向對象更接近人的語言習慣);
  • 安全性,可靠性(Java中沒有指針,程序員無法直接操作內存,而是把操作權限交給Java虛擬機,使程序不容易出現不容易出現內存泄漏和內存溢出問題。);
  • 支持多線程( C++ 語言沒有內置的多線程機制,因此必須調用操作系統的多線程功能來進行多線程程序設計,而 java的lang包提供一個Thread類本身就支持多線程);
  • 編譯與解釋并存(Java編譯生成字節碼文件,交給Java虛擬機解釋);
  • 1.3. 面向對象與面向過程對比。

    我們都知道Java的核心思想是面向對象,Java中萬事萬物皆對象,那么面向對象與面向過程有什么不同呢?

    (1).面向過程

    優點: 性能比面向對象高,因為類調用時需要實例化,開銷比較大,比較消耗資源;比如單片機、嵌入式開發、Linux/Unix等一般采用面向過程開發,性能是最重要的因素。
    缺點: 沒有面向對象易維護、易復用、易擴展。

    (2).面向對象

    優點: 易維護、易復用、易擴展,由于面向對象有封裝、繼承、多態性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易于維護。
    缺點: 性能比面向過程低。

    1.4. Java平臺的三個版本J2EE、J2SE、J2ME。

    JavaSE:即Java標準版,主要用于開發和部署桌面、例如,Java應用程序開發平臺Eclipse(常說的C\S架構)。
    JavaEE:即Java企業版,主要針對企業應用的開發。例如,電商網站(常說的B\S架構)。
    JavaME:即Java微型版,主要針對移動設備和嵌入式設備。例如,手機、PDA、電視機頂盒等等。

    注:從JDK 5.0開始 J2EE 改名為 java EE,J2SE 改名為 java SE,J2ME 改名成 java ME。

    1.5. JDK、JRE、JVM之間的區別于關系。

    LZ身邊很多Java程序員,雖然寫了很久的代碼,但問他們jre 和 jdk 之間有什么關系,jvm 又是什么東西,很多人都講的不是特別清楚,作為一個合格的Java程序員了解這方面的基礎理論知識是很必要的。

    (1).三者之間的區別:

    JDK:(Java Development Kit)即java的開發與運行環境,他除了包含完整的JRE之外,還包含了供開發者使用的工具包。
    JRE:(Java Runtime Environment)即Java運行環境,非開發者只需要安裝 JRE來運行程序, 它包含java運行的所需的類庫+JVM(java虛擬機)。
    JVM: (Java Virtual Machine) 即Java虛擬機, 當我們運行一個程序時,JVM 負責將字節碼轉換為特定機器代碼,JVM 提供了內存管理/垃圾回收和安全機制等。這種獨立于硬件和操作系統,正是 java 程序可以一次編寫多處執行的原因。

    (2).三者之間的關系

  • 作為程序員,就必須安裝JDK,因為其中包含Java開發工具包,同時也包含了JRE。
  • 作為使用者,運行已經開發好的Java程序,只需要安裝JRE。
  • JVM和JRE的關系:JRE包含了JVM,JVM是運行Java程序的核心虛擬機,同時也包含了Java程序所需的環境支持
  • 總結:JDK>JRE>JVM
  • 1.6. 什么是Java環境變量?

  • 環境變量的意義
    讓java bin目錄下的工具,可以在任意目錄下運行,原理是將該工具所在目錄告訴了系統,當使用該工具時,由系統幫我們去找指定的目錄。
  • JAVA_HOME
  • 它指向jdk的安裝目錄,引用%JAVA_HOME%即可,避免每次引用都輸入很長的路徑串,方便第三方軟件引用約定好的JAVA_HOME變量,保證程序正常運行。
  • Path環境變量
    設置Path環境變量之后就可以在任何目錄下執行javac/java等工具命令了。 系統默認先去當前路徑下找要執行的程序,如果沒有,再去path中設置的路徑下找。
  • ClassPath
    如果指定了classpath,那么會在指定的目錄下查找要運行的類文件(JDK1.5后不需要配置
  • 1.7. javac命令和java命令做什么事情呢?

    java運行分兩部分:一個是編譯,一個是運行。
    javac:負責的是編譯的部分,當執行javac時,會啟動java的編譯器程序。對指定擴展名的.java文件進行編譯。編譯后生成class文件。
    java:負責運行的部分.會啟動jvm虛擬機,加載運行時所需的類庫,并對class文件進行執行.

    一個文件要被執行,必須要有一個執行的起始點,這個起始點就是main函數.

    1.8. 什么是字節碼,采用字節碼的好處是什么。

    首先我們來談談Java文件類型,一共有兩種:

  • 擴展名為Java,Java的源文件,編譯之前的純文本文件,用來儲存Java源代碼。

  • 擴展名為class,Java 的類文件,編譯之后的二進制文件,存儲的是字節碼

    也就是說編譯后的.class文件存儲就是字節碼*。

    采用字節碼的最大好處: 可以實現一次編譯到處運行,也就是java的與平臺無關性,它依靠不同平臺的Java虛擬機將編譯后的字節碼解釋成具體平臺上的機器指令執行。

  • 1.9. import java和javax有什么區別

    剛開始的時候 JavaAPI 所必需的包是 java 開頭的包,javax 當時只是擴展 API 包來說使用。然而隨著時間的推移,javax 逐漸的擴展成為 Java API 的組成部分。但是,將擴展從 javax 包移動到 java 包將是太麻煩了,最終會破壞一堆現有的代碼。因此,最終決定 javax 包將成為標準API的一部分。
    所以,實際上java和javax沒有區別。這都是一個名字。

    1.10. Java和C++的區別

    都是面向對象的語言,都支持封裝、繼承和多態
    Java 不提供指針來直接訪問內存,程序內存更加安全
    Java 的類是單繼承的,C++ 支持多重繼承;雖然 Java 的類不可以多繼承,但是接口可以多繼承。
    Java 有自動內存管理機制,不需要程序員手動釋放無用內存

    1.11.Java數據類型

  • 基本數據類型
  • 引用類型
    類、接口類型、數組類型、枚舉類型、注解類型。
  • 區別
    基本數據類型 在被創建時,在棧上給其劃分一塊內存,將數值直接存儲在棧上。
  • 引用數據類型 在被創建時,首先要在棧上給其引用(句柄)分配一塊內存,而對象的具體信息都存儲在堆內存上,然后由棧上面的引用指向堆中對象的地址。

    1.12.Java訪問修飾符

    1.13.標識符的命名規則。

    標識符的含義: 是指在程序中,我們自己定義的內容,譬如,類的名字,方法名稱以及變量名稱等
    等,都是標識符。
    命名規則:(硬性要求) 標識符可以包含英文字母,0-9的數字,$以及_ 標識符不能以數字開頭 標
    識符不是關鍵字
    命名規范:(非硬性要求) 類名規范:首字符大寫,后面每個單詞首字母大寫(大駝峰式)。 變量
    名規范:首字母小寫,后面每個單詞首字母大寫(小駝峰式)。 方法名規范:同變量名。

    1.14.instanceof 關鍵字的作用

    instanceof 嚴格來說是Java中的一個雙目運算符,用來測試一個對象是否為一個類的實例,用法
    為:

    `boolean result = obj instanceof Class

    其中 obj 為一個對象,Class 表示一個類或者一個接口,當 obj 為 Class 的對象,或者是其直接或間接子類,或者是其接口的實現類,結果result 都返回 true,否則返回false

    1.15.Java自動裝箱與拆箱

    裝箱就是自動將基本數據類型轉換為包裝器類型(int–>Integer);調用方法:Integer的
    valueOf(int) 方法
    拆箱就是自動將包裝器類型轉換為基本數據類型(Integer–>int)。調用方法:Integer的
    intValue方法

    在Java SE5之前,需要手動裝箱與拆箱Integer

    //手動裝箱 Integer integer = Integer.valueOf(10); //手動拆箱 int i = num.intValue();

    而在從Java SE5開始就提供了自動裝箱的特性,如果要生成一個數值為10的Integer對象,只需要
    這樣就可以了:

    Integer i = 10;

    1.16. 字符型常量和字符串常量的區別

    char與String

  • 形式上: 字符常量是單引號引起的一個字符 字符串常量是雙引號引起的若干個字符。
  • 含義上: 字符常量相當于一個整形值( ASCII含義上: 字符常量相當于一個整形值( ASCII 值),可以參加表達式運算 字符串常量代表一個地址值(該字符串在內存中存放位置)。
  • 占內存大小 字符常量只占2個字節 字符串常量占若干個字節(至少一個字符結束標志) (注意: char在Java中占兩個字節)
  • 1.17.泛型常用特點 (待補充)

    泛型是Java SE 1.5之后的特性
    “泛型” 意味著編寫的代碼可以被不同類型的對象所重用。

    使用泛型的好處?
    以集合來舉例,使用泛型的好處是我們不必因為添加元素類型的不同而定義不同類型的集合,如整
    型集合類,浮點型集合類,字符串集合類,我們可以定義一個集合來存放整型、浮點型,字符串型
    數據,而這并不是最重要的,因為我們只要把底層存儲設置了Object即可,添加的數據全部都可向
    上轉型為Object。 更重要的是我們可以通過規則按照自己的想法控制存儲的數據類型。

    1.18. Java 面向對象編程三大特性:封裝、繼承、多態

    封裝
    封裝把一個對象的屬性私有化,同時提供一些可以被外界訪問的屬性的方法,如果屬性不想被外界訪問,我們大可不必提供方法給外界訪問。

    繼承
    繼承是使用已存在的類的定義作為基礎建立新類的技術,新類的定義可以增加新的數據或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。通過使用繼承我們能夠非常方便地復用以前的代碼 同時繼承也為實現多態做了鋪墊。

    關于繼承

  • 子類擁有父類非 private 的屬性和方法。
  • 子類可以擁有自己屬性和方法,即子類可以對父類進行擴展。
  • 多態
    所謂多態就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量倒底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在由程序運行期間才能決定。

  • 體現: 父類引用或者接口的引用指向了自己的子類對象
  • 1.19. 代碼中如何實現多態?

    實現多態主要有以下三種方式:

  • 接口實現
  • 繼承父類重寫方法
  • 同一類中進行方法重載
  • 1.20. 多態有什么好處?

    允許不同類對象對同一消息做出響應,即同一消息可以根據發送對象的不同而采用多種不同的行為方式(發送消息就是函數調用)。主要有以下優點:

  • 可替換性:多態對已存在代碼具有可替換性

  • 可擴充性:增加新的子類不影響已經存在的類結構

  • 接口性:多態是超類通過方法簽名,向子類提供一個公共接口,由子類來完善或者重寫它來實現的。

  • 1.21. 接口和抽象類的區別是什么

  • 接口的方法默認是 public,所有方法在接口中不能有實現(Java 8 開始接口方法可以有默認實現),抽象類可以有非抽象的方法。
  • 接口中的實例變量默認是 final 類型的,而抽象類中則不一定。
  • 一個類可以實現多個接口,但最多只能實現一個抽象類。
  • 一個類實現接口的話要實現接口的所有方法,而抽象類不一定。
  • 接口不能用 new 實例化,但可以聲明,但是必須引用一個實現該接口的對象 從設計層面來說,抽象是對類的抽象,是一種模板設計,接口是行為的抽象,是一種行為的規范。
  • 比較抽象類接口
    默認方法抽象類可以有默認的方法實現java 8之前,接口中不存在方法的實現.
    實現方式子類使用extends關鍵字來繼承抽象類.如果子類不是抽象類,子類需要提供抽象類中所聲明方法的實現.子類使用implements來實現接口,需要提供接口中所有聲明的實現.
    構造器抽象類中可以有構造器,接口中不能
    和正常類區別抽象類不能被實例化接口則是完全不同的類型
    訪問修飾符抽象方法可以有public,protected和default等修飾接口默認是public,不能使用其他修飾符
    多繼承一個子類只能存在一個父類一個子類可以存在多個接口
    添加新方法想抽象類中添加新方法,可以提供默認的實現,因此可以不修改子類現有的代碼如果往接口中添加新方法,則子類中需要實現該方法.
    -

    1.22.接口的意義抽象類的意義?

    接口的意義
    接口的意義用三個詞就可以概括:規范,擴展,回調。
    抽象類的意義
    抽象類的意義可以用三句話來概括:

  • 為其他子類提供一個公共的類型

  • 封裝子類中重復定義的內容

  • 定義抽象方法,子類雖然有不同的實現,但是定義時一致的

  • 1.23. 重載和重寫的區別

    重載: 發生在同一個類中,方法名必須相同,參數類型不同、個數不同、順序不同,方法返回值和訪問修飾符可以不同,發生在編譯時。
    重寫: 發生在父子類中,方法名、參數列表必須相同,返回值范圍小于等于父類,拋出的異常范圍小于等于父類,訪問修飾符范圍大于等于父類;如果父類方法訪問修飾符為 private 則子類就不能重寫該方法。

    1.24. 一個類的構造方法的作用是什么 若一個類沒有聲明構造方法,該程序能正確執行嗎 為什么

    主要作用是完成對類對象的初始化工作??梢詧绦?。因為一個類即使沒有聲明構造方法也會有默認的不帶參數的構造方法。

    1.25. 構造方法有哪些特性

  • 名字與類名相同;
  • 沒有返回值,但不能用void聲明構造函數;
  • 生成類的對象時自動執行,無需調用。
  • 1.26. 構造器 Constructor 是否可被 override

    在講繼承的時候我們就知道父類的私有屬性和構造方法并不能被繼承,所以 Constructor 也就不能被 override(重寫),但是可以 overload(重載),所以你可以看到一個類中有多個構造函數的情況。

    1.27. 在調用子類構造方法之前會先調用父類沒有參數的構造方法,其目的是?

    幫助子類做初始化工作。

    1.28. 在 Java 中定義一個不做事且沒有參數的構造方法的作用

    Java 程序在執行子類的構造方法之前,如果沒有用 super() 來調用父類特定的構造方法,則會調用父類中“沒有參數的構造方法”。因此,如果父類中只定義了有參數的構造方法,而在子類的構造方法中又沒有用 super() 來調用父類中特定的構造方法,則編譯時將發生錯誤,因為 Java 程序在父類中找不到沒有參數的構造方法可供執行。解決辦法是在父類里加上一個不做事且沒有參數的構造方法。

    1.29. 在一個靜態方法內調用一個非靜態成員為什么是非法的,靜態方法和實例方法有何不同?

    為什么非法
    由于靜態方法可以不通過對象進行調用,類的靜態成員(變量和方法)屬于類本身,在類加載的時候就會分配內存,可以通過類名直接去訪問;非靜態成員(變量和方法)屬于類的對象,所以只有在類的對象產生(創建類的實例)時才會分配內存,然后通過類的對象(實例)去訪問。
    有何不同

  • 在外部調用靜態方法時,可以使用"類名.方法名"的方式,也可以使用"對象名.方法名"的方式。而實例方法只有后面這種方式。也就是說,調用靜態方法可以無需創建對象。
  • 靜態方法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變量和靜態方法),而不允許訪問實例成員變量和實例方法;實例方法則無此限制.
  • 在一個類的靜態成員中去訪問其非靜態成員之所以會出錯是
    因為在類的非靜態成員不存在的時候類的靜態成員就已經存在了,訪問一個內存中不存在的東西當然會出錯:

    1.30. 成員變量與局部變量的區別有那些

  • 從語法形式上,看成員變量是屬于類的,而局部變量是在方法中定義的變量或是方法的參數;成員變量可以被 public,private,static 等修飾符所修飾,而局部變量不能被訪問控制修飾符及 static 所修飾;但是,成員變量和局部變量都能被 final 所修飾;
  • 從變量在內存中的存儲方式來看,成員變量是對象的一部分,而對象存在于堆內存,局部變量存在于棧內存。
  • 從變量在內存中的生存時間上看,成員變量是對象的一部分,它隨著對象的創建而存在,而局部變量隨著方法的調用而自動消失。
  • 成員變量如果沒有被賦初值,則會自動以類型的默認值而賦值(一種情況例外被 final 修飾的成員變量也必須顯示地賦值);而局部變量則不會自動賦值。
  • 1.31. 什么是不可變對象?

    不可變對象指對象一旦被創建,狀態就不能再改變。任何修改都會創建一個新的對象,如 String、Integer及其它包裝類。

    1.32. java 創建對象的幾種方式

  • 采用new(對象實例在堆內存中),對象引用指向對象實例(對象引用存放在棧內存中)

  • 通過反射

  • 采用clone

  • 通過序列化機制
    前2者都需要顯式地調用構造方法。造成耦合性最高的恰好是第一種,因此你發現無論什么框架,只要涉及到解耦必先減少new的使用。

  • 1.33. Object中有哪些公共方法?

  • equals()

  • clone()

  • getClass()

  • notify(),notifyAll(),wait()

  • toString

  • finalize()

  • 1.34. java當中的四種引用

    強引用,軟引用,弱引用,虛引用。不同的引用類型主要體現在GC上:

  • 強引用:如果一個對象具有強引用,它就不會被垃圾回收器回收。即使當前內存空間不足,JVM也不會回收它,而是拋出 OutOfMemoryError 錯誤,使程序異常終止。obj.equels(new Object())
  • 而這樣 obj對象對后面new Object的一個強引用,只有當obj這個引用被釋放之后,對象才會被釋放**

  • 軟引用(SoftReference):在使用軟引用時,如果內存的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在內存不足時,軟引用才會被垃圾回收器回收。
  • // 這里的軟引用指的是指向new String("str")的引用,也就是SoftReference類中T SoftReference<String> wrf = new SoftReference<String>(new String("str"));

    可用場景: 創建緩存的時候,創建的對象放進緩存中,當內存不足時,JVM就會回收早先創建
    的對象。

  • 弱引用(WeakReference):具有弱引用的對象擁有的生命周期更短暫。因為當 JVM 進行垃圾回收,一旦發現弱引用對象,無論當前內存空間是否充足,都會將弱引用回收。 不過由于垃圾回收器是一個優先級較低的線程,所以并不一定能迅速發現弱引用對象。
  • WeakReference<String> wrf = new WeakReference<String>(str);

    可用場景: Java源碼中的 java.util.WeakHashMap 中的 key 就是使用弱引用,我的理解就是,
    一旦我不需要某個引用,JVM會自動幫我處理它,這樣我就不需要做其它操作

  • 虛引用(PhantomReference):顧名思義,就是形同虛設,如果一個對象僅持有虛引用,那么它相當于沒有引用,在任何時候都可能被垃圾回收器回收。由于這個機制,所以虛引用大多
    被用于引用銷毀前的處理工作。還有就是,虛引用創建的時候,必須帶有 ReferenceQueue ,
    使用例子:
  • PhantomReference<String> prf = new PhantomReference<String>(new String("str"), new ReferenceQueue<>());

    可用場景: 對象銷毀前的一些操作,比如說資源釋放等。

    1.35. WeakReference與SoftReference的區別?

    這點在四種引用類型中已經做了解釋,這里簡單說明一下即可:
    雖然 WeakReference 與 SoftReference 都有利于提高 GC 和 內存的效率,但是 WeakReference ,一旦失去最后一個強引用,就會被 GC 回收,而軟引用雖然不能阻止被回收,但是可以延遲到 JVM 內存不足的時候。

    1.36. 為什么要有不同的引用類型

    不像C語言,我們可以控制內存的申請和釋放,在Java中有時候我們需要適當的控制對象被回收的時機,因此就誕生了不同的引用類型,可以說不同的引用類型實則是對GC回收時機不可控的妥協。有以下幾個使用場景可以充分的說明:

  • 利用軟引用和弱引用解決OOM問題:用一個HashMap來保存圖片的路徑和相應圖片對象關聯的軟引用之間的映射關系,在內存不足時,JVM會自動回收這些緩存圖片對象所占用的空間,從而有效地避免了OOM的問題.

  • 通過軟引用實現Java對象的高速緩存:比如我們創建了一Person的類,如果每次需要查詢一個人的信息,哪怕是幾秒中之前剛剛查詢過的,都要重新構建一個實例,這將引起大量Person對象的消耗,并且由于這些對象的生命周期相對較短,會引起多次GC影響性能。此時,通過軟引用和 HashMap 的結合可以構建高速緩存,提供性能。

  • 1.37. 對象的相等與指向他們的引用相等,兩者有什么不同?

    對象的相等,比的是內存中存放的內容是否相等。而引用相等,比較的是他們指向的內存地址是否相等。

    1.38. 什么是方法的返回值?返回值在類的方法里的作用是什么?

    方法的返回值是指我們獲取到的某個方法體中的代碼執行后產生的結果!(前提是該方法可能產生結果)。返回值的作用:接收出結果,使得它可以用于其他的操作!

    1.39. String 和 StringBuffer、StringBuilder 的區別是什么 String 為什么是不可變的

    可變性

    簡單的來說:String 類中使用 final 關鍵字字符數組保存字符串,private final char value[],所以 String 對象是不可變的。而StringBuilder 與 StringBuffer 都繼承自 AbstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數組保存字符串char[]value 但是沒有用 final 關鍵字修飾,所以這兩種對象都是可變的
    線程安全性
    String 中的對象是不可變的,也就可以理解為常量,線程安全。AbstractStringBuilder 是 StringBuilder 與 StringBuffer 的公共父類,定義了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。StringBuilder 并沒有對方法進行加同步鎖,所以是非線程安全的。   
    性能
    每次對 String 類型進行改變的時候,都會生成一個新的 String 對象,然后將指針指向新的 String 對象。StringBuffer 每次都會對 StringBuffer 對象本身進行操作,而不是生成新的對象并改變對象引用。相同情況下使用 StirngBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風險。
    對于三者使用的總結:

  • 操作少量的數據 = String
  • 單線程操作字符串緩沖區下操作大量數據 = StringBuilder
  • 多線程操作字符串緩沖區下操作大量數據 = StringBuffer
  • 1.40. == 與 equals(重要)

    == : 它的作用是判斷兩個對象的地址是不是相等。即,判斷兩個對象是不是同一個對象。(基本數據類型“= =”比較的是值,引用數據類型 = = 比較的是內存地址).
    equals() : 它的作用也是判斷兩個對象是否相等。但它一般有兩種使用情況:

    情況1:類沒有覆蓋 equals() 方法。則通過 equals() 比較該類的兩個對象時,等價于通過“==”比較這兩個對象。
    情況2:類覆蓋了 equals() 方法。一般,我們都覆蓋 equals() 方法來兩個對象的內容相等;若它們的內容相等,則返回 true (即,認為這兩個對象相等)。
    說明:

    String 中的 equals 方法是被重寫過的,因為 object 的 equals 方法是比較的對象的內存地址,而 String 的 equals 方法比較的是對象的值。
    當創建 String 類型的對象時,虛擬機會在常量池中查找有沒有已經存在的值和要創建的值相同的對象,如果有就把它賦給當前引用。如果沒有就在常量池中重新創建一個 String 對象。

    1.41. hashCode 與 equals(重要)

    面試官可能會問你:“你重寫過 hashcode 和 equals 么,為什么重寫equals時必須重寫hashCode方法?”

    hashCode()介紹
    hashCode() 的作用是獲取哈希碼,也稱為散列碼;它實際上是返回一個int整數。這個哈希碼的作用是確定該對象在哈希表中的索引位置。hashCode() 定義在JDK的Object.java中,這就意味著Java中的任何類都包含有hashCode() 函數。

    散列表存儲的是鍵值對(key-value),它的特點是:能根據“鍵”快速的檢索出對應的“值”。這其中就利用到了散列碼!(可以快速找到所需要的對象)。
    為什么要有 hashCode
    我們以“HashSet 如何檢查重復”為例子來說明為什么要有 hashCode:

    當你把對象加入 HashSet 時,HashSet 會先計算對象的 hashcode 值來判斷對象加入的位置,同時也會與其他已經加入的對象的 hashcode 值作比較,如果沒有相符的hashcode,HashSet會假設對象沒有重復出現。但是如果發現有相同 hashcode 值的對象,這時會調用 equals()方法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同,HashSet 就不會讓其加入操作成功。如果不同的話,就會重新散列到其他位置。(摘自我的Java啟蒙書《Head fist java》第二版)。這樣我們就大大減少了 equals 的次數,相應就大大提高了執行速度。

    hashCode()與equals()的相關規定

  • 如果兩個對象相等,則hashcode一定也是相同的。
  • 兩個對象相等,對兩個對象分別調用equals方法都返回true。
  • 兩個對象有相同的hashcode值,它們也不一定是相等的。
  • 因此,equals 方法被覆蓋過,則 hashCode 方法也必須被覆蓋,hashCode() 的默認行為是對堆上的對象產生獨特值。如果沒有重寫 hashCode(),則該 class 的兩個對象無論如何都不會相等。
  • 1.42. 簡述線程,程序、進程的基本概念。以及他們之間關系是什么?

    1.43. 線程有哪些基本狀態?這些狀態是如何定義的?

  • 新建(new):新創建了一個線程對象。
  • 可運行(runnable):線程對象創建后,其他線程(比如main線程)調用了該對象的start()方法。該狀態的線程位于可運行線程池中,等待被線程調度選中,獲 取cpu的使用權。
  • 運行(running):可運行狀態(runnable)的線程獲得了cpu時間片(timeslice),執行程序代碼。
  • **阻塞(block):**阻塞狀態是指線程因為某種原因放棄了cpu使用權,也即讓出了cpu timeslice,暫時停止運行。直到線程進入可運行(runnable)狀態,才有 機會再次獲得cpu timeslice轉到運行(running)狀態。阻塞的情況分三種:
    (一). 等待阻塞:運行(running)的線程執行o.wait()方法,JVM會把該線程放 入等待隊列(waitting queue)中。
    (二). 同步阻塞:運行(running)的線程在獲取對象的同步鎖時,若該同步鎖 被別的線程占用,則JVM會把該線程放入鎖池(lock pool)中。
    (三). 其他阻塞: 運行(running)的線程執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入可運行(runnable)狀態。
  • 死亡(dead):線程run()、main()方法執行結束,或者因異常退出了run()方法,則該線程結束生命周期。死亡的線程不可再次復生。
  • 1.44.final, finally, finalize的區別

    final

  • 修飾類 表示該類不能被繼承
  • 修飾方法 表示該方法不能被重寫
  • 修飾基本類型變量 表示該變量只能被賦值一次,如果修飾引用,那么表示引用不可變,引用指向的內容可變。
  • 被final修飾的方法,JVM會嘗試將其內聯,以提高運行效率
  • 被final修飾的常量,在編譯階段會存入常量池中。
    finally
    finally 是用于異常處理的場面,無論是否有異常拋出,都會執行
    finalize
    finalize是Object的方法,所有類都繼承了該方法。 當一個對象滿足垃圾回收的條件,并且被回收的時候,其finalize()方法就會被調用
  • 1.45. Java 中的異常處理


    祖先java.lang包中的 Throwable類。Throwable: 有兩個重要的子類:Exception(異常) 和 Error(錯誤) ,二者都是 Java 異常處理的重要子類,各自都包含大量子類。

  • Error(錯誤):是程序無法處理的錯誤,表示運行應用程序中較嚴重問題。大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時 JVM(Java 虛擬機)出現的問題。例如,Java虛擬機運行錯誤(Virtual MachineError),當 JVM 不再有繼續執行操作所需的內存資源時,將出現 OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止。

  • Exception(異常):是程序本身可以處理的異常。 Exception 類有一個重要的子類 RuntimeException。RuntimeException 異常由Java虛擬機拋出。NullPointerException(要訪問的變量沒有引用任何對象時,拋出該異常)、ArithmeticException(算術運算異常,一個整數除以0時,拋出該異常)和 ArrayIndexOutOfBoundsException (下標越界異常)。

  • Throwable類常用方法
    1. public string getMessage():返回異常發生時的詳細信息
    2. public string toString():返回異常發生時的簡要描述
    3. public void printStackTrace():在控制臺上打印Throwable對象封裝的異常信息

  • 異常處理總結
    try 塊: 用于捕獲異常。其后可接零個或多個catch塊,如果沒有catch塊,則必須跟一個finally塊。
    catch 塊:用于處理try捕獲到的異常。
    finally 塊: 無論是否捕獲或處理異常,finally塊里的語句都會被執行。當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行

  • 在以下4種特殊情況下,finally塊不會被執行:

  • 在finally語句塊中發生了異常。
  • 在前面的代碼中用了System.exit()退出程序。
  • 程序所在的線程死亡。
  • 關閉CPU。
  • 1.46. 說出最常見到的runtime exception與Error

  • NullPointerException (空指針異常)
  • ArrayIndexOutOfBoundsException(數組下標越界)
  • IllegalArgumentException (參數錯誤)
  • ArithmeticException 算術異常,比如除數為零
  • ClassCastException 類型轉換異常
  • error

    1. OutOfMemoryError (堆內存溢出) 2. StackOverflowError(棧內存溢出)

    1.47 java中有幾種類型的流?

    Java中所有的流都是基于字節流,所以最基本的流是 字節流

  • 輸入輸出字節流
    InputStream OutputStream
  • 字符流
    在字節流的基礎上,封裝了字符流
    Reader Writer
  • 緩存流
    進一步,又封裝了緩存流
    BufferedReader PrintWriter
  • 數據流
    DataInputStream DataOutputStream
  • 對象流
    ObjectInputStream ObjectOutputStream
  • 1.48. 獲取用鍵盤輸入常用的的兩種方法

    方法1:通過 Scanner

    Scanner input = new Scanner(System.in); String s = input.nextLine(); input.close();

    方法2:通過 BufferedReader

    BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); String s = input.readLine();

    1.49. Java創建對象有幾種方式?

    java中提供了以下四種創建對象的方式:

    • new創建新對象
    • 通過反射機制
    • 采用clone機制
    • 通過序列化機制

    1.50. Java反射

  • java反射是什么
    編譯期和運行期,編譯期就是編譯器幫你把源代碼翻譯成機器能識別的代碼,比如編譯器把java代碼編譯成jvm識別的字節碼文件,而運行期指的是將可執行文件交給操作系統去執行,JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制
    2. java反射(Reflection)的底層實現原理
    Object 類,是所有Java 類的繼承根源,其內聲明了數個應該在所有Java 類中被改寫的方法:其中getClass()返回一個Class 對象
  • 而這個Class 類十分特殊。它和一般類一樣繼承自Object,當一個class被加載,或當加載器(class loader)的defineClass()被JVM調用,JVM 便自動產生一個Class 對象。
    這邊列了下Class類其中的方法

    獲取公共構造器 getConstructors()
    獲取所有構造器 getDeclaredConstructors()
    獲取該類對象 newInstance()
    獲取類名包含包路徑 getName()
    獲取類名不包含包路徑 getSimpleName()
    獲取類公共類型的所有屬性 getFields()
    獲取類的所有屬性 getDeclaredFields()
    獲取類公共類型的指定屬性 getField(String name)
    獲取類全部類型的指定屬性 getDeclaredField(String name)
    獲取類公共類型的方法 getMethods()
    獲取類的所有方法 getDeclaredMethods()
    獲得類的特定公共類型方法: getMethod(String name, Class[] parameterTypes)
    獲取內部類 getDeclaredClasses()
    獲取外部類 getDeclaringClass()
    獲取修飾符 getModifiers()
    獲取所在包 getPackage()
    獲取所實現的接口 getInterfaces()

  • 創建反射實例的三種方式。
  • 直接通過類名點.class獲取
  • 通過Object類的getClass方法來獲取 通過Object類的getClass方法來獲取
  • 通過全類名獲取用的比較多推薦使用 例如:Class.forName(“com.mysql.jdbc.Driver”);
  • 1.51. 反射中,Class.forName和classloader的區別。

    java中class.forName()和classLoader都可用來對類進行加載。
    class.forName()前者除了將類的.class文件加載到jvm中之外,還會對類進行解釋,執行類中的static塊。
    而classLoader只干一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊。

    1.52. 什么是序列化?序列化有什么好處。

    1. 序列化是干什么的?
    簡單說就是將內存中的對象保存下來,并且可以把保存的對象狀態再讀出來。
    實現java序列化的手段是讓該類實現接口 Serializable,這個接口是一個標識性接口,沒有任何方法,僅僅用于表示該類可以序列化。
    2. 什么情況下需要序列化
      當你想把的內存中的對象保存到一個文件中或者數據庫中時候;
      當你想用序列化在網絡上傳送對象的時候;
      當你想通過RMI傳輸對象的時候;

  • **相關注意事項 **
    a)當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable接口;
     把一個對象完全轉成字節序列,方便傳輸。
    就像你寄一箱餅干,因為體積太大,就全壓成粉末緊緊地一包寄出去,這就是序列化的作用。
    只不過JAVA的序列化是可以完全還原的。
  • 1.53. Java序列話中如果有些字段不想進行序列化 怎么辦?

    對于不想進行序列化的變量,使用transient關鍵字修飾。

    transient關鍵字的作用是:阻止實例中那些用此關鍵字修飾的的變量序列化;當對象被反序列化時,被transient修飾的變量值不會被持久化和恢復。transient只能修飾變量,不能修飾類和方法。

    1.54. java拷貝

    淺拷貝與深拷貝
    看了很多文章,有些說淺拷貝只是拷貝引用地址,深拷貝才拷貝具體應用的對象,但經過LZ的核實發現有些文章個人感覺對拷貝的理解不是很正確。
    總結了一下
    淺拷貝
    只復制一個對象與對象內部的基本類型,對象內部存在的指向其他對象數組或者引用則不復制
    深拷貝
    深拷貝:對象,對象內部的引用均復制
    拷貝的幾種方法

    • System.arraycopy(淺拷貝)
    public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length); 通過源代碼我們可以看到,關鍵字native說明它不是用java語言寫的,而是調用其他語言的代碼。
    • Arrays.copyOf(淺拷貝)
      實際上它調用的就是System.arraycopy.
    • Object.clone
      clone()比較特殊,對于對象而言,它是深拷貝,但是對于數組而言,它是淺拷貝。

    (二)基礎相關面試題

    2.1. Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

    Math.round 的意思是+0.5 取整數
    所以 Math.round(11.5) 即 11.5+0.5 = 12
    Math.round(-11.5) 即 -11.5+0.5 = -11

    2.2. String s = new String(“xyz”);創建了幾個String Object?

    String s = new String(“xyz”);
    首先構造方法 new String(“xyz”); 中的"xyz" 這本身就是一個字符串對象
    然后 new 關鍵字一定會創建一個對象
    所以總共創建了兩個String對象

    2.3. &和&&的區別

    & 和 && 分別表示長路與和短路與
    長路:兩側,都會被運算
    短路: 只要第一個是false,第二個就不進行運算了

    2.4. 以下代碼會輸出什么

    題1

    public class Main {public static void main(String[] args) {Integer i1 = 100;Integer i2 = 100;Integer i3 = 200;Integer i4 = 200;System.out.println(i1==i2);System.out.println(i3==i4);} }

    運行結果為 true false
    原因:輸出結果表明i1和i2指向的是同一個對象,而i3和i4指向的是不同的對象 ,Integer的緩沖池如果數值在[-128,127]之間直接是從緩沖池中取得,所以是同一個對象。

    題2:

    public class Main {public static void main(String[] args) {Double i1 = 100.0;Double i2 = 100.0;Double i3 = 200.0;Double i4 = 200.0;System.out.println(i1==i2);System.out.println(i3==i4);} }

    運行結果為 false false
    原因: 在某個范圍內的整型數值的個數是有限的,而浮點數卻不是,故每個double對象指向一個新的地址。

    2.5. 3*0.1 == 0.3返回值是什么?

    返回結果為false,因為浮點數不能完全精確的表示出來,在計算機中浮點數的表示是誤差的。所以一般情況下不進行兩個浮點數是否相同的比較。

    2.6. a=a+b與a+=b有什么區別嗎?

    以下代碼是否有錯,有的話怎么改?

    short s1= 1; s1 = s1 + 1;

    有錯誤.short類型在進行運算時會自動提升為int類型,也就是說 s1+1 的運算結果是int類型,而s1是
    short類型,此時編譯器會報錯

    正確寫法:

    short s1= 1; s1 += 1;

    結論:+= 操作符會進行隱式自動類型轉換,此處a+=b隱式的將加操作的結果類型強制轉換為持有結果的類
    型,而a=a+b則不會自動進行類型轉換.

    2.7 try catch finally,try里有return,finally還執行么?

    執行,并且finally的執行早于try里面的return

    2.8 說說你平時是怎么處理 Java 異常的

    使用 try-catch-finally

    • try 塊負責監控可能出現異常的代碼
    • catch 塊負責捕獲可能出現的異常,并進行處理
    • finally塊負責清理各種資源,不管是否出現異常都會執行
    • 其中 try 塊是必須的,catch 和 finally 至少存在一個標準異常處理流程

    版權聲明:本文為博主原創文章,未經博主允許不得轉載
    https://blog.csdn.net/qq_44614710/article/details/113698325

    總結

    以上是生活随笔為你收集整理的java面试题-基础篇(万字总结,带答案,面试官问烂,跳槽必备)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。