java array 元素的位置_Java常见面试题 非常实用「个人经验」
Java 容器都有哪些
- Collection 的子類 List、Set
- List 的子類 ArrayList、LinkedList等
- Set 的子類 HashSet、TreeSet等
- Map 的子類 HashMap、TreeMao等
Collecion 和 Collections 有什么區別
- java.util,Collection 是一個集合的頂級接口,它提供了對集合對象進行基本操作的通用接口方法,Collection 接口的意義是為各種具體的集合提供了最大化的統一操作方式,其直接繼承接口的有 List 和 Set
- java.util.Collections 是一個包裝類(工具類),它包含了各種有關集合操作的靜態多態方法。此類不能被實例化,用于對集合中元素進行排序、搜索以及線程安全等各種操作,服務于 Java 的 Collection 框架
List、Set、Map 之間的區別
- List、Set 都繼承 Collection 接口,而 Map 則不是
- List 是一個有序集合,元素可重復,可有多個NULL值。可以使用各種循環遍歷集合,因為它是有序的
- Set 是一個無序集合,元素不可重復,重復元素會被覆蓋掉(注意:元素雖然無放入順序,但元素在 Set 中的位置是由該元素的 HashCode 決定的,其位置是固定的,加入 Set 的 Object 必須定義 equals()方法),Set 只能用迭代,因為它是無序的
- Map 是由一系列鍵值對組成的集合,提供了 key 和 value 的映射。在 Map 中保證 key 與 value 一一對應的關系。一個 key 對應一個 value ,不能存在相同的 key,但 value 可以相同
- Set 與 List 相比較
- Map 適合存儲鍵值對的數據
HashMap 和 HashTable 的區別
- HashTable 繼承自 Dictionary 類
- HashMap 繼承自 AbstractMap 類
- HashMap 在缺省的情況下是非Synchronize的
- HashTable 的方法是Synchronize的
- 在多線程下直接使用 HashTable 不需要自己為它的方法實現同步。但使用 HashMap 時需要手動增加同步處理Map m = Collections.synchronizeMap(hashMap);
- HashMap 把 HashTable 的 contains() 方法去掉了,改成了 containsValue() 和 containsKey(),因為 contains 容易讓人誤解
- HashTable 則保留了 contains()、containsValue()、containsKey() 三個方法,其中 contains() 與 containsValue() 功能相同
- HashTable 中,key 和 value 都不能為 null 值
- HashMap 中,null 作為鍵,但這樣的鍵只有一個。可以有多個 value 為 null 值的鍵。當 get() 方式返回 null 有可能是 HashMap 中沒有該鍵,也有可能返回的 value 為 null。所以 HashMap 用containsKey()方法判斷是否存在鍵
- HashTable 與 HashMap 都是使用 Iterator 迭代器遍歷,而由于歷史的原因,HashTable 還使用了 Enumeration 的方式
- 哈希值的使用不同,HashTable直接使用對象的HashCode,而 HashMap 重新計算哈希值
- hashCode是jdk根據對象的地址或者字符串或者數字算出來的int類型的數值
- HashTable 使用的取模運算
- HashMap 使用的與運算,先用 hash & 0x7FFFFFFF 后,再對 length 取模,&0x7FFFFFFF 的目的是為了將負的 hash 值轉化為正值,因為 hash 值有可能為負數,而 &0x7FFFFFFF 后,只有符號外改變,而后面的位都不變
- HashTable 在不指定容量的情況下默認是11,而 HashMap 為16,HashTable 不要求底層數組的容量一定要是2的整數次冪,而 HashMap 底層數組則一定為2的整數次冪
- HashTable 擴容時,將容量變成原來的2倍+1 (old * 2 + 1),而 HashMap 則直接改為原來的2倍 (old * 2)
如何決定使用 HashMap 還是 TreeMap
- 如果需要得到一個有序的 Map 集合就應該使用 TreeMap (因為 HashMap 的排序順序不是固定的)除此之外,由于 HashMap 有比 TreeMap 更好的性能,在不需要使用排序的情況下使用 HashMap 會更好
HashMap 的實現原理
- 利用key的hashCode重新hash計算出當前對象的元素在數組中的下標 存儲時,如果出現hash值相同的key,此時有兩種情況。(1)如果key相同,則覆蓋原始值;(2)如果key不同(出現沖突),則將當前的key-value放入鏈表中 獲取時,直接找到hash值對應的下標,在進一步判斷key是否相同,從而找到對應值。 理解了以上過程就不難明白HashMap是如何解決hash沖突的問題,核心就是使用了數組的存儲方式,然后將沖突的key的對象放入鏈表中,一旦發現沖突就在鏈表中做進一步的對比。
HashSet 的實現原理
- HashSet 實際上是一個 HashMap 實例,都是一個存放鏈表的數組。它不保證存儲元素的迭代順序;此類允許使用 null 元素。HashSet 中不允許有重復元素,這是因為 HashSet 是基于 HashMap 實現的,HashSet 中的元素都存放在 HashMap 的 key 上面,而 value 中的值都是統一的一個固定對象 private static final Object PRESENT = new Object();
- HashSet 中 add() 方法調用的是底層 HashMap 中的 put() 方法,而如果是在 HashMap 中調用 put() ,首先會判斷 key 是否存在,如果 key 存在則修改 value 值,如果 key 不存在這插入這個 key-value。而在 set 中,因為 value 值沒有用,也就不存在修改 value 值的說法,因此往 HashSet 中添加元素,首先判斷元素(也就是key)是否存在,如果不存在這插入,如果存在著不插入,這樣 HashSet 中就不存在重復值。所以判斷 key 是否存在就要重寫元素的類的 equals() 和 hashCode() 方法,當向 Set 中添加對象時,首先調用此對象所在類的 hashCode() 方法,計算次對象的哈希值,此哈希值決定了此對象在Set中存放的位置;若此位置沒有被存儲對象則直接存儲,若已有對象則通過對象所在類的 equals() 比較兩個對象是否相同,相同則不能被添加。
ArrayList 與 LinkList 的區別是什么
如何實現數組與 List 之間的轉換
- List to Array : 可以使用 List 的 toArray() 方法,傳入一個數組的類型例如 Stirng[] strs = strList.toArray(new String[strList.size()]);
- Array to List : 可以使用 java.util.Arrays 的 asList()方法 例如 List strList = Arrays.asList(strs);
ArrayList 與 Vector 的區別是什么
- ArrayList 是非線程安全的,而 Vector 使用了 Synchronized 來實現線程同步的
- ArrayList 在性能方面要優于 Vector
- ArrayList 和 Vector 都會根據實際情況來動態擴容的,不同的是 ArrayList 擴容到原大小的1.5倍,而 Vector 擴容到原大小的2倍
Array 與 ArrayList 有什么區別
- Array 是數組,當定義數組時,必須指定數據類型及數組長度
- ArrayList 是動態數組,長度可以動態改變,會自動擴容,不使用泛型的時候,可以添加不同類型元素
在 Queue 中 poll() 與 remove() 有什么區別
- poll() 和 remove() 都是從隊列頭刪除一個元素,如果隊列元素為空,remove() 方法會拋出NoSuchElementException異常,而 poll() 方法只會返回 null
哪些集合類是線程安全的
迭代器 Iterator 是什么
- Iterator 是集合專用的遍歷方式
- Iterator iterator() : 返回此集合中元素的迭代器,通過集合的iterator()方法得到,所以Iterator是依賴于集合而存在的
Iterator 怎么使用 ? 有什么特點
Iterator 的使用方法
- java.lang.Iterable 接口被 java.util.Collection 接口繼承,java.util.Collection 接口的 iterator() 方法返回一個 Iterator 對象
- next() 方法獲取集合中下一個元素
- hasNext() 方法檢查集合中是否還有元素
- remove() 方法將迭代器新返回的元素刪除
Iterator 的特點
- Iterator 遍歷集合過程中不允許線程對集合元素進行修改
- Iterator 遍歷集合過程中可以用remove()方法來移除元素,移除的元素是上一次Iterator.next()返回的元素
- Iterator 的next()方法是通過游標指向的形式返回Iterator下一個元素
Iterator 與 LinkIterator 有什么區別
- 使用范圍不同
怎么確保一個集合不能被修改
- 可以采用 java.util.Collections 工具類
- Collections.unmodifiableMap(map)
- Collections.unmodifiableList(list)
- Collections.unmodifiableSet(set)
- 如諾修改則會報錯java.lang.UnsupportedOperationException
2|3多線程部分面試題
并發和并行有什么區別
- 并發:不同的代碼塊交替執行
- 并行:不同的代碼塊同時執行
- 個人理解
線程和進程的區別
- 根本區別 :進程是操作系統資源分配的基本單位,而線程是任務調度和執行的基本單位
- 在操作系統中能同時運行多個進程,進程中會執行多個線程
- 線程是操作系統能夠進行運算調度的最小單位
守護線程是什么
- JVM內部的實現是如果運行的程序只剩下守護線程的話,程序將終止運行,直接結束。所以守護線程是作為輔助線程存在的
創建線程有哪幾種方式
- 定義Thread類的子類,并重寫該類的run()方法
- 創建Thread子類的實例,即創建了線程對象
- 調用線程對象的start()方法來啟動該線程
- 創建runnable接口的實現類,并重寫該接口的run()方法
- 創建Runnable實現類的實例,并依此實例作為Thread的target來創建Thread對象,該 Thread對象才是真正的線程對象
- 調用線程對象的start()方法來啟動該線程
- 創建Callable接口的實現類,并重寫call()方法,該call()方法將作為線程執行體,并且有返回值
- 創建Callable實現類的實例,使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的返回值
- 使用FutureTask對象作為Thread對象的target創建并啟動新線程
- 調用FutureTask對象的get()方法來獲得子線程執行結束后的返回值
怎么驗證 MySQL 的索引是否滿足需求
- 使用explain函數驗證索引是否有效
事務的隔離級別
MySQL 常用的引擎
InnoDB 和 Myisam 都是用 B+Tree 來存儲數據的
MySQL 的行鎖、表鎖、頁鎖
- 行級鎖
是Mysql中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加鎖。行級鎖能大大減少數據庫操作的沖突。其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分為共享鎖 和 排他鎖。
- 行級鎖的特點
開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,并發度也最高。
- 表級鎖
表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支持。最常使用的MYISAM與INNODB都支持表級鎖定。表級鎖定分為表共享讀鎖(共享鎖)與表獨占寫鎖(排他鎖)
- 表級鎖的特點
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖沖突的概率最高,并發度最低。
- 頁級鎖
頁級鎖是MySQL中鎖定粒度介于行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但沖突多,行級沖突少,但速度慢。所以取了折衷的頁級,一次鎖定相鄰的一組記錄。BDB支持頁級鎖
- 頁級鎖的特點
開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般
- 擴展
樂觀鎖和悲觀鎖
MySQL 問題排查都有哪些手段
- 使用 show processlist 命令查看當前所有連接信息
- 使用 explain 命令查詢 SQL 語句執行計劃
- 開啟慢查詢日志,查看慢查詢的 SQL
如何做 MySQL 的性能優化
2|7Redis部分面試題
Redis 是什么?有什么優點?都有哪些使用場景
- Reids 是完全開源免費的,用C語言編寫的,遵守BSD協議, 是一個高性能的(key/value)分布式內存數據庫,基于內存運行 并支持持久化的NoSQL數據庫,是當前最熱門的NoSql數據庫之一, 也被人們稱為數據結構服務器
- 優點
- 應用場景
Redis 為什么是單線程的
- Redis是基于內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬。既然單線程容易實現,而且CPU不會成為瓶頸
Redis 的緩存預熱
redis 緩存雪崩是什么,怎么解決 ?
緩存雪崩是指,緩存層出現了錯誤,不能正常工作了.于是所有的請求都會達到存儲層,存儲層的調用量會暴增,造成存儲層也會掛掉的情況.
解決方案
緩存穿透是什么?如何解決
就是訪問redis數據庫,查不到數據,就是沒有命中,會去持久化數據庫查詢,還是沒有查到.假如高并發的情況下,持久化數據庫一下增加了很大壓力,就相當于出現了緩存穿透
解決方案
Redis 支持的數據類型有哪些
- String、List、Set、Hash、ZSet這5種
Redis 支持的 Java 客戶端有哪些
- Redisson、Jedis、lettuce 等等,官方推薦使用 Redisson
Jedis 與 Redisson 有哪些區別
- Jedis 和 Redisson 都是Java中對Redis操作的封裝。Jedis 只是簡單的封裝了 Redis 的API庫,可以看作是Redis客戶端,它的方法和Redis 的命令很類似。Redisson 不僅封裝了 redis ,還封裝了對更多數據結構的支持,以及鎖等功能,相比于Jedis 更加大。但Jedis相比于Redisson 更原生一些,更靈活
怎么保證緩存與數據庫數據的一致性
Redis 持久化有幾種方式
- 快照方式(RDB, Redis DataBase)將某一個時刻的內存數據,以二進制的方式寫入磁盤
- 文件追加方式(AOF, Append Only File),記錄所有的操作命令,并以文本的形式追加到文件中
- 混合持久化方式,Redis 4.0 之后新增的方式,混合持久化是結合了 RDB 和 AOF 的優點,在寫入的時候,先把當前的數據以 RDB 的形式寫入文件的開頭,再將后續的操作命令以 AOF 的格式存入文件,這樣既能保證 Redis 重啟時的速度,又能簡單數據丟失的風險
Redis 怎么實現分布式鎖
- SET key value [EX seconds] [PX milliseconds] [NX|XX]
- EX second :設置鍵的過期時間為second秒
- PX millisecond :設置鍵的過期時間為millisecond毫秒
- NX :只在鍵不存在時,才對鍵進行設置操作
- XX :只在鍵已經存在時,才對鍵進行設置操作
- SET操作成功完成時,返回OK ,否則返回nil
Redis 分布式鎖有什么缺陷
- 設置鎖的過期時間,且需要保證setNx和設置過期時間操作的原子性
- 加鎖時記錄當前線程ID,解鎖時判斷ID是否一致
- 解鎖時,查詢redis里記錄鎖的ID,以及刪除redis中鎖的記錄,這兩步操作可以使用lua腳本保持原子性
- 加鎖成功后開啟守護線程,當臨近過期時間,業務還未完成時,開始續時,重復此步驟直到業務完成
Redis 如何做內存優化
- 縮減鍵值對象:滿足業務要求下 key 越短越好;value 值進行適當壓縮
- 共享對象池:即 Redis 內部維護[0-9999]的整數對象池,開發中在滿足需求的前提下,盡量使用整數對象以節省內存
- 盡可能使用散列表(hashes)
- 編碼優化,控制編碼類型
- 控制 key 的數量
Redis 淘汰策略有哪些
- noeviction: 不刪除策略, 達到最大內存限制時, 如果需要更多內存, 直接返回錯誤信息。 大多數寫命令都會導致占用更多的內存(有極少數會例外, 如 DEL )
- allkeys-lru: 所有key通用; 優先刪除最近最少使用(less recently used ,LRU) 的 key
- volatile-lru: 只限于設置了 expire 的部分; 優先刪除最近最少使用(less recently used ,LRU) 的 key
- allkeys-random: 所有key通用; 隨機刪除一部分 key
- volatile-random: 只限于設置了 expire 的部分; 隨機刪除一部分 key
- volatile-ttl: 只限于設置了 expire 的部分; 優先刪除剩余時間(time to live,TTL) 短的key
Redis 常見的問題有哪些? 該如何解決
- 就是如果對數據有強一致性要求,不能放緩存。我們所做的一切,只能保證最終一致性
- 采取正確更新策略,先更新數據庫,再刪緩存。其次,因為可能存在刪除緩存失敗的問題,提供一個補償措施即可,例如利用消息隊列
- 利用互斥鎖,緩存失效的時候,先去獲得鎖,得到鎖了,再去請求數據庫。沒得到鎖,則休眠一段時間重試
- 采用異步更新策略,無論 Key 是否取到值,都直接返回。Value 值中維護一個緩存失效時間,緩存如果過期,異步起一個線程去讀數據庫,更新緩存。需要做緩存預熱(項目啟動前,先加載緩存)操作
- 提供一個能迅速判斷請求是否有效的攔截機制,比如,利用布隆過濾器,內部維護一系列合法有效的 Key。迅速判斷出,請求所攜帶的 Key 是否合法有效。如果不合法,則直接返回
- 給緩存的失效時間,加上一個隨機值,避免集體失效
- 使用互斥鎖,但是該方案吞吐量明顯下降
- 雙緩存。我們有兩個緩存,緩存 A 和緩存 B。緩存 A 的失效時間為 20 分鐘,緩存 B 不設失效時間。自己做緩存預熱操作(從A中讀不到,就去B讀,返回數據時需要異步啟動一個更新線程,更新線程同時更新緩存 A 和緩存 B)
- 這種情況下,準備一個分布式鎖,大家去搶鎖,搶到鎖就做 set 操作即可,比較簡單。
- 假設有一個 key1,系統 A 需要將 key1 設置為 valueA,系統 B 需要將 key1 設置為 valueB,系統 C 需要將 key1 設置為 valueC
- 期望按照 key1 的 value 值按照 valueA > valueB > valueC 的順序變化。這種時候我們在數據寫入數據庫的時候,需要保存一個時間戳。
- 系統A key 1 {valueA 3:00}
- 系統B key 1 {valueB 3:05}
- 系統C key 1 {valueC 3:10}
- 那么,假設這會系統 B 先搶到鎖,將 key1 設置為{valueB 3:05}。接下來系統 A 搶到鎖,發現自己的 valueA 的時間戳早于緩存中的時間戳,那就不做 set 操作了,以此類推。
- 其他方法,比如利用隊列,將 set 方法變成串行訪問也可以。總之,靈活變通。
2|8RabbitMQ部分面試題
RabbitMq 的使用場景有哪些
- 比如:注冊用戶、發送激活郵箱、訂單下單等
RabbitMq 有哪些重要的角色
- 生產者:消息的創建者,負責創建和推送數據到消息服務器
- 消費者:消息的接收方,負責處理數據和確認消息
- 代理:就是RabbiMQ本身,不生產不消費,只是快遞消息
RabbitMq 有哪些重要的組件
- ConnectionFactory(連接管理器):應用程序與Rabbit之間建立連接的管理器,程序代碼中使用
- Channel(信道):消息推送使用的通道
- Exchange(交換器):用于接受、分配消息
- Queue(隊列):用于存儲生產者的消息
- RoutingKey(路由鍵):用于把生成者的數據分配到交換器上
- BindingKey(綁定鍵):用于把交換器的消息綁定到隊列上
RabbitMQ的消息存儲方式
RabbitMQ 對于 queue 中的 message 的保存方式有兩種方式:disc 和 ram.如果采用disc,則需要對 exchange/queue/delivery mode 都要設置成 durable 模式. Disc 方式的好處是當 RabbitMQ 失效了, message 仍然可以在重啟之后恢復.而使用 ram 方式, RabbitMQ 處理 message 的效率要高很多, ram 和 disc 兩種方式的效率比大概是 3:1.所以如果在有其它 HA 手段保障的情況下,選用 ram 方式是可以提高消息隊列的工作效率的.
RabbitMq 中 vhost 的作用是什么
- vhost本質上是一個mini版的RabbitMQ服務器,擁有自己的隊列、綁定、交換器和權限控制
- 從 RabbitMQ 的全局角度 vhost可以作為不同權限隔離的手段(一個典型的例子,不同的應用可以跑在不同的vhost中)
RabbitMq 的消息是怎么發送的
- 生產者把生產的小心通過channel發送到Exchange上,Exchange通過綁定的router key來選擇Queue,消費者監聽到Queue上有新的消息,就消費調此消息
RabbitMq 怎么保證消息的穩定性
- 提供了事務的功能,通過將 channel 設置為 confirm(確認模式)
RabbitMq 怎么避免丟失消息
要保證消息持久化成功的條件有哪些
- 以上四個條件都滿足才能保證消息持久化成功
RabbitMq 持久化有什么缺點
- 持久化的缺點就是降低了服務器的吞吐量,因為使用的是磁盤而非內存存儲,從而降低了吞吐量。可盡量使用 ssd 硬盤來緩解吞吐量的問題
RabbitMq 有幾種廣播方式
RabbitMq 怎么實現延遲消息隊列
- 通過消息過期后進入死信交換器,再由交換器轉發到延遲消費隊列,實現延遲功能
- 使用 RabbitMQ-delayed-message-exchange 插件實現延遲功能。
RabbitMq 集群有什么用
- 高可用:某個服務器出現問題,整個 RabbitMQ 還可以繼續使用
- 高容量:集群可以承載更多的消息量。
RabbitMq 節點的類型有哪些
- 磁盤節點:消息會存儲到磁盤
- 內存節點:消息都存儲在內存中,重啟服務器消息丟失,性能高于磁盤類型
RabbitMq 集群搭建需要注意哪些問題
RabbitMq 每個節點是其他節點的完整拷貝嗎
不是
- 如果每個節點都擁有所有隊列的完全拷貝,這樣新增節點,不但沒有新增存儲空間,反而增加了更多的冗余數據
- 如果每條消息都需要完整拷貝到每一個集群節點,那新增節點并沒有提升處理消息的能力,最多是保持和單節點相同的性能甚至是更糟
RabbitMq 集群中唯一一個磁盤節點崩潰了會發生什么
- 唯一磁盤節點崩潰了,集群是可以保持運行的,但不能更改任何東西
RabbitMq 對集群停止順序有要求嗎
- RabbitMQ 對集群的停止的順序是有要求的,應該先關閉內存節點,最后再關閉磁盤節點。如果順序恰好相反的話,可能會造成消息的丟失
2|9JVM部分面試題
JVM 主要的組成部分?及其作用
JVM 運行時數據區是什么
- 堆是java對象的存儲區域,任何用new字段分配的java對象實例和數組,都被分配在堆上,java堆可用-Xms和-Xmx進行內存控制,
- 常量池:運行時常量池是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載后進入方法區的運行時常量池中存放,jdk1.7以后,運行時常量池從方法區移到了堆上
- 方法區:用于存儲已被虛擬機加載的類信息,常量,靜態變量,即是編譯器編譯后的代碼等數據
- 虛擬機棧:虛擬機棧中執行每個方法的時候,都會創建一個棧楨用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息
- 本地方法棧:與虛擬機發揮的作用相似,相比于虛擬機棧為Java方法服務,本地方法棧為虛擬機使用的Native方法服務,執行每個本地方法的時候,都會創建一個棧幀用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息
- 程序計數器:指示Java虛擬機下一條需要執行的字節碼指令
堆和棧的區別
隊列和棧是什么?有什么區別
- 隊列和棧是兩種不同的數據結構
- 隊列的插入稱為入隊,隊列的刪除稱為出隊。棧的插入稱為進棧,棧的刪除稱為出棧
- 隊列是在隊尾入隊,隊頭出隊,即兩邊都可操作。而棧的進棧和出棧都是在棧頂進行的,無法對棧底直接進行操作。
- 隊列先進先出 FIFO,棧是后進先出 LIFO
類加載器有哪些?什么是雙親委派模型
雙親委派的意思是如果一個類加載器需要加載類,那么首先它會把這個類請求委派給父類加載器去完成,每一層都是如此。一直遞歸到頂層,當父加載器無法完成這個請求時,子類才會嘗試去加載。這里的雙親其實就指的是父類,沒有mother。父類也不是我們平日所說的那種繼承關系,只是調用邏輯是這樣
類加載的執行過程
- 加載
- 鏈接
主要是為了保證加載進來的字節流符合虛擬機規范,不會造成安全錯誤,包括對于文件格式的驗證
主要是為類變量(注意,不是實例變量)分配內存,并且賦予初值。特別需要注意,初值,不是代碼中具體寫的初始化的值,而是Java虛擬機根據不同變量類型的默認初始值:8種基本類型的初值,默認為0;引用類型的初值則為null;
將常量池內的符號引用替換為直接引用的過程。在解析階段,虛擬機會把所有的類名,方法名,字段名這些符號引用替換為具體的內存地址或偏移量,也就是直接引用
- 初始化
這個階段主要是對類變量初始化,是執行類構造器的過程
怎么判斷對象是否可以收回
- 判斷對象的引用數量
- 優缺點
- 通過判斷對象的引用鏈是否可達來決定對象是否可以被回收
- 可以作為GC Root對象的對象有
Java 中有哪些引用類型
就是指在程序代碼之中普遍存在的,類似“Object obj=new Object()” 這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象實例
是用來描述一些還有用但并非必需的對象。對于軟引用關聯著的對象, 在系統將要發生內存溢出異常之前,將會把這些對象實例列進回收范圍之中進行 第二次回收。如果這次回收還沒有足夠的內存,才會拋出內存溢出異常。在 JDK 1.2 之后,提供了SoftReference 類來實現軟引用
也是用來描述非必需對象的,但是它的強度比軟引用更弱一些,被弱 引用關聯的對象實例只能生存到下一次垃圾收集發生之前。當垃圾收集器工作時, 無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象實例。在 JDK 1.2 之 后,提供了WeakReference 類來實現弱引用
也稱為幽靈引用或者幻影引用,它是最弱的一種引用關系。一個對象實例是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用 來取得一個對象實例。為一個對象設置虛引用關聯的唯一目的就是能在這個對象 實例被收集器回收時收到一個系統通知。在 JDK 1.2 之后,提供了 PhantomReference 類來實現虛引用
JVM 中垃圾回收算法
標記-清除算法采用從根集合(GC Roots)進行掃描,對存活的對象進行標記,標記完畢后,再掃描整個空間中未被標記的對象,進行回收,如下圖所示。標記-清除算法不需要進行對象的移動,只需對不存活的對象進行處理,在存活對象比較多的情況下極為高效,但由于標記-清除算法直接回收不存活的對象,因此會造成內存碎片
復制算法的提出是為了克服句柄的開銷和解決內存碎片的問題。它開始時把堆分成 一個對象 面和多個空閑面, 程序從對象面為對象分配空間,當對象滿了,基于copying算法的垃圾 收集就從根集合(GC Roots)中掃描活動對象,并將每個 活動對象復制到空閑面(使得活動對象所占的內存之間沒有空閑洞),這樣空閑面變成了對象面,原來的對象面變成了空閑面,程序會在新的對象面中分配內存
標記-整理算法采用標記-清除算法一樣的方式進行對象的標記,但在清除時不同,在回收不存活的對象占用的空間后,會將所有的存活對象往左端空閑空間移動,并更新對應的指針。標記-整理算法是在標記-清除算法的基礎上,又進行了對象的移動,因此成本更高,但是卻解決了內存碎片的問題
JVM 有哪些垃圾回收器
- 新生代收集器:Serial、ParNew、Parallel Scavenge
- 老年代收集器:CMS、Serial Old、Parallel Old
- 整堆收集器: G1
介紹一下 CMS 垃圾回收器
- CMS收集器 :一種以獲取最短回收停頓時間為目標的收集器
- 特點:基于標記-清除算法實現。并發收集、低停頓
- 應用場景:適用于注重服務的響應速度,希望系統停頓時間最短,給用戶帶來更好的體驗等場景下。如web程序、b/s服務
- CMS收集器的運行過程分為下列4步:
- CMS收集器的內存回收過程是與用戶線程一起并發執行的
- CMS收集器的缺點:
- 對CPU資源非常敏感
- 無法處理浮動垃圾,可能出現Concurrent Model Failure失敗而導致另一次Full GC的產生
- 因為采用標記-清除算法所以會存在空間碎片的問題,導致大對象無法分配空間,不得不提前觸發一次Full GC
CMS收集器的工作過程圖:
新生代垃圾回收器和老生代垃圾回收器有哪些?有什么區別
- 新生代收集器:Serial、ParNew、Parallel Scavenge
- 老年代收集器:CMS、Serial Old、Parallel Old
- 區別:
新生代垃圾回收器一般采用的是復制算法,復制算法的優點是效率高,缺點是內存利用率低;老年代回收器一般采用的是標記-整理的算法進行垃圾回收
簡述分代垃圾回收器是怎么工作的
- 分代回收器有兩個分區:老生代和新生代,新生代默認的空間占比總空間的 1/3,老生代的默認占比是 2/3。 新生代使用的是復制算法,新生代里有 3 個分區:Eden、To Survivor、From Survivor,它們的默認占比是 8:1:1
- 執行流程
JVM 調優的工具有哪些
- jconsole jdk自帶的工具:是一個基于JMX(java management extensions)的GUI性能監測工具(jdk/bin目錄下點擊jconsole.exe即可啟動)
- VisualVM:它提供了一個可視界面,用于查看 Java 虛擬機 (Java Virtual Machine, JVM) 上運行的基于 Java 技術的應用程序(Java 應用程序)的詳細信息(jdk/bin目錄下面雙擊jvisualvm.exe既可使用)
- MAT 第三方調優工具:一個基于Eclipse的內存分析工具,是一個快速、功能豐富的Java heap分析工具,它可以幫助我們查找內存泄漏和減少內存消耗(MAT以eclipse 插件的形式來安裝)
- GChisto:專業分析gc日志的工具,可以通過gc日志來分析:Minor GC、full gc的時間、頻率等等,通過列表、報表、圖表等不同的形式來反應gc的情況(配置好本地的jdk環境之后,雙擊GChisto.jar,在彈出的輸入框中點擊 add 選擇gc.log日志)
- gcviewer:分析小工具,用于可視化查看由Sun / Oracle, IBM, HP 和 BEA Java 虛擬機產生的垃圾收集器的日志
JVM 調優的參數有哪些
2|10算法題
2|11其他部分面試題
Api 接口如何實現 ?
在類里使用 implements 關鍵字實現 Api 接口
MySQL 鏈接數據庫常用的幾種方式 ?
SpringBoot 如何集成 Redis ?
在 pom.xml 文件引入 redis 依賴
org.springframework.boot spring-boot-starter-data-redis在 application 配置文件中 書寫 redis 配置
spring.redis.host=127.0.0.1 #Redis服務器連接端口 spring.redis.port=6379 #Redis服務器連接密碼(默認為空) #spring.redis.password=SpringCloud 的優點 ?
SpringCloud 用了哪些組件 ?
List 和 Set 的區別
擴展 Map的實現類有HashMap、HashTable、TreeMap
Java 中 static 的作用
什么單例模式 ?
保證整個項目中一個類只有一個對象的實例,實現這種功能就叫做單例模式
把對象創建好,需要使用的時候直接拿到就行
等你需要的時候在創建對象,后邊就不會再次創建
SpringBoot 常用的幾個注解 ?
Java 八大數據類型
char 字符型 byte 字節型 boolean 布爾型
float 單浮點型 double 雙浮點型
int 整數型 short 短整數型 long 長整數型
MySQL分頁和升序降序如何實現 ?
select name,age,sex from t_student limit(0,5);
select name,age,sex from t_student order by age asc;
select name,age,sex from t_student order by age desc;
maven 是干什么的,它有什么好處 ?
MySQL 如何添加索引 ?
MySQL 索引的實現方式?
MySQL 索引底層的實現方式是 B+Tree也就是B+樹 具體查看 B+Tree實現方式
Vue的數據雙向綁定原理
使用v-mode屬性, 它的原理是利用了Object.defineProperty()方法重新定義了對象獲取屬性值(get)和設置屬性值(set)的操作來實現的
ActiveMQ的消息存儲方式
- 采取先進先出模式,同一時間,消息只會發送給某一個消費者,只有當該消息被消費并告知已收到時,它才能在代理的存儲中被刪除.
- 對于持久性訂閱來說,每一個消費者都會獲取消息的拷貝.為了節約空間,代理的存儲介質中只存儲了一份消息,存儲介質的持久訂閱對象為其以后的被存儲的消息維護了一個指針,消費者消費時,從存儲介質中復制一個消息.消息被所有訂閱者獲取后才能刪除.
KahaDB消息存儲
基于文件的消息存儲機制,為了提高消息存儲的可靠性和可恢復性,它整合了一個事務日志.KahaDB擁有高性能和可擴展性等特點.由于KahaDB使用的是基于文件的存儲,所以不需要使用第三方數據庫
學習沒資料,面試找不到方向怎么辦?
下面是針對一到五年開發的Java程序員整理的Java實戰視頻+電子版本書籍+面試試題資料文檔分享給大家學習!
面試試題資料及答案:
面試試題資料
電子版本書籍:
電子版本書籍
電子書
領取步驟:
1、轉發+點贊文章
2、關注我,私信“電子書”,即可免費領取
總結
以上是生活随笔為你收集整理的java array 元素的位置_Java常见面试题 非常实用「个人经验」的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 04款伊兰特1.8L手动挡暖风怎么开?
- 下一篇: 前端命名规范_前端开发工程师如何突破年薪