Java八股文


Java語言有哪些特點?

1.Java為純面向對象的語言,它能夠直接反應顯示生活中的對象。

2.具有平台無關性。Java利用Java虛擬機運行字節碼,無論是在Windows,Linux還是MacOS等其他平台對Java進程進行編譯,編譯后的程序可在其他平台運行。

3.Java為解釋型語言,編譯器吧Java代碼編譯成平台無關的中間代碼,任后在JVM上解釋運行,具有很好的可移植性。

4.Java提供了哼多內置類庫。如對多線程支持,對網絡通信支持,最重要的一點是提供了垃圾回收器。

5.Java具有較好的安全性和健壯性。Java提供了異常處理和垃圾回收機制,去除c++中難以理解的指針特性。

JDK和JRE有什么區別?

1.JDK:Java開發工具包(Java Development Kit),提供了Java開發環境和運行環境。

2.JRE:Java運行環境(Java Runtime Environment),提供了Java運行所需的環境。

3.JDK包涵了JRE,如果只運行Java程序,安裝JRE即可。要編寫Java程序需要安裝JDK。

簡述Java基礎數據類型

1.byte:占1個字節,取值范圍-128~127

2.short:占2個字節,取值范圍-2^15~(2^15)-1

3.int:占4個字節,取值范圍-2^31~(2^31)-1

4.long:占用8個字節

5.folat:占用4個字節

6.double:占用8個字節

7.char:占用2個字節

8.boolean:占用大小根據虛擬機的不同有所差異,可能(boolean數組在通過Java虛擬機編譯后使用byte數組代替)是1個字節,也可能(boolean類型通過Java虛擬機編譯后使用int類型來代替)是4個字節

簡述自動裝箱拆箱

1.對於Java基礎數據類型,均對應一個包裝類。

2.裝箱就是自動將基本數據類型轉換為包裝器類型,如int->Integer

3.拆箱就是自動將包裝器類型轉換為基本數據類型,如Integer->int

簡述Java訪問修飾符

1.default:默認訪問修飾符,在同一包內可見

2.private:在同一類內可見,不能修飾類

3.protected:對同一包類和所有子類可見,不能修飾類

4.public:對所有類可見

構造方法,成員初始化及靜態成員變量的初始化順序?

1.先后順序:靜態成員,靜態變量,構造方法。

2.詳細先后順序:父類靜態變量,父類靜態代碼塊,子類靜態變量,子類靜態代碼塊,父類靜態非靜態變量,父類非靜態代碼塊,父類構造函數,子類非靜態變量,子類非靜態代碼塊,子類構造函數。

Java代碼塊執行順序

1.父類靜態代碼塊(只執行一次)

2.子類靜態代碼塊(只執行一次)

3.父類構造代碼塊

4.父類構造函數

5.子類構造代碼塊

6.子類構造函數

7.普通代碼塊

面向對象三大特性?

1.繼承:對象的一個新類可以從現有的類中派生,派生可以從它基類那繼承方法和實例變量,且派生類可以修改或新增新的方法讓適合特殊需求。

2.封裝:將客觀事物抽象成類,每個類可以把自身的數據和方法只讓可信的類或對象操作,對不可信的進行消息隱藏

3.多態:允許不同類的對象對同一消息做出響應。對不同的對象調用相同的方法即使參數相同,最終表現的行為是不一樣的。

為什么Java語言不支持多重繼承?

1.為了程序的結構能更加清晰從而便於維護。

eg:假設Java語言支持多重繼承,類C繼承類A和類B,如果類A和B都有自定義的成員方法 f(),那么當代碼調用類C的 f()方法時就會產生二義性。

2.Java語言通過實現多個接口間接支持多從繼承,接口由於只包含方法定義,不能有方法的實現,類C繼承類A與接口B時即使它們都有方法f(),也不能直接掉用方法,需要實現具體的f()方法才能調用,不產生二意性。

3.多重繼承會使用類型轉換,構造方法的調用順序會變得復雜,會影響到性能。

 簡述Java的多態

1.Java多態可分為編譯時多態和運行時多態

2.編譯時多態主要只方法的重載,即通過參數列表的不同來區分不同的方法

3.運行時多態主要指繼承父類實現接口時,可以使用父類引用指向子類對象

3.運行時多態的實現:主要依靠方法表,方法表中最先存放的是Object類的方法,接下來是該類的父類方法,最后是該類本身的方法。

如果子類改寫了父類發方法,那么子類和父類的那些同名方法共享一個方法表項,都被認作是父類的方法,因此可以實現運行時多態。

Java提供的多態機制?

1.Java提供了兩種屬於多態的機制,分別是重載和覆蓋

2.重載:重載是指同一個類中有多個同名的方法,但這些方法有不同的參數,在編譯期間就可以確定調用哪個方法。

3.覆蓋:覆蓋是指派生類重寫基類的方法,使用基類指向其子類的實例對象,或接口的引用變量指向其實現類的實例對象,在程序調用的運行期根據引用變量所指的具體實例對象調用正在運行的那個對象的方法,即需要運行期才能調用的哪個方法。

重載與覆蓋的區別?

1.覆蓋是父類與子類間的關系,是垂直關系;重載是同一類之中方法的關系,是水平關系。

2.覆蓋只能由一個方法或一對方法產生關系;重載是多個方法之間的聯系。

3.覆蓋要求參數列表相同;重載要求參數列表不同。

4.覆蓋中,調用方法體是根據對象的類型來決定的,而重載是根據調用的時實參表與形參表來對應選擇方法體

5.重載方法可以該百年返回值的類型,覆蓋方法不能改變返回值的類型。

接口和抽象類的相同點和不同點?

相同點:

1.都不能被實例化

2.接口的實現類或抽象類的子類需實現接口或抽象類中相應的方法才能被實例化

不同點:

1.接口只能由方法定義,不能有方法的實現,而抽象類可以有方法的定義與實現

2.實現接口的關鍵字為implements,繼承抽象類的關鍵字為extends。

3.一個類可以實現多個接口,但只能繼承一個抽象類

4.當子類和父類之間存在邏輯上的層次結構,推薦使用抽象類,有利於功能的積累,當功能不需要,希望支持差別比較大的兩個或更多對象間特定的交互行為,推薦使用接口。使用接口能降低軟件系統的耦合度,

便於日后的維護或增加刪除方法

簡述抽象類與接口的區別

抽象類:體現的是is-a的關系。如對於 man is a person 定義為抽象類。

接口:體現的是can的關系。是作為模板是西安的。如設置接口fly,plane類和bird類均可是西安該接口。

一個類只能繼承一個抽象類,單可以實現多個接口。

簡述內部類及其作用

1.成員內部類:作為成員對象的內部類。可以訪問private及以上外部類的屬性和方法。外部類想要訪問內部類屬性或者方法時,必須創建一個內部類對象,然后通過該對象方位內部類的屬性和方法。外部類也可訪問private修飾的內部類屬性

2.局部內部類:存在於方法之中的內部類。訪問權限類似局部變量,只能訪問外部類的final變量

3.匿名內部類:只能使用一次,沒有類名,只能訪問外部類的final變量。

4.靜態內部類:類似類的靜態成員變量

Java語言中關鍵字static的作用是什么

static 的主要作用有哪兩個:

1.為某種特定數據類型或對象分配與創建對象個數無關的單一存儲空間

2.使得某個方法或屬性與類而不是和對象關聯在一起,即在不創建對象的情況下可通過直接調用方法或使用類的屬性。

具體而言static又可以分為4中使用方式:

1.修飾成員變量。用static關機字修飾靜態變量子啊內存中只有一個副本。只要靜態變量所在的類被加載,這個靜態變量就會被分配空間,可以使用’類.靜態變量‘和’對象.靜態變量‘的方法使用。

2.修飾成員方法。用static修飾的方法無需創建對象就可以被調用。static方法中不能使用this和super關鍵字,不能調用非static方法,只能調用所屬類的靜態成員和靜態成員方法。

3.修飾代碼塊。JVM在加載類的時候會執行static代碼塊。static代碼塊常用於初始化靜態變量。static代碼塊只會被執行一次。

4.修飾內部類。static內部類可以不用依賴外部類實例對象而被實例化。靜態內部類不能與外部類有相同的名字,不能訪問普通成員變量,只能訪問外部類中的靜態成員和靜態成員方法。

為什么要不啊String設計為不可變?

1.節省空間:字符串常量儲存在JVM的字符串池中可以被用戶共享。

2.提高效率: String 可以被不同線程共享,是線程安全的。在涉及多線程的操作中不需要同步操作。

3.安全:String 常被用於用戶名,密碼,文件名等使用,由於其不可變,可避免黑客行為對其的惡意修改。

簡述String/StringBuffer 與StringBuilder

1.String類采用利用final修飾的字符數組進行字符串保存,因此不可變。如果對String類型對象修改,需要新建對象,將老的字符和新增加的字符一並存進去。

2.StringBuilder,采用無final修飾的字符數組進行保存,因此可變,但線程不安全。

3.StringBuffer,采用無final修飾的字符數組進行保存,可以理解為實現線程安全的StringBulider。

判等運算符==和equals的區別?

==比較的是引用,equals比較的是內容。

1.如果變量是基礎數據類型,==用於比較其對應值是否相等。如果變量指向的是對象,==用於比較兩個對象是否指向同一塊存儲空間。

2.equals 是Object類提供的方法之一,每個Java 類都繼承自Object類,所以每個對象都有equals這個方法。

Object類中定義的equals方法內部都是直接調用==比較對象的。但通過覆蓋的方法可以讓它不是比較引用地址而是比較數據內容。

簡述Object類常用方法

1.hasCode:通過對象計算出的散列碼。用於map型或equals()方法。需要保證同一個對象多次調用該方法,總返回相同的整型值。

2.equals:判斷兩個對象是否一致。需保證equals方法相對應的對象hashCode也相同。

3.toString:用字符串表示對象

4.clone:深拷貝一個對象

Java 中一維數組和二維數組的聲明方式?

一維數組的聲明方式:

type arrayName[] type[] arrayName 

二維數組的聲明方式:

type arrayName[][] type[][] arrayName type[] arrayName[] 

其中 type 為基本數據類型或類,arrayName 為數組名字

簡述 Java 異常的分類

Java 異常分為 Error(程序無法處理的錯誤),和 Exception(程序本身可以處理的異常)。這兩個類均繼承 Throwable。

Error 常見的有 StackOverFlowError、OutOfMemoryError 等等。

Exception 可分為運行時異常和非運行時異常。對於運行時異常,可以利用 try catch 的方式進行處理,也可以不處理。對於非運行時異常,必須處理,不處理的話程序無法通過編譯。

簡述 throw 與 throws 的區別

throw 一般是用在方法體的內部,由開發者定義當程序語句出現問題后主動拋出一個異常。

throws 一般用於方法聲明上,代表該方法可能會拋出的異常列表。

出現在 Java 程序中的 finally 代碼塊是否一定會執行?

當遇到下面情況不會執行。

  • 當程序在進入 try 語句塊之前就出現異常時會直接結束。
  • 當程序在 try 塊中強制退出時,如使用 System.exit(0),也不會執行 finally 塊中的代碼。

其它情況下,在 try/catch/finally 語句執行的時候,try 塊先執行,當有異常發生,catch 和 finally 進行處理后程序就結束了,當沒有異常發生,在執行完 finally 中的代碼后,后面代碼會繼續執行。值得注意的是,當 try/catch 語句塊中有 return 時,finally 語句塊中的代碼會在 return 之前執行。如果 try/catch/finally 塊中都有 return 語句,finally 塊中的 return 語句會覆蓋 try/catch 模塊中的 return 語句。

final、finally 和 finalize 的區別是什么?

  • final 用於聲明屬性、方法和類,分別表示屬性不可變、方法不可覆蓋、類不可繼承。
  • finally 作為異常處理的一部分,只能在 try/catch 語句中使用,finally 附帶一個語句塊用來表示這個語句最終一定被執行,經常被用在需要釋放資源的情況下。
  • finalize 是 Object 類的一個方法,在垃圾收集器執行的時候會調用被回收對象的 finalize()方法。當垃圾回收器准備好釋放對象占用空間時,首先會調用 finalize()方法,並在下一次垃圾回收動作發生時真正回收對象占用的內存。

簡述泛型

泛型,即“參數化類型”,解決不確定對象具體類型的問題。在編譯階段有效。在泛型使用過程中,操作的數據類型被指定為一個參數,這種參數類型在類中稱為泛型類、接口中稱為泛型接口和方法中稱為泛型方法。

簡述泛型擦除

Java 編譯器生成的字節碼是不包涵泛型信息的,泛型類型信息將在編譯處理是被擦除,這個過程被稱為泛型擦除。

簡述注解

Java 注解用於為 Java 代碼提供元數據。作為元數據,注解不直接影響你的代碼執行,但也有一些類型的注解實際上可以用於這一目的。

其可以用於提供信息給編譯器,在編譯階段時給軟件提供信息進行相關的處理,在運行時處理寫相應代碼,做對應操作。

簡述元注解

元注解可以理解為注解的注解,即在注解中使用,實現想要的功能。其具體分為:

  • @Retention: 表示注解存在階段是保留在源碼,還是在字節碼(類加載)或者運行期(JVM 中運行)。
  • @Target:表示注解作用的范圍。
  • @Documented:將注解中的元素包含到 Javadoc 中去。
  • @Inherited:一個被@Inherited 注解了的注解修飾了一個父類,如果他的子類沒有被其他注解修飾,則它的子類也繼承了父類的注解。
  • @Repeatable:被這個元注解修飾的注解可以同時作用一個對象多次,但是每次作用注解又可以代表不同的含義。

簡述 Java 中 Class 對象

java 中對象可以分為實例對象和 Class 對象,每一個類都有一個 Class 對象,其包含了與該類有關的信息。

獲取 Class 對象的方法:

Class.forName(“類的全限定名”) 實例對象.getClass() 類名.class 

Java 反射機制是什么?

Java 反射機制是指在程序的運行過程中可以構造任意一個類的對象、獲取任意一個類的成員變量和成員方法、獲取任意一個對象所屬的類信息、調用任意一個對象的屬性和方法。反射機制使得 Java 具有動態獲取程序信息和動態調用對象方法的能力。可以通過以下類調用反射 API。

  • Class 類:可獲得類屬性方法
  • Field 類:獲得類的成員變量
  • Method 類:獲取類的方法信息
  • Construct 類:獲取類的構造方法等信息

序列化是什么?

序列化是一種將對象轉換成字節序列的過程,用於解決在對對象流進行讀寫操作時所引發的問題。序列化可以將對象的狀態寫在流里進行網絡傳輸,或者保存到文件、數據庫等系統里,並在需要的時候把該流讀取出來重新構造成一個相同的對象。

簡述 Java 序列化與反序列化的實現

序列化:將 java 對象轉化為字節序列,由此可以通過網絡對象進行傳輸。

反序列化:將字節序列轉化為 java 對象。

具體實現:實現 Serializable 接口,或實現 Externalizable 接口中的 writeExternal()與 readExternal()方法。

簡述 Java 的 List

List 是一個有序隊列,在 Java 中有兩種實現方式:

ArrayList 使用數組實現,是容量可變的非線程安全列表,隨機訪問快,集合擴容時會創建更大的數組,把原有數組復制到新數組。

LinkedList 本質是雙向鏈表,與 ArrayList 相比插入和刪除速度更快,但隨機訪問元素很慢。

Java 中線程安全的基本數據結構有哪些

  • HashTable: 哈希表的線程安全版,效率低
  • ConcurrentHashMap:哈希表的線程安全版,效率高,用於替代 HashTable
  • Vector:線程安全版 Arraylist
  • Stack:線程安全版棧
  • BlockingQueue 及其子類:線程安全版隊列

簡述 Java 的 Set

Set 即集合,該數據結構不允許元素重復且無序。Java 對 Set 有三種實現方式:

HashSet 通過 HashMap 實現,HashMap 的 Key 即 HashSet 存儲的元素,Value 系統自定義一個名為 PRESENT 的 Object 類型常量。判斷元素是否相同時,先比較 hashCode,相同后再利用 equals 比較,查詢 O(1)

LinkedHashSet 繼承自 HashSet,通過 LinkedHashMap 實現,使用雙向鏈表維護元素插入順序。

TreeSet 通過 TreeMap 實現的,底層數據結構是紅黑樹,添加元素到集合時按照比較規則將其插入合適的位置,保證插入后的集合仍然有序。查詢 O(logn)

簡述 Java 的 HashMap

JDK8 之前底層實現是數組 + 鏈表,JDK8 改為數組 + 鏈表/紅黑樹。主要成員變量包括存儲數據的 table 數組、元素數量 size、加載因子 loadFactor。HashMap 中數據以鍵值對的形式存在,鍵對應的 hash 值用來計算數組下標,如果兩個元素 key 的 hash 值一樣,就會發生哈希沖突,被放到同一個鏈表上。

table 數組記錄 HashMap 的數據,每個下標對應一條鏈表,所有哈希沖突的數據都會被存放到同一條鏈表,Node/Entry 節點包含四個成員變量:key、value、next 指針和 hash 值。在 JDK8 后鏈表超過 8 會轉化為紅黑樹。

若當前數據/總數據容量>負載因子,Hashmap 將執行擴容操作。默認初始化容量為 16,擴容容量必須是 2 的冪次方、最大容量為 1<< 30 、默認加載因子為 0.75。

為何 HashMap 線程不安全

在 JDK1.7 中,HashMap 采用頭插法插入元素,因此並發情況下會導致環形鏈表,產生死循環。

雖然 JDK1.8 采用了尾插法解決了這個問題,但是並發下的 put 操作也會使前一個 key 被后一個 key 覆蓋。

由於 HashMap 有擴容機制存在,也存在 A 線程進行擴容后,B 線程執行 get 方法出現失誤的情況。

簡述 Java 的 TreeMap

TreeMap 是底層利用紅黑樹實現的 Map 結構,底層實現是一棵平衡的排序二叉樹,由於紅黑樹的插入、刪除、遍歷時間復雜度都為 O(logN),所以性能上低於哈希表。但是哈希表無法提供鍵值對的有序輸出,紅黑樹可以按照鍵的值的大小有序輸出。

ArrayList、Vector 和 LinkedList 有什么共同點與區別?

  • ArrayList、Vector 和 LinkedList 都是可伸縮的數組,即可以動態改變長度的數組。
  • ArrayList 和 Vector 都是基於存儲元素的 Object[] array 來實現的,它們會在內存中開辟一塊連續的空間來存儲,支持下標、索引訪問。但在涉及插入元素時可能需要移動容器中的元素,插入效率較低。當存儲元素超過容器的初始化容量大小,ArrayList 與 Vector 均會進行擴容。
  • Vector 是線程安全的,其大部分方法是直接或間接同步的。ArrayList 不是線程安全的,其方法不具有同步性質。LinkedList 也不是線程安全的。
  • LinkedList 采用雙向列表實現,對數據索引需要從頭開始遍歷,因此隨機訪問效率較低,但在插入元素的時候不需要對數據進行移動,插入效率較高。

HashMap 和 Hashtable 有什么區別?

  • HashMap 是 Hashtable 的輕量級實現,HashMap 允許 key 和 value 為 null,但最多允許一條記錄的 key 為 null.而 HashTable 不允許。
  • HashTable 中的方法是線程安全的,而 HashMap 不是。在多線程訪問 HashMap 需要提供額外的同步機制。
  • Hashtable 使用 Enumeration 進行遍歷,HashMap 使用 Iterator 進行遍歷。

如何決定使用 HashMap 還是 TreeMap?

如果對 Map 進行插入、刪除或定位一個元素的操作更頻繁,HashMap 是更好的選擇。如果需要對 key 集合進行有序的遍歷,TreeMap 是更好的選擇。

HashSet 中,equals 與 hashCode 之間的關系?

equals 和 hashCode 這兩個方法都是從 object 類中繼承過來的,equals 主要用於判斷對象的內存地址引用是否是同一個地址;hashCode 根據定義的哈希規則將對象的內存地址轉換為一個哈希碼。HashSet 中存儲的元素是不能重復的,主要通過 hashCode 與 equals 兩個方法來判斷存儲的對象是否相同:

  • 如果兩個對象的 hashCode 值不同,說明兩個對象不相同。
  • 如果兩個對象的 hashCode 值相同,接着會調用對象的 equals 方法,如果 equlas 方法的返回結果為 true,那么說明兩個對象相同,否則不相同。

fail-fast 和 fail-safe 迭代器的區別是什么?

  • fail-fast 直接在容器上進行,在遍歷過程中,一旦發現容器中的數據被修改,就會立刻拋出 ConcurrentModificationException 異常從而導致遍歷失敗。常見的使用 fail-fast 方式的容器有 HashMap 和 ArrayList 等。
  • fail-safe 這種遍歷基於容器的一個克隆。因此對容器中的內容修改不影響遍歷。常見的使用 fail-safe 方式遍歷的容器有 ConcurrentHashMap 和 CopyOnWriteArrayList。

Collection 和 Collections 有什么區別?

  • Collection 是一個集合接口,它提供了對集合對象進行基本操作的通用接口方法,所有集合都是它的子類,比如 List、Set 等。
  • Collections 是一個包裝類,包含了很多靜態方法、不能被實例化,而是作為工具類使用,比如提供的排序方法:Collections.sort(list);提供的反轉方法:Collections.reverse(list)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM