1. 接口與抽象類的區(qū)別
在Java中,接口(Interface)和抽象類(Abstract Class)都是面向對象編程的重要概念泰演,它們都是用來定義抽象行為的方式恬惯,但它們在設計和使用上存在一些關鍵區(qū)別洗搂。
(1)定義和實現(xiàn):
接口:接口是一種完全抽象的類型讯沈,它只包含抽象方法(從Java 8開始,接口還可以包含默認方法和靜態(tài)方法祝迂,以及從Java 9開始睦尽,還可以包含私有方法)。接口不能包含實例字段或實例方法的具體實現(xiàn)型雳。
抽象類:抽象類是一個不完整的類当凡,它至少包含一個抽象方法,但也可以包含非抽象方法纠俭、實例字段和構造器宁玫。抽象類不能被實例化,必須被其他類繼承才能使用柑晒。
(2)繼承與實現(xiàn):
接口:一個類可以實現(xiàn)多個接口,這允許類繼承多個類型的行為眷射。接口提供了一種實現(xiàn)多重繼承的方式匙赞,而Java不支持類的多重繼承。
抽象類:一個類只能繼承自一個抽象類(除了間接繼承自Object類)妖碉。因此涌庭,抽象類在提供共享實現(xiàn)的同時,限制了類的繼承結構欧宜。
(3)設計和使用場景:
接口:接口通常用于定義對象的行為坐榆,它定義了一組方法,但不關心這些方法的具體實現(xiàn)冗茸。接口非常適合定義一組相關操作的契約席镀,而不關心這些操作是如何實現(xiàn)的。
抽象類:抽象類通常用于提供一組相關操作的共享實現(xiàn)夏漱,同時定義一些抽象方法供子類實現(xiàn)豪诲。抽象類適合在多個類之間有共享行為,但某些行為需要子類具體實現(xiàn)的情況下使用挂绰。
(4)默認方法和靜態(tài)方法:
從Java 8開始屎篱,接口可以包含默認方法和靜態(tài)方法。默認方法允許在接口中提供方法的默認實現(xiàn)葵蒂,這樣實現(xiàn)接口的類可以選擇是否覆蓋這些方法交播。靜態(tài)方法則與接口的實現(xiàn)類無關,它們可以在接口中直接調(diào)用践付。
抽象類也可以包含默認方法和靜態(tài)方法秦士,但其用途和接口中的默認方法和靜態(tài)方法有所不同。
(5)字段:
接口中只能定義常量字段(即使用public static final修飾的字段)荔仁。
抽象類可以定義實例字段和靜態(tài)字段伍宦。
(6)設計角度來說:
接口: 自上而下的設計
抽象類: 自下而上的設計
在JDK8中芽死,接口和抽象類都有了一些重要的改進和變化,主要體現(xiàn)在接口上次洼。以下是對這些改進的具體說明:
(1)接口的變化:
默認方法(Default Methods):在JDK8中关贵,接口允許定義默認方法,這些方法帶有實現(xiàn)卖毁。這使得接口可以添加新的方法揖曾,而不會破壞現(xiàn)有的實現(xiàn)類。默認方法使用default關鍵字修飾亥啦,并且可以有方法體炭剪。這使得接口更加靈活,可以在不修改現(xiàn)有類的情況下擴展接口的功能翔脱。
靜態(tài)方法(Static Methods):接口現(xiàn)在也可以包含靜態(tài)方法奴拦。靜態(tài)方法與接口的實現(xiàn)類無關,它們可以在接口中直接調(diào)用届吁。靜態(tài)方法使用static關鍵字修飾错妖,并且也只能通過接口名來調(diào)用。
方法引用:JDK8引入了方法引用疚沐,這使得可以更加簡潔地引用接口中的默認方法和靜態(tài)方法暂氯。方法引用可以用于Lambda表達式中,提供了一種更簡潔的方式來表示函數(shù)式接口的實例亮蛔。
(2)抽象類的變化:
默認方法和靜態(tài)方法:雖然抽象類本身在JDK8中沒有引入新的特性痴施,但抽象類可以包含默認方法和靜態(tài)方法。這與接口中的默認方法和靜態(tài)方法有相似之處究流,但它們的語義和使用場景是不同的辣吃。抽象類中的默認方法和靜態(tài)方法主要提供了一種在抽象類中定義共享行為的方式。
2. ArrayList底層實現(xiàn)原理(/HashSet/HashMap/TreeMap)
ArrayList 是 Java 集合框架(Java Collections Framework)中的一個核心類梯嗽,它實現(xiàn)了 List 接口齿尽,以動態(tài)數(shù)組的形式存儲元素。ArrayList 的底層實現(xiàn)基于可變大小的數(shù)組灯节,允許存儲任何類型的對象循头,包括 null。下面詳細解釋 ArrayList 的底層實現(xiàn)原理:
(1)數(shù)據(jù)結構
ArrayList 內(nèi)部使用一個 Object 類型的數(shù)組 elementData 來存儲元素炎疆。數(shù)組的大小可以根據(jù)需要動態(tài)調(diào)整卡骂。
(2) 初始化
當創(chuàng)建一個新的 ArrayList 對象時,如果不指定初始容量形入,則會使用默認的初始容量(通常是 10)全跨。
如果指定了初始容量,ArrayList 會根據(jù)這個容量來初始化內(nèi)部數(shù)組的大小亿遂。
(3)添加元素
當向 ArrayList 添加元素時浓若,首先檢查當前數(shù)組是否有足夠的空間來容納新元素渺杉。
如果有足夠的空間,則直接將新元素添加到數(shù)組的末尾挪钓。
如果空間不足是越,則需要進行擴容操作。擴容通常是通過創(chuàng)建一個新的碌上、容量更大的數(shù)組倚评,并將原數(shù)組的元素復制到新數(shù)組中來實現(xiàn)的。擴容后的數(shù)組容量通常是原容量的 1.5 倍(這個比例可能因 Java 版本和實現(xiàn)的不同而有所差異)馏予。
(4)刪除元素
當從 ArrayList 中刪除元素時天梧,需要將要刪除元素之后的所有元素向前移動一位,以填補刪除元素留下的空位霞丧。
同時呢岗,ArrayList 的 size 屬性會減一,以反映集合中元素數(shù)量的減少蛹尝。
(5)訪問元素
由于 ArrayList 內(nèi)部使用數(shù)組存儲元素敷燎,因此可以通過索引快速訪問任意位置的元素。訪問元素的時間復雜度是 O(1)箩言。
(6)容量和大小
ArrayList 的容量(capacity)是指其內(nèi)部數(shù)組的大小,而大谢澜蟆(size)是指實際存儲的元素數(shù)量陨收。
容量總是大于等于大小,當添加元素導致大小超過容量時鸵赖,ArrayList 會自動擴容务漩。
(7) 性能特點
由于 ArrayList 內(nèi)部使用數(shù)組存儲元素,因此在內(nèi)存使用上相對緊湊它褪。
添加元素到末尾的操作非常高效饵骨,時間復雜度是 O(1)。
在數(shù)組中間插入或刪除元素時茫打,由于需要移動元素居触,所以效率較低,時間復雜度是 O(n)老赤。
ArrayList 不支持并發(fā)修改轮洋,如果在迭代過程中修改了 ArrayList 的結構(如添加、刪除元素)抬旺,則會拋出 ConcurrentModificationException 異常弊予。
(8)迭代和遍歷
ArrayList 提供了多種迭代和遍歷元素的方式,包括使用迭代器(Iterator)开财、增強 for 循環(huán)(for-each loop)以及傳統(tǒng)的 for 循環(huán)汉柒。
總結
ArrayList 的底層實現(xiàn)基于可變大小的數(shù)組误褪,通過動態(tài)調(diào)整數(shù)組容量來適應元素數(shù)量的變化。它在內(nèi)存使用上相對緊湊碾褂,添加元素到末尾的操作非常高效兽间,但在中間位置插入或刪除元素時效率較低。因此斋扰,在需要頻繁在中間位置插入或刪除元素的場景中渡八,可能需要考慮使用其他數(shù)據(jù)結構或集合類,如 LinkedList传货。
3. 線程有哪幾種創(chuàng)建方式
(1)繼承Thread類創(chuàng)建線程
這是創(chuàng)建線程的一種常用方式屎鳍。你需要創(chuàng)建一個新的類,這個類繼承自Thread類问裕,然后重寫其run()方法逮壁。在run()方法中,編寫線程需要執(zhí)行的代碼粮宛。然后窥淆,創(chuàng)建這個新類的實例,并調(diào)用它的start()方法啟動線程巍杈。需要注意的是忧饭,啟動線程是通過start()方法實現(xiàn)的,而不是直接調(diào)用run()方法筷畦。
(2)實現(xiàn)Runnable接口創(chuàng)建線程
與繼承Thread類創(chuàng)建線程不同词裤,實現(xiàn)Runnable接口的方式更加靈活。因為Java不允許多繼承鳖宾,如果一個類已經(jīng)繼承了其他類吼砂,那么就不能再繼承Thread類。此時鼎文,實現(xiàn)Runnable接口是一個很好的選擇渔肩。同樣,需要重寫run()方法拇惋,并在其中編寫線程需要執(zhí)行的代碼周偎。然后,創(chuàng)建Runnable實現(xiàn)類的實例撑帖,將其作為參數(shù)傳遞給Thread類的構造器栏饮,創(chuàng)建Thread對象,再調(diào)用Thread對象的start()方法來啟動線程磷仰。
(3)實現(xiàn)Callable接口創(chuàng)建線程
Callable接口是Java 5中新增的一個接口袍嬉,它可以有返回值,并且可以聲明拋出異常。Callable接口是Functional Interface伺通,所以可以使用Lambda表達式創(chuàng)建Callable對象箍土。創(chuàng)建Callable實現(xiàn)類的實例,使用FutureTask類來包裝Callable對象罐监,該FutureTask對象封裝了該Callable對象的call()方法的返回值吴藻。使用FutureTask對象作為Thread對象的target創(chuàng)建并啟動新線程。調(diào)用FutureTask對象的get()方法來獲得子線程執(zhí)行結束后的返回值弓柱。
(4)使用線程池創(chuàng)建線程
線程池是一種多線程處理形式沟堡,處理過程中將任務添加到隊列,然后在創(chuàng)建線程后自動啟動這些任務矢空。線程池線程都是后臺線程航罗。每個線程都使用默認的ThreadFactory創(chuàng)建一個新線程。通過Executor框架的工具類Executors來實現(xiàn)屁药。
4. session和cookie的區(qū)別
(1)存儲區(qū)域與機制:
Session是服務器端的對象粥血,用于存儲和管理特定用戶會話期間的信息。當用戶訪問Web應用程序時酿箭,服務器會為每個用戶創(chuàng)建一個唯一的Session對象复亏,并為其分配一個Session ID。這個Session ID通常存儲在用戶的瀏覽器中的Cookie中缭嫡,以便在用戶的不同請求之間進行傳遞缔御。
Cookie則是一種在Web瀏覽器和服務器之間傳遞信息的機制。它是一小段文本信息妇蛀,由服務器發(fā)送到客戶端的瀏覽器刹淌,并存儲在客戶端的計算機上。瀏覽器在將來的請求中會自動將該Cookie信息包含在HTTP頭中發(fā)送回服務器讥耗。
(2)保存內(nèi)容:
Session能夠存取任何類型的數(shù)據(jù),包括用戶的登錄憑證疹启、購物車中的商品或其他自定義的用戶狀態(tài)信息古程。Session的大小沒有限制,可以存儲大量的信息喊崖。
Cookie只能保存ASCII字符串挣磨,并且其保存的內(nèi)容比Session小。如果需要存儲復雜的數(shù)據(jù)結構或大量數(shù)據(jù)荤懂,Session更為適合茁裙。
(3)有效期:
Session的有效期相對較短。一旦用戶關閉瀏覽器节仿,Session通常會失效晤锥。如果需要長期保存用戶信息话侧,則需要采用其他方法各拷,如將信息存儲在數(shù)據(jù)庫中,并在每次用戶訪問時通過Session或Cookie驗證其身份。
Cookie的有效期則相對較長原献,可以設置過期時間,使其在用戶關閉瀏覽器后仍然保留在客戶端棚品。這使得Cookie適用于需要跨多個會話或長時間保存的信息艺栈。
(4)對服務器資源的影響:
由于Session存儲在服務器端,當并發(fā)訪問用戶多時放妈,會產(chǎn)生大量的Session對象北救,占用服務器內(nèi)存資源。因此芜抒,在高并發(fā)的場景下珍策,需要合理管理Session,避免內(nèi)存溢出挽绩。
Cookie存儲在客戶端膛壹,不占用服務器資源。這使得Cookie在處理大量用戶請求時更加高效唉堪。
(5)安全性:
Session:存儲在服務器上模聋,無法偽造,因此Session的安全性相對較高唠亚。在Java中链方,Session默認是線程安全的,這意味著多個線程可以同時訪問和操作同一個Session對象灶搜,而不會導致數(shù)據(jù)錯誤或沖突祟蚀。Java Servlet容器會使用同步機制來確保多個線程之間對Session的訪問不會發(fā)生沖突。
Cookie:存儲在客戶端割卖,可以被用戶或惡意軟件篡改前酿,因此安全性相對較低。為了防止Cookie被篡改鹏溯,可以在生成Cookie時添加時間戳罢维,并使用非對稱加密算法對其進行簽名。同時丙挽,可以設置Cookie的HttpOnly屬性以防止通過JavaScript獲取Cookie的值肺孵,以及設置Secure屬性以確保Cookie只在HTTPS連接中進行傳輸。
(6)大醒詹:
Session:在Java中平窘,Session的大小沒有嚴格的限制,但它會占用服務器運行內(nèi)存凳怨。每個Session可以存儲的數(shù)據(jù)量是有限的瑰艘,如果Session中存儲的數(shù)據(jù)量過大,可能會導致內(nèi)存溢出或性能下降。因此磅叛,需要合理管理Session的大小屑咳,及時清理不再需要的數(shù)據(jù),并避免在Session中存儲大量數(shù)據(jù)弊琴。
Cookie:大多數(shù)瀏覽器支持最大為4096字節(jié)的Cookie兆龙。由于這個限制,Cookie更適合用于存儲少量數(shù)據(jù)敲董,如用戶ID之類的標識符紫皇。同時,瀏覽器還限制了每個站點可以存儲的Cookie數(shù)量腋寨,一般為20個聪铺,而瀏覽器通常對來自所有站點的Cookie總數(shù)也有一個絕對限制,通常為300個萄窜。
5.spring mvc執(zhí)行流程
Spring MVC 的執(zhí)行流程是一個相對復雜但有序的過程铃剔,它涉及多個組件的協(xié)同工作。以下是 Spring MVC 的主要執(zhí)行流程:
(1)用戶發(fā)起請求:
用戶通過瀏覽器或其他客戶端向服務器發(fā)送 HTTP 請求查刻,請求中包含 URL键兜、請求方法(GET、POST 等)穗泵、請求頭普气、請求體等信息。
(2)前端控制器(DispatcherServlet)接收請求:
Spring MVC 的前端控制器(通常是 DispatcherServlet)接收到用戶的請求佃延。DispatcherServlet 是整個 Spring MVC 流程的核心现诀,它負責協(xié)調(diào)整個流程。
(3)解析請求并確定處理器:
DispatcherServlet 根據(jù)請求的 URL 和配置的處理器映射(HandlerMapping)來確定處理該請求的處理器(通常是 Controller 中的某個方法)履肃。這個過程涉及到解析 URL仔沿、查找對應的 Handler。
(4)處理器適配器調(diào)用處理器:
確定處理器后尺棋,DispatcherServlet 會使用處理器適配器(HandlerAdapter)來調(diào)用實際的處理器(Controller 方法)封锉。處理器適配器是 DispatcherServlet 和處理器之間的橋梁,它負責將請求轉換為處理器能夠理解的格式陡鹃。
(5)處理器處理請求并返回模型視圖:
處理器(Controller)處理請求,并返回一個包含數(shù)據(jù)和視圖的模型(ModelAndView)抖坪。模型通常包含業(yè)務邏輯處理后的數(shù)據(jù)萍鲸,視圖則指定了數(shù)據(jù)的呈現(xiàn)方式。
(6)處理器適配器返回模型視圖給前端控制器:
處理器處理完畢后擦俐,處理器適配器將模型視圖返回給 DispatcherServlet脊阴。
(7)視圖解析器解析視圖:
DispatcherServlet 使用視圖解析器(ViewResolver)來解析模型視圖中的視圖部分,確定用于渲染數(shù)據(jù)的具體視圖技術(如 JSP、Thymeleaf 等)嘿期。
(8)前端控制器渲染視圖:
DispatcherServlet 將模型和解析后的視圖結合起來品擎,交給視圖進行渲染。視圖根據(jù)模型中的數(shù)據(jù)生成最終的 HTML 頁面或其他格式的響應备徐。
(9)響應返回給客戶端:
渲染完成后萄传,DispatcherServlet 將響應返回給客戶端(瀏覽器或其他客戶端),用戶看到最終的頁面或數(shù)據(jù)蜜猾。
(10)流程結束:
至此秀菱,整個 Spring MVC 的執(zhí)行流程結束。
在整個流程中蹭睡,Spring MVC 提供了豐富的擴展點衍菱,如攔截器(Interceptor)、異常處理器(ExceptionResolver)等肩豁,開發(fā)者可以根據(jù)需要定制和擴展流程中的各個環(huán)節(jié)脊串。
6. mybatis如何實現(xiàn)模糊查詢(#{}和${}區(qū)別)
#{}, 預編譯sql,使用占位符. 會自動添加引號.
${}, 靜態(tài)sql, sql注入風險, 不會自動添加引號.
#{}:先編譯sql語句,再給占位符傳值清钥,底層是PreparedStatement實現(xiàn)琼锋。可以防止sql注入循捺,比較常用斩例。
${}:先進行sql語句拼接,然后再編譯sql語句从橘,底層是Statement實現(xiàn)念赶。存在sql注入現(xiàn)象。只有在需要進行sql語句關鍵字拼接的情況下才會用到恰力。
select * from t_user where username like "%"#{name}"%". ?????
select * from t_user where username like? #{name} , ok可以使用.
select * from t_user where username like? '%${name}%' , 可以使用,但是不推薦.有sql風險.
select * from t_user where username like? concat('%', #{name}, '%') , 推薦寫法.
7. 談談你對面向切面編程(答題范圍非常廣)
面向過程 -> 面向對象 -> 面向切面
(1)面向切面編程(Aspect Oriented Programming叉谜,AOP)是一種編程范式,旨在通過預定義的方式將橫切關注點(cross-cutting concerns)模塊化踩萎,以便將它們從業(yè)務邏輯中分離出來停局。這些橫切關注點通常包括日志記錄、事務管理香府、安全控制等董栽,它們在多個地方重復出現(xiàn),但又不屬于任何特定的業(yè)務邏輯企孩。
(2)一般一個系統(tǒng)當中都會有一些系統(tǒng)服務锭碳,例如:日志、事務管理勿璃、安全等擒抛。這些系統(tǒng)服務被稱為:交叉業(yè)務
這些交叉業(yè)務幾乎是通用的推汽,不管你是做銀行賬戶轉賬,還是刪除用戶數(shù)據(jù)歧沪。日志歹撒、事務管理、安全诊胞,這些都是需要做的暖夭。
如果在每一個業(yè)務處理過程當中,都摻雜這些交叉業(yè)務代碼進去的話厢钧,存在兩方面問題:
● 第一:交叉業(yè)務代碼在多個業(yè)務流程中反復出現(xiàn)鳞尔,顯然這個交叉業(yè)務代碼沒有得到復用。并且修改這些交叉業(yè)務代碼的話早直,需要修改多處寥假。
● 第二:程序員無法專注核心業(yè)務代碼的編寫,在編寫核心業(yè)務代碼的同時還需要處理這些交叉業(yè)務霞扬。
使用AOP可以很輕松的解決以上問題糕韧。
(3)用一句話總結AOP:將與核心業(yè)務無關的代碼獨立的抽取出來,形成一個獨立的組件喻圃,然后以橫向交叉的方式應用到業(yè)務流程當中的過程被稱為AOP萤彩。
AOP的優(yōu)點:
● 第一:代碼復用性增強。
● 第二:代碼易維護斧拍。
● 第三:使開發(fā)者更關注業(yè)務邏輯雀扶。
(4)AOP的七大術語
● 連接點 Joinpoint
? ○ 在程序的整個執(zhí)行流程中,可以織入切面的位置肆汹。方法的執(zhí)行前后愚墓,異常拋出之后等位置。
● 切點 Pointcut
○ 在程序執(zhí)行流程中昂勉,真正織入切面的方法浪册。(一個切點對應多個連接點)
● 通知 Advice
○ 通知又叫增強,就是具體你要織入的代碼岗照。
○ 通知包括:
■ 前置通知
■ 后置通知
■ 環(huán)繞通知
■ 異常通知
■ 最終通知
● 切面 Aspect
? ○ 切點 + 通知就是切面村象。
● 織入 Weaving
? ○ 把通知應用到目標對象上的過程。
● 代理對象 Proxy
? ○ 一個目標對象被織入通知后產(chǎn)生的新對象攒至。
● 目標對象 Target
? ○ 被織入通知的對象厚者。
8. spring擴展接口
BeanFactory
1. FactoryBean, 將復雜對象放到容器當中,譬如說, spring 整合mybatis . getObjcet,將這個方法的返回值放到了容器當中,我們獲取的也是這個方法的返回值.
該接口允許你自定義bean的創(chuàng)建過程。
當你需要返回一個復雜對象或需要根據(jù)特定邏輯創(chuàng)建對象時迫吐,可以實現(xiàn)這個接口库菲。
2. BeanPostProcessor, 后置處理器/后置增強器.bean初始化前后對bean功能進行增強.
該接口允許你在Spring IoC容器實例化bean之后、初始化方法執(zhí)行之前或之后執(zhí)行自定義邏輯渠抹。
常見的使用場景包括AOP代理的創(chuàng)建蝙昙、日志記錄、安全檢查等梧却。
3. BeanFactoryPostProcessor, 對bean進行增強
該接口允許你在Spring IoC容器實例化bean之前奇颠,修改或重新定義bean的屬性。
常見的實現(xiàn)有PropertyPlaceholderConfigurer放航,它用于將屬性文件中的值注入到bean的屬性中烈拒。
4. ApplicationContextAware, 從容器當中獲取對象.
(5)Aware接口:
Spring提供了一系列的Aware接口(如ApplicationContextAware、BeanNameAware等)广鳍,允許bean獲取Spring容器的上下文或其他bean的元數(shù)據(jù)荆几。
這些接口通常通過依賴注入的方式與bean關聯(lián),以便bean能夠訪問容器的特定功能或信息赊时。
(6)ApplicationListener:
該接口允許你監(jiān)聽Spring容器發(fā)布的事件吨铸,并在事件發(fā)生時執(zhí)行自定義邏輯。
常見的使用場景包括監(jiān)聽容器的啟動和關閉事件祖秒、監(jiān)聽特定業(yè)務事件等诞吱。
(7)EnvironmentAware 和 ResourceLoaderAware:
這些接口允許bean訪問Spring的環(huán)境信息和資源加載器,從而能夠讀取外部配置文件或加載資源文件竭缝。
(8)MessageSource 和 MessageSourceAware:
用于國際化支持房维,允許你定義和訪問多語言環(huán)境下的消息。
(9)AspectJ的切面接口:
Spring AOP與AspectJ集成抬纸,允許你使用AspectJ的注解(如@Aspect咙俩、@Before、@After等)定義切面湿故。
這些接口和注解使得AOP編程更加靈活和強大阿趁。
(10)HandlerInterceptor:
在Spring MVC中,該接口用于定義請求處理過程中的攔截器晓锻。
你可以使用它來實現(xiàn)諸如認證歌焦、授權、日志記錄等功能砚哆。
(11)TaskExecutor:
用于定義自定義的線程池独撇,以便在Spring中執(zhí)行異步任務。
你可以實現(xiàn)這個接口或使用Spring提供的ThreadPoolTaskExecutor等實現(xiàn)類躁锁。
(12)PropertyEditor 和 CustomEditorConfigurer:
用于自定義類型轉換邏輯纷铣,允許你在Spring中將字符串轉換為自定義類型的對象。
Initializer 和 WebApplicationInitializer:
在Spring Boot和Spring MVC中战转,這些接口用于替代傳統(tǒng)的web.xml配置文件搜立,以編程方式配置Servlet容器和Spring MVC。
9. spring事務機制【重點】
● 什么是事務
○ 在一個業(yè)務流程當中槐秧,通常需要多條DML(insert delete update)語句共同聯(lián)合才能完成啄踊,這多條DML語句必須同時成功忧设,或者同時失敗,這樣才能保證數(shù)據(jù)的安全颠通。
? ○ 多條DML要么同時成功址晕,要么同時失敗,這叫做事務顿锰。
○ 事務:Transaction(tx)
● 事務的四個處理過程:
? ○ 第一步:開啟事務 (start transaction)
? ○ 第二步:執(zhí)行核心業(yè)務代碼
? ○ 第三步:提交事務(如果核心業(yè)務處理過程中沒有出現(xiàn)異常)(commit transaction)
? ○ 第四步:回滾事務(如果核心業(yè)務處理過程中出現(xiàn)異常)(rollback transaction)
● 事務的四個特性:
? ○ A 原子性:事務被視為一個最小的工作單元谨垃,其操作要么全部完成,要么全部不做硼控。即事務中的各項操作在一次執(zhí)行過程中刘陶,只允許出現(xiàn)兩種狀態(tài)之一,要么都成功牢撼,要么都失敗匙隔。任何一項操作的失敗都會導致整個事務的失敗,同時其它已經(jīng)被執(zhí)行的操作都將被撤銷并回滾熏版。只有所有的操作全部成功牡直,整個事務才算是成功完成。
? ○ C 一致性:事務必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另一個一致性狀態(tài)纳决。也就是說碰逸,一個事務執(zhí)行之前和執(zhí)行之后,數(shù)據(jù)庫都必須處于一致性狀態(tài)阔加。如果事務執(zhí)行失敗饵史,數(shù)據(jù)庫的狀態(tài)將回滾到事務開始前的狀態(tài)。
? ○ I 隔離性:在并發(fā)環(huán)境中胜榔,并發(fā)的事務是互相隔離的胳喷,一個事務的執(zhí)行不能被其它事務干擾。不同的事務并發(fā)操作相同的數(shù)據(jù)時夭织,每個事務都有各自完整的數(shù)據(jù)空間吭露。一個事務內(nèi)部的操作及使用的數(shù)據(jù)對其它并發(fā)事務是隔離的,并發(fā)執(zhí)行的各個事務是不能互相干擾的尊惰。
? ○ D 持久性:一旦事務提交讲竿,那么對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久性的。即使系統(tǒng)遇到故障弄屡,事務執(zhí)行的結果也不會丟失铜犬。
Spring實現(xiàn)事務的兩種方式
● 編程式事務
? ○ 通過編寫代碼的方式來實現(xiàn)事務的管理勺卢。
● 聲明式事務
? ○ 基于注解方式
? ○ 基于XML配置方式
事務傳播行為
什么是事務的傳播行為燥翅?
在service類中有a()方法和b()方法拿穴,a()方法上有事務,b()方法上也有事務,當a()方法執(zhí)行過程中調(diào)用了b()方法秀仲,事務是如何傳遞的融痛?合并到一個事務里?還是開啟一個新的事務神僵?這就是事務傳播行為酌心。
事務傳播行為在spring框架中被定義為枚舉類型:
一共有七種傳播行為:
● REQUIRED:支持當前事務,如果不存在就新建一個(默認)【沒有就新建挑豌,有就加入】
● SUPPORTS:支持當前事務,如果當前沒有事務墩崩,就以非事務方式執(zhí)行【有就加入氓英,沒有就不管了】
● MANDATORY:必須運行在一個事務中,如果當前沒有事務正在發(fā)生鹦筹,將拋出一個異陈敛【有就加入,沒有就拋異愁砉眨】
● REQUIRES_NEW:開啟一個新的事務徘键,如果一個事務已經(jīng)存在,則將這個存在的事務掛起【不管有沒有遍蟋,直接開啟一個新事務吹害,開啟的新事務和之前的事務不存在嵌套關系,之前事務被掛起】
● NOT_SUPPORTED:以非事務方式運行虚青,如果有事務存在它呀,掛起當前事務【不支持事務,存在就掛起】
● NEVER:以非事務方式運行棒厘,如果有事務存在纵穿,拋出異常【不支持事務奢人,存在就拋異澄矫剑】
● NESTED:如果當前正有一個事務在進行中,則該方法應當運行在一個嵌套式事務中何乎。被嵌套的事務可以獨立于外層事務進行提交或回滾句惯。如果外層事務不存在,行為就像REQUIRED一樣支救∽谕洌【有事務的話,就在這個事務里再嵌套一個完全獨立的事務搂妻,嵌套的事務可以獨立的提交和回滾蒙保。沒有事務就和REQUIRED一樣∮鳎】
事務隔離級別
事務隔離級別類似于教室A和教室B之間的那道墻邓厕,隔離級別越高表示墻體越厚逝嚎。隔音效果越好。
數(shù)據(jù)庫中讀取數(shù)據(jù)存在的三大問題:(三大讀問題)
● 臟讀:讀取到?jīng)]有提交到數(shù)據(jù)庫的數(shù)據(jù)详恼,叫做臟讀补君。
● 不可重復讀:在同一個事務當中,第一次和第二次讀取的數(shù)據(jù)不一樣昧互。
● 幻讀:讀到的數(shù)據(jù)是假的挽铁。
事務隔離級別包括四個級別:
● 讀未提交:READ_UNCOMMITTED
? ○ 這種隔離級別,存在臟讀問題敞掘,所謂的臟讀(dirty read)表示能夠讀取到其它事務未提交的數(shù)據(jù)叽掘。
● 讀提交:READ_COMMITTED
○ 解決了臟讀問題,其它事務提交之后才能讀到玖雁,但存在不可重復讀問題更扁。
● 可重復讀:REPEATABLE_READ
○ 解決了不可重復讀,可以達到可重復讀效果赫冬,只要當前事務不結束浓镜,讀取到的數(shù)據(jù)一直都是一樣的。但存在幻讀問題劲厌。
● 序列化:SERIALIZABLE
? ○ 解決了幻讀問題膛薛,事務排隊執(zhí)行。不支持并發(fā)补鼻。
平臺事務管理器TrancationManager
提交,回滾
事務定義
事務狀態(tài)
聲明式事務, rollbackfor.exception
10. 設計模式:
單例模式是一種設計模式相叁,用于限制某個類只能創(chuàng)建一個實例。這個模式常用于一些全局配置類辽幌、數(shù)據(jù)庫連接池等增淹,以確保全局只有一個實例對象。
(1)餓漢式(線程安全)
餓漢式在類加載時就完成了初始化乌企,所以類加載較慢虑润,但獲取對象的速度快。由于JVM在類加載時采用單例模式加酵,所以線程安全拳喻。
(2)懶漢式(線程不安全)
懶漢式在第一次調(diào)用getInstance()方法時才進行初始化,所以類加載較快猪腕,但獲取對象的速度稍慢冗澈。這種寫法在多線程環(huán)境下是不安全的。
(3)懶漢式(線程安全陋葡,同步方法)
為了解決懶漢式線程不安全的問題亚亲,可以在getInstance()方法上加上synchronized關鍵字,但這會導致每次調(diào)用getInstance()方法時都要進行同步,效率較低捌归。
(4)懶漢式(線程安全肛响,雙重檢查鎖定)
雙重檢查鎖定是懶漢式線程安全的推薦寫法。它只在第一次初始化時同步惜索,之后直接返回已創(chuàng)建的實例特笋,因此效率較高。但需要注意JVM的內(nèi)存模型問題巾兆,通常需要volatile關鍵字來保證多線程環(huán)境下的正確性猎物。
(5)枚舉(線程安全)
枚舉方式是單例實現(xiàn)的最佳方法。它不僅能避免多線程同步問題角塑,而且還能防止反序列化重新創(chuàng)建新的對象蔫磨。
(6)靜態(tài)內(nèi)部類(線程安全)
靜態(tài)內(nèi)部類方式同樣實現(xiàn)了懶加載,且是線程安全的吉拳。這種方式利用了類加載器的機制來保證初始化instance時只有一個線程,并且只有在第一次調(diào)用getInstance()方法時才會加載SingletonHolder類适揉,從而初始化instance留攒。
11. mybatis動態(tài)sql標簽有哪些(也可以使用mp實現(xiàn))
if標簽 需求:多條件查詢。作用:用于根據(jù)條件決定是否包含某個 SQL 片段嫉嘀。如果條件滿足炼邀,則包含該 SQL 片段;否則剪侮,忽略該片段拭宁。
where標簽的作用:讓where子句更加動態(tài)智能。
處理 SQL 語句中的 WHERE 條件瓣俯,自動添加 WHERE 關鍵字杰标,并處理多余的 AND 或 OR。
● 所有條件都為空時彩匕,where標簽保證不會生成where子句腔剂。
● 自動去除某些條件前面多余的and或or。
<choose>, <when>, <otherwise>作用:類似于 Java 中的 switch-case-default 語句驼仪,用于根據(jù)多個條件生成不同的 SQL 片段掸犬。
set標簽? ? 處理 SQL 語句中的 SET 子句,自動添加 SET 關鍵字绪爸,并處理多余的逗號湾碎。
主要使用在update語句當中,用來生成set關鍵字奠货,同時去掉最后多余的“,”
trim標簽的屬性:通用的處理標簽介褥,可以自定義前綴和后綴的添加和移除規(guī)則。
● prefix:在trim標簽中的語句前添加內(nèi)容
● suffix:在trim標簽中的語句后添加內(nèi)容
● prefixOverrides:前綴覆蓋掉(去掉)
● suffixOverrides:后綴覆蓋掉(去掉)
foreach標簽? 作用:用于處理集合類型的參數(shù),生成 IN 查詢語句或其他需要迭代集合的場景呻顽。
循環(huán)數(shù)組或集合雹顺,動態(tài)生成sql,批量刪除,批量添加
12. Servlet的體系結構
首先Servlet是一個接口,有兩個實現(xiàn)類,GenericServlet實現(xiàn)了Servlet接口,是一個抽象類,在Servlet中有五個抽象方法,GenericServlet將Servlet中的除了service之外的四個方法都做了默認空實現(xiàn)
只抽象了service一個方法,
因為在service方法中需要獲取數(shù)據(jù),而在獲取數(shù)據(jù)之前,需要判斷請求方式,所以就有了HttpServlet
HttpServlet繼承了GenericServlet,也是一個抽象類,是對http協(xié)議的一種封裝,可以簡化操作.可以定義一個類繼承httpServlet,復寫doGet/doPost方法
interface Servlet
抽象方法, 5個
abstract class GenericServlet implements Servlet
重寫了四個方法,只剩下一個抽象方法. abstract service. 如果直接使用它,則需要我們自己判斷請求方式.不是那么方便.
abstract class HttpServlet, 沒有抽象方法.
service方法 --> 成員方法 --> 根據(jù)不同的請求方式,給出不同的處理方法.在這些方法當中, 默認實現(xiàn)都拋出了異常.
強制子類去重寫這些個方法,不能直接使用父類的方法 【模板方法】
service方法 --> 重寫了Servlet當中的service()方法.
------------------------------------------------------------------------------------------
DispatcherServlet
doDispatcher, spring mvc核心方法.
13. redis數(shù)據(jù)類型有哪些, 列舉一些redis數(shù)據(jù)類型的應用場景;
九種, 常用的是五種
String(字符串):
應用場景:這是Redis最基本的數(shù)據(jù)類型廊遍,用于存儲字符串類型的數(shù)據(jù)嬉愧,如用戶信息、配置信息等喉前。String類型支持修改操作没酣,因此也可以用于實現(xiàn)計數(shù)器功能,如網(wǎng)站訪問量統(tǒng)計卵迂。驗證碼啥的
Hash(哈希):
應用場景:Hash類型是一個鍵值對的集合裕便,可以用于存儲對象的多個字段和值。這使得Hash類型非常適用于存儲用戶信息见咒、配置項等復雜數(shù)據(jù)偿衰。購物車
List(列表):
應用場景:列表是簡單的字符串列表,按照插入順序排序改览。因此下翎,它適用于實現(xiàn)消息隊列、最新消息列表等場景宝当。例如视事,可以將新發(fā)布的文章ID添加到列表中,然后按照發(fā)布順序展示給用戶庆揩。
Set(集合):
應用場景:集合是無序的字符串集合俐东,不允許重復元素。因此订晌,它適用于需要存儲唯一元素的場景虏辫,如用戶ID集合、網(wǎng)站標簽集合等锈拨。好友關注啥的.
zset, Sorted Set(有序集合):
應用場景:有序集合與集合類似乒裆,但元素是有序的,每個元素都關聯(lián)一個分數(shù)推励。這使得有序集合非常適合用于排行榜鹤耍、按分數(shù)檢索等場景。例如验辞,可以根據(jù)用戶的積分或活躍度對用戶進行排序稿黄。排行榜等
-----------------
Bitmap:
應用場景:Bitmap類型以bit為單位進行操作,提供了一種更細化的數(shù)據(jù)存儲方式跌造。它通常用于需要大量節(jié)省空間且數(shù)據(jù)狀態(tài)只有兩種(如開/關)的場景杆怕,如用戶在線狀態(tài)族购、簽到記錄等。
HyperLogLog:
應用場景:HyperLogLog是一種基于概率的數(shù)據(jù)結構陵珍,用于估計集合中唯一元素的數(shù)量寝杖。它非常適合用于大規(guī)模數(shù)據(jù)統(tǒng)計場景,如網(wǎng)站獨立訪客數(shù)統(tǒng)計互纯。
Geo(地理位置):
應用場景:Geo類型用于存儲地理位置信息瑟幕,并支持對地理位置進行各種操作,如計算兩點之間的距離留潦、獲取指定范圍內(nèi)的地理坐標等只盹。因此,它適用于基于位置的應用兔院,如附近地點搜索殖卑、用戶位置統(tǒng)計等。
Stream(流):
應用場景:Stream是Redis 5.0版本新增的數(shù)據(jù)結構坊萝,用于實現(xiàn)消息隊列功能孵稽。它支持消息的發(fā)布、訂閱和消費十偶,非常適合用于構建實時通信菩鲜、事件驅動等應用。
14. 內(nèi)部類有哪些
在Java中扯键,內(nèi)部類主要有四種類型:
普通內(nèi)部類(Non-static Nested Class):
這是最常見的內(nèi)部類形式睦袖。當你定義一個類在另一個類的內(nèi)部珊肃,而沒有在內(nèi)部類前使用static關鍵字時荣刑,你就在創(chuàng)建一個普通內(nèi)部類。
普通內(nèi)部類可以訪問其外部類的所有成員(包括私有成員)伦乔。
創(chuàng)建普通內(nèi)部類的實例時厉亏,需要先有一個外部類的實例,因為內(nèi)部類實例會隱式地持有對其外部類實例的引用烈和。
靜態(tài)內(nèi)部類(Static Nested Class):
在內(nèi)部類前使用static關鍵字定義的就是靜態(tài)內(nèi)部類爱只。
靜態(tài)內(nèi)部類只能訪問其外部類的靜態(tài)成員。
創(chuàng)建靜態(tài)內(nèi)部類的實例不需要外部類的實例招刹。
局部內(nèi)部類(Local Inner Class):
定義在方法體或代碼塊中的內(nèi)部類就是局部內(nèi)部類。
局部內(nèi)部類可以訪問其外部類的所有成員疯暑,包括私有成員训柴。
局部內(nèi)部類還可以訪問定義它的方法或代碼塊中的局部變量,但這些局部變量必須是final的(在Java 8及以后的版本中妇拯,這個限制已經(jīng)被放寬幻馁,只要局部變量是“事實上的final”即可)洗鸵。
局部內(nèi)部類的作用范圍僅限于其定義的方法或代碼塊。
匿名內(nèi)部類(Anonymous Inner Class):
匿名內(nèi)部類是沒有名稱的內(nèi)部類仗嗦。
它通常用于實現(xiàn)一個接口或繼承一個類膘滨,并立即創(chuàng)建該類的實例。
匿名內(nèi)部類常用于創(chuàng)建只使用一次的簡單對象稀拐。
匿名內(nèi)部類沒有構造方法火邓,因為不能給它命名。但它可以訪問外部類的所有成員钩蚊。
每種內(nèi)部類都有其特定的使用場景和優(yōu)勢贡翘,根據(jù)具體需求選擇合適的內(nèi)部類類型。
public class A {
class B {}
static C {}
}
B的對象
15. synchronized和lock的區(qū)別
synchronized和Lock在Java中都是用于實現(xiàn)線程同步的機制砰逻,但它們之間存在一些關鍵的區(qū)別鸣驱。以下是它們之間的一些主要差異:
實現(xiàn)原理:
(1)來源與靈活性:
JVM層面實現(xiàn)synchronized是Java語言的關鍵字,它是內(nèi)置的語言特性蝠咆,用于修飾方法或代碼塊踊东,實現(xiàn)基本的線程同步。
Java層面實現(xiàn),Lock是Java的一個接口刚操,在java.util.concurrent.locks包下闸翅,提供了比synchronized更廣泛的鎖定操作。它允許更靈活的結構菊霜,比如可以嘗試獲取鎖(tryLock())坚冀,可以中斷等待鎖的線程,可以實現(xiàn)公平鎖等鉴逞。
(2)等待可中斷:
synchronized不可中斷记某,除非加鎖的代碼拋出異常或者運行結束构捡,否則線程將一直等待下去液南。
Lock接口提供了可以中斷等待鎖的線程的方法,如lockInterruptibly()勾徽。
(3)鎖的釋放:
synchronized在發(fā)生異常時滑凉,會自動釋放線程占有的鎖,因此不會導致死鎖現(xiàn)象發(fā)生喘帚;在代碼執(zhí)行完畢時畅姊,會自動釋放線程占有的鎖。
Lock在發(fā)生異常時吹由,如果沒有主動通過unlock()去釋放鎖若未,則很可能造成死鎖現(xiàn)象,因此使用Lock時需要在finally塊中釋放鎖溉知。
(4)鎖的狀態(tài):
對于synchronized陨瘩,我們無法判斷線程是否成功獲取到了鎖腕够。
對于Lock,我們可以查詢線程是否成功獲取到了鎖舌劳,例如使用tryLock()或者isLocked()等方法帚湘。
(5)性能:
在資源競爭不激烈的情況下惠爽,synchronized的性能要優(yōu)于Lock栓霜,因為Lock的獲取和釋放操作比synchronized復雜。任務時長長
在資源競爭非常激烈的情況下避乏,Lock的性能可能會比synchronized好贯卦,因為Lock提供了更多的自定義和靈活性资柔,可以根據(jù)實際場景選擇合適的鎖策略。任務時長短暫
(6)公平鎖與非公平鎖:
synchronized是非公平的撵割,即等待時間最長的線程不一定能優(yōu)先獲取到鎖贿堰。
Lock接口可以實現(xiàn)公平鎖,即等待時間最長的線程會優(yōu)先獲取到鎖啡彬。
綜上所述羹与,synchronized和Lock各有其優(yōu)缺點和適用場景。在選擇使用哪種同步機制時庶灿,需要根據(jù)具體的業(yè)務需求和性能要求進行權衡纵搁。對于簡單的同步需求,synchronized可能是一個更好的選擇往踢,因為它簡單易用且性能在大多數(shù)情況下都足夠好腾誉。對于更復雜的同步需求,Lock提供了更多的靈活性和控制力峻呕。
1. synchronized jvm層面實現(xiàn)的. Lock純java層面實現(xiàn)的.【CAS + va】
2. synchronized自動釋放鎖, Lock不會.手動釋放,一般情況將lock放到try...catch... finally
3. synchronized適用場景: 耗時比較長的任務, Lock適用任務時長短暫的場景
4. 實現(xiàn)原理, synchronized, 對象頭【mark word】. Lock基于cas實現(xiàn)
16. spring mvc執(zhí)行原理
DispatcherServlet類當中的doDispatcher方法當中邏輯.
Spring MVC是一個基于Java的Web框架利职,它使用了模型-視圖-控制器(MVC)設計模式,使得Web應用的開發(fā)更加靈活和模塊化山上。以下是Spring MVC的執(zhí)行原理的詳細解釋:
1. 發(fā)起請求
當用戶通過瀏覽器向服務器發(fā)送請求時眼耀,這個請求首先會被前端的Web服務器(如Tomcat)接收英支。
2. 前端控制器(DispatcherServlet)
在Spring MVC中佩憾,DispatcherServlet充當前端控制器的角色。它接收所有的Web請求干花,并根據(jù)請求的URL查找相應的處理器映射(HandlerMapping)妄帘。
3. 處理器映射(HandlerMapping)
處理器映射負責將請求的URL映射到相應的處理器(Handler),這個處理器通常是一個Controller中的方法池凄。映射完成后抡驼,它會返回一個處理器執(zhí)行鏈(HandlerExecutionChain),該鏈包含了處理器和任何相關的攔截器(Interceptor)肿仑。
4. 處理器適配器(HandlerAdapter)
處理器適配器根據(jù)返回的處理器執(zhí)行鏈中的處理器信息致盟,調(diào)用相應的處理器(Controller中的方法)進行業(yè)務處理碎税。這個過程可能涉及到與后端服務的交互、數(shù)據(jù)庫操作等馏锡。
5. 模型與視圖
處理器處理完業(yè)務邏輯后雷蹂,會返回一個ModelAndView對象。ModelAndView包含了視圖需要的數(shù)據(jù)模型(Model)和視圖的邏輯名稱(View Name)杯道。
6. 視圖解析器(ViewResolver)
視圖解析器根據(jù)ModelAndView對象中的視圖邏輯名稱匪煌,查找具體的視圖實現(xiàn)類(通常是JSP、Thymeleaf等模板)党巾,并將數(shù)據(jù)模型傳遞給視圖進行渲染萎庭。
7. 視圖渲染
視圖使用數(shù)據(jù)模型進行渲染,生成HTML響應齿拂。這個響應最終會發(fā)送回用戶的瀏覽器驳规。
8. 響應返回
瀏覽器接收到服務器返回的HTML響應后,進行解析和渲染署海,最終展示給用戶达舒。
總結
Spring MVC的執(zhí)行原理可以概括為:前端控制器接收請求,通過處理器映射找到對應的處理器叹侄,處理器適配器調(diào)用處理器處理業(yè)務邏輯并返回ModelAndView巩搏,視圖解析器根據(jù)ModelAndView找到并渲染視圖,最終返回響應給瀏覽器趾代。這個過程中贯底,Spring MVC框架提供了豐富的組件和擴展點,使得開發(fā)者可以靈活地定制和擴展Web應用的功能撒强。
17.redis持久化
首先,redis是一個內(nèi)存數(shù)據(jù)庫,當redis服務器重啟或者電腦重啟后,數(shù)據(jù)就會丟失,我們可以將redis內(nèi)存中的數(shù)據(jù)持久化保存到硬盤的文件中.
redis持久化機制:有兩種RDB和AOF
RDB:默認方式,不需要進行配置,默認使用這種機制,原理是:在一定的間隔時間中,檢測key的變化情況,然后持久化數(shù)據(jù)(推薦),對性能影響較小
AOF:日志記錄的方式,可以記錄每一條命令的操作.可以在每一次命令操作后,持久化數(shù)據(jù),對性能影響較大
Redis 的持久化機制主要用于將數(shù)據(jù)從內(nèi)存保存到磁盤中禽捆,以確保在系統(tǒng)崩潰或重啟后數(shù)據(jù)不會丟失。Redis 提供了兩種主要的持久化方式:RDB(Redis DataBase)和 AOF(Append Only File)飘哨。
1. RDB(Redis DataBase)
RDB 是 Redis 默認使用的持久化方式胚想,它基于快照實現(xiàn),將數(shù)據(jù)以二進制文件的形式保存在磁盤中芽隆。以下是 RDB 的詳細介紹:
觸發(fā)方式
手動觸發(fā):通過執(zhí)行 SAVE 或 BGSAVE 命令來觸發(fā) RDB 持久化浊服。其中,SAVE 命令會阻塞 Redis 服務器胚吁,直到快照保存完成牙躺;而 BGSAVE 命令則會創(chuàng)建一個子進程來異步保存快照,不會阻塞主進程腕扶。
自動觸發(fā):通過 Redis 配置文件中的 save 選項來設置觸發(fā)條件孽拷,當滿足指定的時間間隔和修改鍵的數(shù)量時,Redis 會自動執(zhí)行 BGSAVE 命令來保存快照半抱。
優(yōu)點
高效:RDB 文件是二進制文件脓恕,體積小膜宋,恢復速度快。
緊湊:RDB 文件是壓縮的炼幔,因此可以節(jié)省存儲空間激蹲。
容災性好:RDB 文件可以保存到安全的磁盤中,方便備份和恢復江掩。
缺點
數(shù)據(jù)丟失風險:由于 RDB 是基于快照的持久化方式学辱,如果在兩次快照之間 Redis 服務器崩潰,那么上次快照之后的所有數(shù)據(jù)修改都會丟失环形。
fork 進程開銷:在生成 RDB 文件時策泣,Redis 需要 fork 出一個子進程來執(zhí)行快照操作,這會增加一定的開銷抬吟。
2. AOF(Append Only File)
AOF 持久化通過記錄 Redis 服務器接收到的每一個寫命令(如 SET萨咕、DEL 等),并在服務器啟動時重新執(zhí)行這些命令來恢復數(shù)據(jù)火本。以下是 AOF 的詳細介紹:
寫入方式
appendfsync always:每次寫入命令都同步到 AOF 文件危队,這種方式最安全但性能最差。
appendfsync everysec:每秒同步一次 AOF 文件钙畔,這是 Redis 的默認配置茫陆,兼顧了性能和安全性。
appendfsync no:不同步 AOF 文件擎析,由操作系統(tǒng)決定何時同步簿盅,這種方式性能最好但安全性最差。
優(yōu)點
數(shù)據(jù)安全性高:AOF 持久化可以確保數(shù)據(jù)的完整性揍魂,即使 Redis 服務器崩潰桨醋,也可以通過 AOF 文件來恢復數(shù)據(jù)。
靈活性高:AOF 文件是文本文件现斋,可以方便地進行查看和編輯喜最。
缺點
恢復速度慢:由于 AOF 文件記錄了所有的寫命令,因此在 Redis 服務器啟動時需要重新執(zhí)行這些命令來恢復數(shù)據(jù)庄蹋,這會導致恢復速度比 RDB 慢瞬内。
AOF 文件體積大:與 RDB 文件相比,AOF 文件的體積可能會很大蔓肯,需要定期進行重寫(rewrite)來減小文件體積遂鹊。
3. 混合持久化(RDB-AOF)
Redis 4.0 版本開始支持混合持久化振乏,即將 RDB 持久化的數(shù)據(jù)內(nèi)容和 AOF 持久化的日志內(nèi)容混合寫入到一個 AOF 文件中蔗包。這種方式可以同時利用 RDB 持久化快速恢復和 AOF 持久化數(shù)據(jù)安全性的優(yōu)點。在 Redis 服務器啟動時慧邮,會先加載 RDB 文件的內(nèi)容调限,然后再重放 AOF 文件中的增量命令來恢復數(shù)據(jù)舟陆。
18. 動態(tài)代理【重要】
代理模式是二十三種設計模式之一,屬于結構型設計模式
三個作用:當一個對象需要受到保護的時候,可以考慮使用代理對象去完成某個行為.
需要給某個對象的功能進行增強的時候,可以考慮找一個代理進行增強
A對象和B對象無法直接交互時,可以使用代理對象
代理模式中有三大角色:目標對象
? ? 代理對象
? 目標對象和代理對象的公告接口
代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下耻矮,一個客戶不想或者不能直接引用一個對象秦躯,此時可以通過一個稱之為“代理”的第三者來實現(xiàn)間接引用。代理對象可以在客戶端和目標對象之間起到中介的作用裆装,并且可以通過代理對象去掉客戶不應該看到的內(nèi)容和服務或者添加客戶需要的額外服務踱承。 通過引入一個新的對象來實現(xiàn)對真實對象的操作或者將新的對象作為真實對象的一個替身,這種實現(xiàn)機制即為代理模式哨免,通過引入代理對象來間接訪問一個對象茎活,這就是代理模式的模式動機。
代理模式中的角色:
● 代理類(代理主題)
● 目標類(真實主題)
● 代理類和目標類的公共接口(抽象主題):客戶端在使用代理類時就像在使用目標類琢唾,不被客戶端所察覺载荔,所以代理類和目標類要有共同的行為,也就是實現(xiàn)共同的接口采桃。
代理模式在代碼實現(xiàn)上,包括兩種形式:靜態(tài)代理和動態(tài)代理
靜態(tài)代理會產(chǎn)生類爆炸的問題
動態(tài)代理:
在程序運行階段懒熙,在內(nèi)存中動態(tài)生成代理類,被稱為動態(tài)代理普办,目的是為了減少代理類的數(shù)量工扎。解決代碼復用的問題。
在內(nèi)存當中動態(tài)生成類的技術常見的包括:
● JDK動態(tài)代理技術:只能代理接口衔蹲。
● CGLIB動態(tài)代理技術:CGLIB(Code Generation Library)是一個開源項目定庵。是一個強大的,高性能踪危,高質量的Code生成類庫蔬浙,它可以在運行期擴展Java類與實現(xiàn)Java接口。它既可以代理接口贞远,又可以代理類畴博,底層是通過繼承的方式實現(xiàn)的。性能比JDK動態(tài)代理要好蓝仲。(底層有一個小而快的字節(jié)碼處理框架ASM俱病。)
● Javassist動態(tài)代理技術:Javassist是一個開源的分析、編輯和創(chuàng)建Java字節(jié)碼的類庫袱结。是由東京工業(yè)大學的數(shù)學和計算機科學系的 Shigeru Chiba (千葉 滋)所創(chuàng)建的亮隙。它已加入了開放源代碼JBoss 應用服務器項目,通過使用Javassist對字節(jié)碼操作為JBoss實現(xiàn)動態(tài)"AOP"框架垢夹。
JDK實現(xiàn)動態(tài)代理:需要用到java.lang.reflect.Proxy
創(chuàng)建代理對象時:Object proxyObj = Proxy.newProxyInstance(類加載器,代理類要實現(xiàn)的接口,調(diào)用處理器),這個步驟首先在內(nèi)存中動態(tài)的生成了一個代理類的字節(jié)碼class
其次,new對象.通過內(nèi)存中生成的代理類的代碼,實例化了代理對象.
(類加載器,代理類要實現(xiàn)的接口,調(diào)用處理器)
第一個參數(shù):類加載器(ClassLoader loader):在內(nèi)存中生成的字節(jié)碼也是class文件,要執(zhí)行也得先加載到內(nèi)存當中,加載類就需要類加載器.所以這里需要指定類加載器.并且,JDK要求,目標類的類加載器必須和代理類使用同一個.
第二個參數(shù):Class<?>[] interfaves:代理類和目標類要實現(xiàn)同一個接口或同一些接口.在內(nèi)存中生成代理類的時候,這個代理類是需要你告訴它實現(xiàn)哪些接口的.
第三個參數(shù):InvocationHandler l (調(diào)用處理器).是一個接口,在調(diào)用處理器中編寫的代碼就是增強代碼.需要編寫這個接口的實現(xiàn)類,并不會產(chǎn)生類爆炸的問題
在編寫這個接口的實現(xiàn)類的時候,必須實現(xiàn)接口中的方法:invoke(方法),JDK在底層已經(jīng)寫好了調(diào)用invoke()方法的程序
當代理對象調(diào)用代理方法的時候,注冊在InvocationHandler調(diào)用處理器中的方法被調(diào)用
invoke()方法中也有三個參數(shù)
動態(tài)代理的作用主要體現(xiàn)在以下幾個方面:
解耦:通過將業(yè)務邏輯與日志溢吻、事務等非業(yè)務邏輯分離,降低代碼之間的耦合度,使代碼更加清晰促王、易于維護犀盟。
功能增強:在不修改原始代碼的情況下,為對象添加新的功能或行為蝇狼。
靈活性:動態(tài)代理可以在運行時根據(jù)需要創(chuàng)建代理對象阅畴,適應不同的場景和需求。
可擴展性:通過動態(tài)代理迅耘,我們可以方便地擴展系統(tǒng)的功能贱枣,而無需修改大量現(xiàn)有代碼。
靜態(tài)代理
解釋概念
動態(tài)代理
jdk
cglib
應用場景:
ao
19. spring boot自動裝配原理
SpringBoot的自動裝配原理是其核心特性之一颤专,它極大地簡化了Spring應用的初始化和配置過程冯事。以下是關于SpringBoot自動裝配原理的詳細解釋:
(1)@SpringBootApplication注解:
SpringBoot自動裝配的核心起始于@SpringBootApplication注解。這個注解實際上是多個注解的組合血公,其中最為關鍵的是@EnableAutoConfiguration昵仅。
@EnableAutoConfiguration注解告訴SpringBoot根據(jù)添加的jar依賴自動配置你的Spring應用。它會從META-INF/spring.factories文件中加載所有可用的自動配置類累魔。
(2)條件注解:
SpringBoot使用條件注解來確定是否應該自動配置某個bean摔笤。這些條件注解包括:
@ConditionalOnClass:當類路徑下存在指定的類時才會生效。
@ConditionalOnMissingBean:當容器中不存在指定Bean時才會生效垦写。
@ConditionalOnProperty:指定的屬性是否有指定的值吕世。
等等。
這些條件注解允許SpringBoot根據(jù)應用的上下文和環(huán)境進行靈活的自動配置梯投。
(3)自動配置類:
SpringBoot提供了大量的自動配置類终娃,這些類會根據(jù)上述的條件注解來決定是否應該創(chuàng)建和配置相應的bean。
這些自動配置類通常包含了大量使用@Bean方法定義的bean,這些方法同樣會受到條件注解的控制。
(4)@SpringBootConfiguration和@ComponentScan:
@SpringBootApplication注解還包含了@SpringBootConfiguration和@ComponentScan探赫。
@SpringBootConfiguration實際上是一個@Configuration注解,它告訴Spring這是一個配置類箱靴,可以定義bean谱姓。
@ComponentScan告訴Spring在哪里查找?guī)в蠤Component、@Service刨晴、@Repository等注解的類屉来,并將它們作為bean注冊到Spring容器中。
(5)SPI機制:
SpringBoot使用Java的SPI(Service Provider Interface)機制來加載自動配置類狈癞。這通過META-INF/spring.factories文件實現(xiàn)茄靠,其中列出了所有可用的自動配置類。
總結:
當SpringBoot應用啟動時蝶桶,它會讀取META-INF/spring.factories文件慨绳,并根據(jù)其中的配置加載自動配置類。
這些自動配置類會根據(jù)條件注解來決定是否應該創(chuàng)建和配置bean。
最終脐雪,SpringBoot會基于這些自動配置的bean來構建應用的Spring容器厌小,從而實現(xiàn)了應用的快速啟動和配置。
SpringBoot的自動裝配原理大大簡化了Spring應用的開發(fā)和配置過程战秋,使得開發(fā)者能夠更專注于業(yè)務邏輯的實現(xiàn)璧亚,而不是花費大量時間在繁瑣的配置上。
20. mybatis常用注解有哪些
MyBatis 是一款優(yōu)秀的 ORM(對象關系映射)框架脂信,它提供了大量的注解來簡化 Java 應用程序與關系數(shù)據(jù)庫之間的交互癣蟋。以下是一些 MyBatis 中的常用注解:
@Select:
用于標注查詢 SQL 語句的方法。
例如:@Select("SELECT * FROM user WHERE id = #{id}")
@Insert:
用于標注插入 SQL 語句的方法狰闪。
例如:@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
@Update:
用于標注更新 SQL 語句的方法疯搅。
例如:@Update("UPDATE user SET name = #{name} WHERE id = #{id}")
@Delete:
用于標注刪除 SQL 語句的方法。
例如:@Delete("DELETE FROM user WHERE id = #{id}")
@Results 和 @Result:
@Results 用于定義結果集映射埋泵,可以包含多個 @Result幔欧。
@Result 用于定義單個字段的映射關系。
這兩個注解通常用于處理復雜的查詢結果丽声,如聯(lián)合查詢等礁蔗。
@ResultMap:
用于引用已定義的 <resultMap>。當 SQL 查詢結果比較復雜時恒序,可以在 XML 映射文件中定義 <resultMap>瘦麸,然后在注解中使用 @ResultMap 引用它。
@SelectKey:
用于在插入或更新操作后獲取自動生成的主鍵或其他字段的值歧胁。
常常與 @Insert 或 @Update 一起使用滋饲,以處理自增主鍵等場景。
@Options:
用于設置一些全局的選項喊巍,如是否使用緩存屠缭、是否生成自增的 key 等。
@Param:
用于命名方法參數(shù)崭参,以便在 SQL 語句中引用它們呵曹。當方法有多個參數(shù)時,需要使用 @Param 來指定參數(shù)名何暮。
@Mapper 和 @MapperScan:
@Mapper 注解用于標注 Mapper 接口奄喂,告訴 MyBatis 這是一個 Mapper 接口,需要為其生成實現(xiàn)類海洼。
@MapperScan 用于指定掃描 Mapper 接口的包路徑跨新,MyBatis 會自動掃描這些包路徑下的 Mapper 接口并為其生成實現(xiàn)類。
這些注解大大簡化了 MyBatis 的使用坏逢,使得開發(fā)者可以更加便捷地編寫 SQL 語句和處理數(shù)據(jù)庫操作域帐。
21. 原生jdbc連接步驟
原生JDBC(Java Database Connectivity)連接數(shù)據(jù)庫的步驟通常包括以下七個主要步驟:
導入JDBC驅動包:首先赘被,你需要將目標數(shù)據(jù)庫的JDBC驅動包導入到你的Java項目中。這通常是通過將JAR文件添加到項目的類路徑中來實現(xiàn)的肖揣。
加載并注冊JDBC驅動:使用Class.forName()方法加載并注冊JDBC驅動民假。這實際上是讓JVM知道你要使用哪個數(shù)據(jù)庫的JDBC驅動。
注意:在JDBC 4.0及更高版本中龙优,顯式加載驅動類通常是不必要的羊异,因為DriverManager會在需要時自動加載驅動。
3. 建立數(shù)據(jù)庫連接:使用DriverManager.getConnection()方法建立與數(shù)據(jù)庫的連接陋率。你需要提供數(shù)據(jù)庫的URL球化、用戶名和密碼作為參數(shù)秽晚。
創(chuàng)建Statement或PreparedStatement對象:使用Connection對象的createStatement()或prepareStatement()方法創(chuàng)建Statement或PreparedStatement對象瓦糟。PreparedStatement通常用于執(zhí)行帶有參數(shù)的SQL語句,并且可以提高性能并防止SQL注入攻擊赴蝇。
執(zhí)行SQL語句:使用Statement或PreparedStatement對象的executeQuery()(用于查詢)或executeUpdate()(用于更新菩浙、插入或刪除)方法執(zhí)行SQL語句。
處理結果集:如果SQL語句是查詢語句句伶,那么它將返回一個ResultSet對象劲蜻。你可以使用ResultSet對象的各種方法來遍歷和處理查詢結果。
關閉連接和結果集:最后考余,使用ResultSet先嬉、Statement和Connection對象的close()方法關閉它們,以釋放資源楚堤。這是一個非常重要的步驟疫蔓,因為它可以確保及時關閉數(shù)據(jù)庫連接,并防止?jié)撛诘馁Y源泄漏問題身冬。
22. redis rdb持久化原理
啥叫持久化【解釋一下概念】, Redis基于內(nèi)存型key-value的數(shù)據(jù)庫,由于數(shù)據(jù)保存在內(nèi)存當中,斷電或者服務崩潰,內(nèi)存數(shù)據(jù)丟失, 為了防止這種情況出現(xiàn), redis提供一種機制,將內(nèi)存數(shù)據(jù)按照配置寫到磁盤當中.稱為持久化.
rdb, redis database, 它是redis提供的持久化方案當中的一種.
當正常關閉服務, flushall, save命令的時候,會觸發(fā)持久化,此種持久化方式是阻塞式.當觸發(fā)save 時間 修改key個數(shù)或者bgsave的時候,此時父進程
會調(diào)用系統(tǒng)函數(shù)fork(), 快速創(chuàng)建一個子進程.此時,父進程繼續(xù)對外提供讀寫服務, 子進程執(zhí)行持久化.這里父進程衅胀、子進程都指向同一個物理內(nèi)存空間, 所以不會發(fā)生內(nèi)存復制.此時,如果有客戶端通過父進程修改了某些key/新增key, 此時會觸發(fā)copy on write(寫時復制), 并不會影響到當前落盤的文件.
23.spring中常用的注解有哪些?
Spring框架中常用的注解有很多,它們?yōu)殚_發(fā)者提供了更加簡潔、靈活的方式來編寫和管理Spring應用程序。以下是一些常用的Spring注解:
組件掃描和自動裝配:
@Component:用于標識一個類為Spring的組件蚪拦,可以被自動掃描并注冊為Bean烟很。
@Service:用于標注業(yè)務邏輯層組件,即Service層文搂。
@Repository:用于標注數(shù)據(jù)訪問組件,即DAO層。
@Controller:用于標識一個類為控制器層(Controller)組件丧凤,通常用于處理HTTP請求。
@RestController:結合了@Controller和@ResponseBody的功能茄唐,用于標識一個類為RESTful風格的控制器息裸,返回的數(shù)據(jù)會自動轉換為JSON或XML等格式蝇更。
@Autowired:用于自動注入依賴,可以用在構造函數(shù)呼盆、成員變量年扩、方法、方法參數(shù)上访圃。它默認按類型匹配的方式厨幻,在容器查找匹配的Bean,當有且僅有一個匹配的Bean時腿时,Spring將其注入@Autowired標注的變量中况脆。
@Qualifier:與@Autowired配合使用,當容器中有多個相同類型的Bean時批糟,通過該注解限定Bean的名稱格了。
Java配置類:
@Configuration:用于標識一個類為配置類,通常與@Bean一起使用徽鼎。
@Bean:注解在方法上盛末,聲明當前方法的返回值為一個Bean。
切面(AOP):
@Aspect:聲明一個切面否淤。
@After悄但、@Before、@Around等:用于定義通知(Advice)石抡,可直接將攔截規(guī)則(切點)作為參數(shù)檐嚣。
其他常用注解:
@Value:用于注入配置文件中的值或表達式的結果。
@Resource:與@Autowired類似啰扛,但它是Java自帶的注解嚎京,可以指定Bean的名稱。
@RequestMapping:用于處理HTTP請求侠讯,可以指定請求的URL挖藏、請求方法、請求參數(shù)等厢漩。
@PathVariable膜眠、@RequestParam等:與@RequestMapping配合使用,用于從請求URL或請求參數(shù)中綁定值到方法參數(shù)上溜嗜。
使用這些注解可以大大減少配置文件的內(nèi)容宵膨,提高開發(fā)效率,并使代碼更加簡潔炸宵、清晰辟躏。但需要注意的是,在使用注解時土全,必須確保已經(jīng)開啟了注解的支持捎琐。
24. mysql事務隔離級別及不同隔離所產(chǎn)生的問題
MySQL支持四種事務隔離級別会涎,它們分別定義了事務在并發(fā)執(zhí)行時如何相互影響。這四種隔離級別是:
讀未提交(Read Uncommitted)
讀已提交(Read Committed)
可重復讀(Repeatable Read)
串行化(Serializable)
1. 讀未提交(Read Uncommitted)
定義:一個事務可以讀取到另一個未提交事務的修改瑞凑。
問題:
臟讀:一個事務讀取到另一個未提交事務的修改末秃,如果那個未提交事務回滾,那么讀取到的數(shù)據(jù)就是無效的(臟的)籽御。
不可重復讀:在一個事務內(nèi)练慕,多次讀取同一數(shù)據(jù)返回的結果有所不同。
幻讀:一個事務在讀取某些行后技掏,另一個并發(fā)事務插入新行铃将,然后前者再次讀取同樣的范圍時,看到了這些新的“幻影”行哑梳。
2. 讀已提交(Read Committed)
定義:一個事務只能讀取到已經(jīng)提交的事務的修改劲阎。
問題:
不可重復讀:與讀未提交相同,在一個事務內(nèi)涧衙,多次讀取同一數(shù)據(jù)返回的結果有所不同哪工。
幻讀:同樣可能發(fā)生奥此。
3. 可重復讀(Repeatable Read)
定義:這是MySQL的默認隔離級別(對于InnoDB存儲引擎)弧哎。在一個事務內(nèi),多次讀取同一數(shù)據(jù)返回的結果是相同的稚虎,即使其他事務修改了那些數(shù)據(jù)撤嫩。
問題:
幻讀:盡管InnoDB通過多版本并發(fā)控制(MVCC)來盡量避免幻讀,但在某些情況下蠢终,如使用RANGE類型的查詢條件時序攘,仍可能發(fā)生幻讀。
4. 串行化(Serializable)
定義:這是最高的隔離級別寻拂,它強制事務串行執(zhí)行程奠,從而避免了上述的所有問題。
問題:
性能下降:由于事務是串行執(zhí)行的祭钉,因此性能會受到嚴重影響瞄沙。
總結
選擇合適的隔離級別需要權衡并發(fā)性和數(shù)據(jù)一致性。在大多數(shù)情況下慌核,可重復讀是一個很好的選擇距境,因為它提供了較好的并發(fā)性能,同時通過MVCC避免了大部分的數(shù)據(jù)一致性問題垮卓。但是垫桂,如果應用對數(shù)據(jù)一致性要求非常高,或者需要避免幻讀粟按,那么可能需要考慮使用串行化隔離級別诬滩。
需要注意的是霹粥,MySQL中的InnoDB存儲引擎通過其特有的MVCC技術,使得在可重復讀隔離級別下能夠避免臟讀和不可重復讀問題疼鸟,但幻讀在某些情況下仍可能發(fā)生蒙挑。因此,在設計數(shù)據(jù)庫和編寫SQL語句時愚臀,仍需要考慮并處理可能出現(xiàn)的并發(fā)問題忆蚀。
25. 方法的重載與重寫
方法的重載(Overloading)
方法的重載是指在同一個類中,可以有多個方法具有相同的名稱姑裂,但它們的參數(shù)列表(參數(shù)的類型馋袜、數(shù)量或順序)必須不同。這樣舶斧,在調(diào)用方法時欣鳖,Java會根據(jù)傳遞的參數(shù)來決定使用哪個方法。
重載的規(guī)則:
方法名必須相同茴厉。
參數(shù)列表必須不同(參數(shù)類型泽台、數(shù)量或順序)。
方法的返回類型可以相同也可以不同矾缓。
重載的方法可以有不同的訪問修飾符怀酷。
方法的重寫(Overriding)
方法的重寫是面向對象編程中的一個核心概念,它發(fā)生在子類和父類之間嗜闻。當子類想要改變從父類繼承的某個方法的行為時蜕依,可以在子類中定義一個與父類方法簽名完全相同的方法,這就是方法的重寫琉雳。
重寫的規(guī)則:
方法名样眠、參數(shù)列表必須與父類中被重寫的方法相同。
訪問修飾符不能低于父類中被重寫的方法的訪問修飾符翠肘。
返回類型必須與父類中被重寫的方法的返回類型相同或是其子類型檐束。
子類方法拋出的異常類型必須是父類方法拋出異常類型的子集。
被重寫的方法不能是final方法束倍,因為final方法無法被改變被丧。
被重寫的方法不能是靜態(tài)方法,因為靜態(tài)方法和類的關聯(lián)比和對象的關聯(lián)更強肌幽。
26.Java基本數(shù)據(jù)類型包括以下幾種:
byte:一種8位有符號整數(shù)類型晚碾,用于處理文件和網(wǎng)絡傳輸?shù)茸止?jié)級別的數(shù)據(jù)。它的取值范圍為-128到127喂急,占用1個字節(jié)的空間格嘁。其對應的包裝類類型是Byte。
short:一種16位有符號整數(shù)類型廊移,可以用于節(jié)約內(nèi)存空間的需求糕簿。它的取值范圍為-32768到32767探入,占用2個字節(jié)的空間。其對應的包裝類類型是Short懂诗。
int:一種32位有符號整數(shù)類型蜂嗽,是使用最廣泛的整數(shù)類型。它的取值范圍為-2147483648到2147483647殃恒,占用4個字節(jié)的空間植旧。其對應的包裝類類型是Integer。
long:一種64位有符號整數(shù)類型离唐,用于處理需要較大值的整數(shù)計算病附。它的取值范圍為-9223372036854774808到9223372036854774807,占用8個字節(jié)的空間亥鬓。其對應的包裝類類型是Long完沪。
float:一種32位的單精度浮點數(shù)類型,用于科學計算和需要高精度計算的場景嵌戈。它可以表示小數(shù)點前8位和小數(shù)點后23位的數(shù)字覆积。其對應的包裝類類型是Float。
double:一種64位的雙精度浮點數(shù)類型熟呛,是使用最廣泛的浮點數(shù)類型宽档。其對應的包裝類類型是Double。
char:用于表示任何字符惰拱,它是基于Unicode編碼的雌贱,所以它可以表示中文字符。其對應的包裝類類型是Character偿短。
boolean:一種邏輯類型,用于條件判斷和布爾運算馋没,只有兩個取值:true和false昔逗。其對應的包裝類類型是Boolean。
這些基本數(shù)據(jù)類型在Java編程中非常常用篷朵,它們各自有特定的取值范圍和字節(jié)大小勾怒,對應的包裝類則提供了更多操作這些基本數(shù)據(jù)類型的方法。
Java中的基本數(shù)據(jù)類型各自占用的字節(jié)數(shù)如下:
byte:占用1個字節(jié)(8位)声旺。
short:占用2個字節(jié)(16位)笔链。
int:占用4個字節(jié)(32位)。
long:占用8個字節(jié)(64位)腮猖。
float:占用4個字節(jié)(32位)鉴扫,遵循IEEE 754標準。
double:占用8個字節(jié)(64位)澈缺,遵循IEEE 754標準坪创。
char:占用2個字節(jié)(16位)炕婶,用于表示Unicode字符。
boolean:在Java虛擬機內(nèi)部莱预,boolean類型通常被特別處理柠掂,可能只占用特定的一個或多個位,但在Java虛擬機規(guī)范中并沒有明確規(guī)定其大小依沮。但在實際應用中涯贞,boolean類型通常會被當作一個字節(jié)來處理,因為Java虛擬機基于字節(jié)碼進行操作危喉。不過肩狂,這并不意味著boolean類型的變量實際上會占用一個字節(jié)的存儲空間,這只是一個方便的實現(xiàn)方式姥饰。
需要注意的是傻谁,基本數(shù)據(jù)類型的大小是固定的,不會因為運行環(huán)境的改變而改變列粪。而對應的包裝類(如Byte审磁、Short、Integer岂座、Long态蒂、Float、Double费什、Character钾恢、Boolean)則提供了更多操作這些基本數(shù)據(jù)類型的方法,并且它們都是對象類型鸳址,占用的空間會比基本數(shù)據(jù)類型大瘩蚪。
boolean 類型: 1或者4個
27.Object類常用的方法有哪些
Object類是Java中所有類的基類,提供了許多常用的方法稿黍。以下是一些Object類常用的方法:
equals(Object obj):
該方法用于比較兩個對象是否相等疹瘦。默認情況下,它比較的是對象的內(nèi)存地址是否相同巡球。但在實際應用中言沐,我們通常會根據(jù)對象的屬性值來重寫此方法,以實現(xiàn)內(nèi)容的比較酣栈。
hashCode():
返回對象的哈希碼值险胰。哈希碼通常用于在哈希表中存儲對象,例如HashMap和HashSet等矿筝。重寫equals方法時起便,通常也需要重寫hashCode方法,以確保當兩個對象相等時,它們的哈希碼也相同缨睡。
getClass():
返回對象的運行時類鸟悴。此方法被final修飾,不允許子類覆蓋奖年。通過getClass()方法细诸,我們可以獲取對象的實際類型,這在一些需要動態(tài)類型檢查的場景中非常有用陋守。
toString():
返回對象的字符串表示形式震贵。默認情況下,它返回的是對象的類名水评、@符號和對象的哈希碼的無符號十六進制表示猩系。但通常,我們會在子類中重寫此方法中燥,以返回更具可讀性的字符串寇甸。
clone():
創(chuàng)建并返回此對象的一個副本。但需要注意的是疗涉,此方法是protected的拿霉,且只有在對象的類實現(xiàn)了Cloneable接口時,才能調(diào)用此方法咱扣。否則绽淘,會拋出CloneNotSupportedException異常。另外闹伪,clone方法實現(xiàn)的是淺復制沪铭,如果對象中包含對其他對象的引用,那么這些引用不會被復制偏瓤。
finalize():
當垃圾回收器確定對象不再被引用時杀怠,由對象的finalize()方法自動調(diào)用。但需要注意的是硼补,finalize()方法并不能保證一定會被調(diào)用驮肉,而且其執(zhí)行時間也是不確定的。因此已骇,在Java中,我們通常不推薦使用finalize()方法來釋放資源票编,而是應該使用try-with-resources語句或顯式地關閉資源褪储。
notify()、notifyAll()和wait():
這三個方法用于實現(xiàn)多線程之間的通信慧域。wait()方法使當前線程等待鲤竹,直到其他線程調(diào)用此對象的notify()方法或notifyAll()方法。notify()方法隨機喚醒在此對象監(jiān)視器上等待的單個線程,而notifyAll()方法則喚醒在此對象監(jiān)視器上等待的所有線程辛藻。
以上就是Object類的一些常用方法碘橘。當然,除了這些方法外吱肌,Object類還提供了其他一些方法痘拆,如getProtectionDomain()等,但這些方法在一般的應用開發(fā)中并不常用氮墨。
28.集合的體系結構
在Java的集合框架中纺蛆,Iterable接口扮演著非常重要的角色。以下是關于Iterable接口的一些關鍵點和它與其他接口/類的關系:
定義:Iterable接口位于java.lang包下规揪,它定義了一個名為iterator()的抽象方法桥氏,該方法返回一個實現(xiàn)了Iterator接口的對象猛铅。這使得實現(xiàn)了Iterable接口的類可以使用Java中的for-each循環(huán)語法來遍歷其元素字支。
核心地位:Iterable接口是所有集合類(包括Collection、Map等)的根接口奸忽。它定義了一種通用的迭代方式堕伪,用于遍歷集合中的元素。
與Collection接口的關系:java.util.Collection接口直接繼承自Iterable接口月杉,是集合框架的核心接口之一刃跛。它代表一組對象的集合,提供了對集合元素的基本操作苛萎,如添加桨昙、刪除、查詢大小腌歉、是否為空蛙酪、是否包含某個元素等。
迭代器的使用:通過調(diào)用Iterable接口的iterator()方法翘盖,可以獲得一個Iterator對象桂塞,該對象包含了hasNext()、next()和remove()等方法馍驯,用于遍歷和操作集合中的元素阁危。
與Map接口的關系:雖然Map接口不直接繼承自Iterable接口,但Map接口有一個entrySet()方法汰瘫,該方法返回一個實現(xiàn)了Set接口的視圖狂打,該視圖包含了映射中的鍵值對。由于Set接口繼承了Collection接口混弥,因此可以通過entrySet()方法返回的集合來使用for-each循環(huán)遍歷Map中的元素实辑。
總的來說,Iterable接口在Java集合框架中起到了橋梁的作用炬藤,它使得所有實現(xiàn)了該接口的集合類都可以使用統(tǒng)一的迭代方式進行遍歷。
Java中的集合框架是一個用于表示和操作對象的集合的體系結構蒿涎。這個框架主要包含了Collection接口和Map接口,以及它們各自的子接口和實現(xiàn)類惦辛。
1. Collection接口
Collection接口是Java集合框架中的核心接口之一劳秋,它表示一組對象的集合。Collection接口的主要特點包括:
集合中的元素不保證有序(某些子接口如List是有序的)裙品。
集合中的元素可以重復(某些子接口如Set是不允許重復的)俗批。
集合中的元素都是對象,不能存儲基本數(shù)據(jù)類型(但可以使用基本數(shù)據(jù)類型的包裝類)市怎。
Collection接口的主要子接口包括:
List:代表有序可重復的集合岁忘,可以直接根據(jù)元素的索引來訪問。常用的實現(xiàn)類有ArrayList区匠、LinkedList和Vector干像。
ArrayList:基于數(shù)組實現(xiàn),支持快速隨機訪問驰弄,適用于讀取操作比較多的場景麻汰。
LinkedList:基于鏈表實現(xiàn),支持快速插入和刪除操作戚篙,適用于插入和刪除操作比較多的場景五鲫。
Vector:與ArrayList類似,但是支持同步操作岔擂,適用于多線程環(huán)境位喂。
Set:代表無序不重復的集合,只能根據(jù)元素本身來訪問乱灵。常用的實現(xiàn)類有HashSet塑崖、TreeSet和LinkedHashSet。
HashSet:基于哈希表實現(xiàn)痛倚,元素存儲位置由元素的哈希碼決定规婆,因此無序。
TreeSet:基于紅黑樹實現(xiàn)蝉稳,元素自動排序抒蚜,不允許插入重復元素。
LinkedHashSet:具有HashSet的查找效率耘戚,同時保持元素的插入順序削锰。
Queue:代表隊列集合,是一種特殊的線性表毕莱,其只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作。常用的實現(xiàn)類有LinkedList朋截、ArrayDeque和PriorityQueue蛹稍。
2. Map接口
Map接口是Java集合框架中的另一個核心接口,它表示鍵值對的集合部服。Map中的每一個元素都是一個鍵值對(key-value pair)唆姐,鍵(key)是唯一的,而值(value)可以重復廓八。Map接口的主要特點包括:
鍵(key)必須是唯一的奉芦,不能重復。
值(value)可以重復剧蹂。
鍵和值都是對象声功,不能存儲基本數(shù)據(jù)類型(但可以使用基本數(shù)據(jù)類型的包裝類)。
Map接口的主要實現(xiàn)類包括:
HashMap:基于哈希表實現(xiàn)宠叼,允許null鍵和null值先巴,不保證映射的順序。
TreeMap:基于紅黑樹實現(xiàn)冒冬,能夠自然排序或者通過Comparator進行定制排序伸蚯,不允許null鍵。
LinkedHashMap:具有HashMap的查找效率简烤,同時保持元素的插入順序剂邮。
遍歷集合
Java提供了多種遍歷集合的方式,包括使用for循環(huán)横侦、增強for循環(huán)(foreach循環(huán))挥萌、迭代器(Iterator)以及Java 8引入的forEach方法和Stream API等。這些遍歷方式各有特點丈咐,可以根據(jù)具體的需求和場景選擇合適的遍歷方式瑞眼。
總之,Java的集合框架為Java程序提供了豐富的數(shù)據(jù)結構支持棵逊,使得Java程序能夠更加方便地處理和操作對象集合伤疙。
29.mysql多表查詢的方式
內(nèi)連接 (INNER JOIN)
隱式內(nèi)連接:
隱式內(nèi)連接不使用JOIN關鍵字,而是通過在WHERE子句中指定連接條件來實現(xiàn)辆影。
顯式內(nèi)連接:
顯式內(nèi)連接使用INNER JOIN關鍵字來指定連接條件和參與連接的表徒像。
外連接 (OUTER JOIN)
左外連接 (LEFT OUTER JOIN):
左外連接從左表中選擇所有的行,即使右表中沒有匹配的行蛙讥。如果沒有匹配的行锯蛀,則結果集中的右表字段將為NULL。
右外連接 (RIGHT OUTER JOIN):
右外連接與左外連接相反次慢,從右表中選擇所有的行旁涤,即使左表中沒有匹配的行翔曲。
子查詢 (Subquery)
單行單列子查詢:
子查詢返回單一的值,通常用于比較操作劈愚,如=瞳遍、<、>等菌羽。
多行單列子查詢:
子查詢返回多行但僅一列的結果集掠械,通常與IN、ANY注祖、ALL等操作符一起使用猾蒂。
多行多列子查詢:
多行多列子查詢通常與JOIN一起使用,將子查詢的結果作為虛擬表是晨。但在某些情況下肚菠,您可能想從子查詢中選擇多列數(shù)據(jù)并在外部查詢中引用它們。
30.java基本數(shù)據(jù)類型及對應的包裝類類型
Java中有八種基本數(shù)據(jù)類型(primitive data types)署鸡,每種基本數(shù)據(jù)類型都對應一個包裝類(wrapper class)案糙,這些包裝類屬于Java的標準庫java.lang包。下面是基本數(shù)據(jù)類型及其對應的包裝類的列表:
byte - Byte
byte 數(shù)據(jù)類型是 8 位靴庆、有符號的二進制整數(shù)时捌。它的取值范圍是 -128 到 127(包括)。
short - Short
short 數(shù)據(jù)類型是 16 位炉抒、有符號的二進制整數(shù)奢讨。它的取值范圍是 -32,768 到 32,767(包括)。
int - Integer
int 數(shù)據(jù)類型是 32 位焰薄、有符號的二進制整數(shù)拿诸。它的取值范圍大約是 -2^31 到 2^31 - 1。
long - Long
long 數(shù)據(jù)類型是 64 位塞茅、有符號的二進制整數(shù)亩码。它的取值范圍大約是 -2^63 到 2^63 - 1。
float - Float
float 數(shù)據(jù)類型是單精度野瘦、32位IEEE 754浮點數(shù)描沟。
double - Double
double 數(shù)據(jù)類型是雙精度、64位IEEE 754浮點數(shù)鞭光。
char - Character
char 數(shù)據(jù)類型是 16 位 Unicode 字符吏廉。它的取值范圍是從 '\u0000'(即0)到 '\uffff'(即65,535)。
boolean - Boolean
boolean 數(shù)據(jù)類型有兩個可能的值:true 和 false惰许。
包裝類的主要用途是在需要對象的地方使用基本數(shù)據(jù)類型席覆。例如,當你需要將基本數(shù)據(jù)類型作為對象在集合類(如ArrayList)中使用時汹买,或者當你需要為基本數(shù)據(jù)類型提供額外的功能(如方法)時佩伤,就可以使用包裝類聊倔。
此外,包裝類還提供了很多有用的方法和常量畦戒,如Integer.MAX_VALUE方库、Double.parseDouble()等。
31.有哪幾種方式創(chuàng)建對象
使用new關鍵字創(chuàng)建對象:
這是最常見和基本的對象創(chuàng)建方式障斋。通過調(diào)用類的構造方法(可以是無參或有參構造方法)來實例化對象。使用new關鍵字可以在堆內(nèi)存中為對象分配內(nèi)存徐鹤,并調(diào)用構造方法對對象進行初始化垃环。
使用反射機制創(chuàng)建對象:
反射機制允許我們在運行時獲取類的信息并操作類的屬性、方法等返敬。通過反射遂庄,我們可以通過類的全限定名獲取Class對象,并使用該對象的newInstance()方法(或getDeclaredConstructor().newInstance()方法劲赠,如果有參數(shù))創(chuàng)建對象涛目。
使用克隆的clone()方法創(chuàng)建對象:
通過實現(xiàn)Cloneable接口并重寫clone()方法,我們可以使用clone()方法創(chuàng)建對象的副本凛澎。需要注意的是霹肝,不是所有的對象都可以被克隆,只有實現(xiàn)了Cloneable接口并且正確重寫了clone()方法的對象才可以被克隆塑煎。
使用序列化和反序列化創(chuàng)建對象:
序列化是將對象轉換為字節(jié)流的過程沫换,而反序列化則是將字節(jié)流轉換回對象的過程。這種方式可以在網(wǎng)絡傳輸或者持久化對象時使用最铁。要支持序列化和反序列化讯赏,類需要實現(xiàn)Serializable接口。
32.redis作為緩存有哪些問題?對應的解決方案有哪些 ?
Redis作為緩存時冷尉,可能會遇到以下幾個問題漱挎,以及相應的解決方案:
緩存穿透:
問題描述:當查詢一個不存在的數(shù)據(jù)時,由于緩存中沒有該數(shù)據(jù)雀哨,每次查詢都會直接訪問數(shù)據(jù)庫磕谅,導致數(shù)據(jù)庫壓力過大。
解決方案:
緩存空對象:當數(shù)據(jù)庫查詢結果為空時震束,將空結果也緩存起來怜庸,并設置一個較短的過期時間。這樣垢村,后續(xù)請求相同的數(shù)據(jù)時割疾,可以直接從緩存中獲取空結果,而不會再次訪問數(shù)據(jù)庫嘉栓。
布隆過濾器:布隆過濾器是一種空間效率極高的概率型數(shù)據(jù)結構宏榕,它利用位數(shù)組很簡潔地表示一個集合拓诸,并能判斷一個元素是否屬于這個集合。在緩存之前麻昼,使用布隆過濾器判斷數(shù)據(jù)是否存在奠支,如果不存在則直接返回,避免訪問數(shù)據(jù)庫抚芦。
緩存擊穿:
問題描述:當某個熱點數(shù)據(jù)(被頻繁訪問的數(shù)據(jù))的緩存失效時倍谜,大量的請求會同時打到數(shù)據(jù)庫上,導致數(shù)據(jù)庫壓力驟增叉抡。
解決方案:
設置失效期為永不失效:對于熱點數(shù)據(jù)尔崔,可以將其緩存的失效時間設置為一個較長的值,甚至永不失效褥民。
增加互斥鎖:在緩存失效時季春,只允許一個線程去查詢數(shù)據(jù)庫,其他線程等待結果即可消返。這樣可以避免多個線程同時查詢數(shù)據(jù)庫载弄。
設置二級緩存(本地緩存):在應用程序中設置本地緩存,當Redis緩存失效時撵颊,可以從本地緩存中獲取數(shù)據(jù)宇攻,減少對數(shù)據(jù)庫的訪問。
緩存雪崩:
問題描述:在同一時間點秦驯,大量的緩存數(shù)據(jù)過期或失效尺碰,導致所有請求都直接打到數(shù)據(jù)庫上,造成數(shù)據(jù)庫壓力過大译隘。
解決方案:
為預計的熱key設置過期時間時增加一個隨機時間亲桥,防止同時過期。
設置為永久不過期:對于重要的熱點數(shù)據(jù)固耘,可以將其緩存的失效時間設置為永久不過期题篷。
保證Redis服務的高可用:使用Redis集群、主從復制等方式厅目,確保Redis服務的高可用性番枚,避免單點故障。
使用互斥鎖逐步重新創(chuàng)建所有緩存:在緩存失效時损敷,使用互斥鎖確保只有一個線程去重新創(chuàng)建緩存葫笼,其他線程等待結果即可。
異步任務全量重新創(chuàng)建緩存:使用異步任務定期全量重新創(chuàng)建緩存拗馒,避免緩存集中失效的問題路星。
數(shù)據(jù)一致性問題:
問題描述:當使用Redis作為緩存時,由于緩存與數(shù)據(jù)庫的數(shù)據(jù)可能存在不一致的情況诱桂,導致數(shù)據(jù)不一致問題洋丐。
解決方案:
使用雙寫一致性方案:在更新數(shù)據(jù)時呈昔,同時更新數(shù)據(jù)庫和Redis緩存,確保數(shù)據(jù)的一致性友绝。但需要注意雙寫時可能存在的并發(fā)問題堤尾。
延遲雙刪策略:在更新數(shù)據(jù)時,先刪除Redis緩存中的舊數(shù)據(jù)迁客,然后更新數(shù)據(jù)庫郭宝;在更新數(shù)據(jù)庫后,再異步刪除Redis緩存中的舊數(shù)據(jù)哲泊。這樣可以避免在更新過程中其他線程讀取到舊數(shù)據(jù)的問題剩蟀。
監(jiān)聽數(shù)據(jù)庫變更:使用數(shù)據(jù)庫的變更監(jiān)聽功能(如MySQL的binlog),當數(shù)據(jù)庫數(shù)據(jù)發(fā)生變化時切威,自動更新Redis緩存中的數(shù)據(jù)。這樣可以確保Redis緩存中的數(shù)據(jù)與數(shù)據(jù)庫中的數(shù)據(jù)保持一致丙号。
33. 獲取Class對象有幾種方式
使用.class語法:
這是最常用的方法先朦,直接在類名后面加上.class。
使用對象的getClass()方法:
如果你已經(jīng)有一個類的實例犬缨,可以使用getClass()方法獲取其Class對象喳魏。注意,getClass()方法返回的是具體的類類型(即String.class)怀薛,而不是父類或接口刺彩。
使用Class.forName()方法:
你可以使用Class.forName()方法通過類的全限定名來獲取Class對象。此方法常用于在運行時動態(tài)加載類枝恋。注意创倔,如果類不存在于類路徑中,Class.forName()會拋出ClassNotFoundException焚碌。
使用類的加載器(ClassLoader):
你可以使用ClassLoader的loadClass()方法來加載類并獲取其Class對象畦攘。這通常在你需要更精細地控制類的加載過程時使用。這里的ClassLoader可以是系統(tǒng)類加載器十电、自定義類加載器等知押。
使用Java的內(nèi)置類型包裝類:
對于Java的原始數(shù)據(jù)類型(如int, double等),它們的包裝類(如Integer, Double等)都有一個靜態(tài)的TYPE字段鹃骂,該字段是一個Class對象台盯,代表該原始數(shù)據(jù)類型的類。
注意畏线,這與使用.class語法(如int.class)是不同的静盅,因為原始數(shù)據(jù)類型沒有.class屬性。但是象踊,你可以使用它們的包裝類的.TYPE字段來獲取對應的Class對象温亲。
使用數(shù)組的getClass()方法(對于數(shù)組類型):
對于數(shù)組類型棚壁,你可以使用數(shù)組的getClass()方法來獲取其Class對象。但請注意栈虚,這將返回數(shù)組的Class對象袖外,而不是數(shù)組元素類型的Class對象。要獲取數(shù)組元素類型的Class對象魂务,你可以使用getComponentType()方法曼验。
34.反射有哪些重要的操作,什么是反射?
在Java中,反射(Reflection)是一種強大的機制粘姜,允許程序在運行時檢查和修改類鬓照、接口、字段和方法的行為孤紧。以下是Java反射中一些重要的操作:
獲取Class對象:
使用.class語法豺裆。
使用對象的getClass()方法。
使用Class.forName()方法通過類的全限定名獲取号显。
創(chuàng)建對象:
通過Class對象的newInstance()方法(對于無參構造函數(shù))臭猜。
使用Class對象的getDeclaredConstructor()方法獲取Constructor對象,然后通過Constructor對象的newInstance()方法創(chuàng)建對象(對于有參構造函數(shù))押蚤。
獲取類成員變量:
使用Class對象的getDeclaredFields()方法獲取所有聲明的字段(包括私有字段)蔑歌。
使用Class對象的getFields()方法獲取所有公共字段。
使用Field對象的getName()方法獲取字段名揽碘。
獲取和設置成員變量的值:
對于公共字段次屠,可以直接使用Field對象的get()和set()方法。
對于私有字段雳刺,需要先調(diào)用Field對象的setAccessible(true)方法取消訪問檢查劫灶,然后再使用get()和set()方法。
獲取類的方法:
使用Class對象的getDeclaredMethods()方法獲取所有聲明的方法(包括私有方法)煞烫。
使用Class對象的getMethods()方法獲取所有公共方法(包括從父類和接口繼承的方法)浑此。
使用Method對象的invoke()方法調(diào)用方法。
獲取類的構造方法:
使用Class對象的getDeclaredConstructors()方法獲取所有聲明的構造方法滞详。
使用Class對象的getConstructors()方法獲取所有公共構造方法凛俱。
訪問私有成員:
通過setAccessible(true)方法可以取消Java語言的訪問檢查,允許訪問類的私有成員料饥。
動態(tài)代理:
使用java.lang.reflect.Proxy類和InvocationHandler接口可以創(chuàng)建動態(tài)代理對象蒲犬,在運行時動態(tài)地實現(xiàn)接口或代理類。
類加載器:
Java的類加載器負責在運行時加載類岸啡。通過類加載器原叮,可以在運行時動態(tài)地加載和卸載類。
這些反射操作使得Java程序在運行時具有更高的靈活性和動態(tài)性,但也需要注意其性能開銷和安全性問題奋隶。
35.Java中sleep和wait的區(qū)別
在Java中擂送,sleep和wait都是用于線程控制的方法,但它們之間存在顯著的差異唯欣。以下是sleep和wait的主要區(qū)別:
所屬類和方法簽名:
sleep是Thread類的一個靜態(tài)方法嘹吨,用于使當前線程暫停執(zhí)行一段時間。其方法簽名是public static void sleep(long millis)和public static void sleep(long millis, int nanos)境氢。
wait是Object類的一個方法蟀拷,用于使當前線程等待,直到其他線程調(diào)用此對象的notify()或notifyAll()方法萍聊,或者超過指定的時間量问芬。其方法簽名是public final void wait(), public final void wait(long timeout), 和 public final void wait(long timeout, int nanos)。
使用上下文:
sleep可以在任何情況下使用寿桨,它僅僅是讓當前線程暫停執(zhí)行一段時間此衅。
wait只能在同步方法或同步代碼塊中使用,因為它依賴于對象的監(jiān)視器鎖(monitor lock)亭螟。
釋放鎖:
當線程調(diào)用sleep方法時炕柔,它不會釋放持有的任何鎖。這意味著如果線程在持有某個對象的鎖時調(diào)用sleep媒佣,其他線程仍然無法訪問該對象,直到原始線程醒來并釋放鎖陵刹。
當線程調(diào)用wait方法時默伍,它會釋放當前持有的對象的監(jiān)視器鎖。這允許其他線程進入同步方法或同步代碼塊并訪問該對象衰琐。
喚醒機制:
sleep方法在指定的時間過去后會自動喚醒也糊。
wait方法需要其他線程調(diào)用notify()或notifyAll()方法來喚醒,或者等待超時羡宙。
異常處理:
兩者都會拋出InterruptedException狸剃,當線程在等待、睡眠或進行其他可以中斷的阻塞狀態(tài)時狗热,如果其他線程中斷了當前線程钞馁,那么會拋出這個異常。
用途:
sleep通常用于模擬等待匿刮、暫停線程執(zhí)行等場景僧凰。
wait通常用于線程間的通信和協(xié)調(diào),如生產(chǎn)者-消費者問題中的等待-通知機制熟丸。
返回值:
sleep沒有返回值训措。
wait在方法被喚醒或拋出InterruptedException之前,會一直阻塞。如果調(diào)用了帶參數(shù)的wait方法绩鸣,并且超時了怀大,那么wait方法會返回,但不會拋出異常呀闻。
在實際應用中化借,wait和notify/notifyAll通常用于實現(xiàn)更復雜的線程間通信和同步,而sleep則用于簡單的線程暫停总珠。
36. java中this關鍵字作用, super關鍵字作用
this關鍵字的作用
引用當前對象的成員變量:當成員變量和局部變量重名時屏鳍,可以使用this來區(qū)分它們。
調(diào)用當前對象的成員方法:雖然在大多數(shù)情況下局服,我們可以直接調(diào)用成員方法钓瞭,但在某些情況下,使用this可以使代碼更清晰淫奔。
作為方法的返回值:在某些情況下山涡,你可能希望方法返回當前對象本身,這時可以使用this唆迁。
在構造函數(shù)中調(diào)用另一個構造函數(shù)(自Java 8起):可以使用this(...)來調(diào)用當前類的另一個構造函數(shù)鸭丛。
super關鍵字的作用
引用父類的成員變量:當子類隱藏了父類的成員變量時(即子類和父類有同名的成員變量),可以使用super來引用父類的成員變量唐责。
調(diào)用父類的成員方法:當子類重寫了父類的成員方法時鳞溉,可以使用super來調(diào)用父類的成員方法腻格。
調(diào)用父類的構造函數(shù):在子類的構造函數(shù)中棒旗,可以使用super(...)來調(diào)用父類的構造函數(shù)。這是子類構造函數(shù)必須做的第一件事情(除非父類有無參構造函數(shù)且子類構造函數(shù)沒有顯式調(diào)用其他構造函數(shù))更米。
在匿名內(nèi)部類中使用外部類的成員:在匿名內(nèi)部類中朴恳,super引用的是外部類的父類(如果有的話)抄罕,而不是外部類本身。但在大多數(shù)情況下于颖,我們會在匿名內(nèi)部類中使用外部類的成員呆贿,這時直接使用外部類的成員名即可。但在某些需要區(qū)分的情況下森渐,可以使用OuterClass.this來引用外部類的實例做入。
37.==和equals區(qū)別
基本類型與對象類型:
對于基本數(shù)據(jù)類型(如int, char, boolean等),== 用于比較它們的值是否相等章母。
對于對象引用類型母蛛,== 用于比較兩個引用是否指向內(nèi)存中的同一個對象(即比較它們的內(nèi)存地址是否相同)。
equals() 方法:
equals() 方法是Object類的一個方法乳怎,用于比較兩個對象的內(nèi)容是否相等彩郊。但是前弯,Object類的equals()方法默認實現(xiàn)的是和==相同的比較(即比較引用是否相同)。
通常秫逝,Java中的類(如String, Integer, 自定義類等)會重寫equals()方法恕出,以提供更有意義的比較邏輯(例如,比較兩個String對象的內(nèi)容是否相同)违帆。
null值處理:
使用==比較時浙巫,如果其中一個引用是null,那么結果就會是false(因為null不指向任何對象)刷后。
在使用equals()方法時的畴,如果調(diào)用它的對象是null,那么將會拋出NullPointerException尝胆。因此丧裁,在使用equals()方法之前,通常需要檢查對象是否為null含衔。
對稱性和一致性:
equals()方法必須滿足對稱性(即a.equals(b)和b.equals(a)的結果應該相同)和一致性(即多次調(diào)用a.equals(b)的結果應該相同煎娇,前提是a和b都沒有被修改)。
38.列舉一些常用軟件或框架的端口號
8080:這是Tomcat默認的HTTP端口贪染。當然缓呛,它也可以被配置為使用其他端口。
3306:MySQL數(shù)據(jù)庫的默認端口號杭隙,用于數(shù)據(jù)庫連接和數(shù)據(jù)傳輸哟绊。
MongoDB:默認端口為27017,這是一個流行的NoSQL文檔數(shù)據(jù)庫痰憎。
Elasticsearch:這是一個基于Lucene的搜索和分析引擎匿情,默認HTTP端口是9200。
Redis:默認端口為6379信殊,它是一個開源的內(nèi)存數(shù)據(jù)結構存儲系統(tǒng),可以用作數(shù)據(jù)庫汁果、緩存和消息代理涡拘。
Nginx:雖然Nginx本身不是Java軟件,但它經(jīng)常與Java應用一起使用作為反向代理据德。Nginx的默認HTTP端口是80鳄乏,HTTPS默認端口是443。
1521:Oracle數(shù)據(jù)庫的默認端口號棘利,用于數(shù)據(jù)庫連接和數(shù)據(jù)傳輸橱野。
SQL Server:默認端口為1433,這是Microsoft的關系型數(shù)據(jù)庫管理系統(tǒng)善玫。
rabbitmq 5672
39.rabbitmq 模式有哪些?特點都是啥
RabbitMQ支持多種消息傳遞模式水援,每種模式都有其特定的用途和特點。以下是RabbitMQ的一些常見模式及其特點:
簡單模式(Simple):
特點:一個生產(chǎn)者將消息放入隊列,一個消費者從隊列中獲取并消費消息蜗元。消息一旦被消費者拿走或渤,就會自動從隊列中刪除。
應用場景:簡單的消息隊列場景奕扣,如聊天應用(一個服務器和多個客戶端之間的通信)薪鹦。
工作模式(Work):
特點:也稱為“能者多勞隊列”,一個生產(chǎn)者將消息放入隊列惯豆,多個消費者同時監(jiān)聽同一個隊列池磁,消息被消費者消費后自動從隊列中刪除。消費者之間通過競爭關系來消費消息楷兽。
應用場景:需要并行處理大量消息的場景地熄,如訂單處理、日志處理等拄养。
發(fā)布/訂閱模式(Publish/Subscribe):
特點:也稱為fanout模式离斩,生產(chǎn)者將消息發(fā)送到交換機(Exchange),交換機將消息廣播到所有與之綁定的隊列中瘪匿,每個隊列中的消費者都可以消費消息跛梗。
應用場景:需要向多個消費者發(fā)送相同消息的場景,如實時新聞推送棋弥、公告發(fā)布等核偿。
路由模式(Routing):
特點:生產(chǎn)者將消息發(fā)送到交換機,交換機根據(jù)路由規(guī)則將消息發(fā)送到與規(guī)則匹配的隊列中顽染。消費者從對應的隊列中獲取并消費消息漾岳。
應用場景:需要根據(jù)不同條件將消息發(fā)送到不同隊列的場景,如訂單處理系統(tǒng)(根據(jù)訂單類型發(fā)送到不同的處理隊列)粉寞。
主題模式(Topics):
特點:生產(chǎn)者將消息發(fā)送到交換機尼荆,交換機使用模糊匹配規(guī)則將消息發(fā)送到與規(guī)則匹配的隊列中。消費者從對應的隊列中獲取并消費消息唧垦。
應用場景:需要更復雜的路由規(guī)則的場景捅儒,如日志處理系統(tǒng)(根據(jù)日志級別和來源發(fā)送到不同的處理隊列)。
RPC模式(Remote Procedure Call):
特點:客戶端發(fā)送帶有請求ID和回復隊列的RPC請求到RabbitMQ振亮,服務器處理請求后將結果發(fā)送到指定的回復隊列中巧还,客戶端從回復隊列中獲取結果。
應用場景:需要實現(xiàn)遠程過程調(diào)用的場景坊秸,如分布式系統(tǒng)中的服務調(diào)用麸祷。
RabbitMQ的主要特點包括:
可靠性:基于AMQP協(xié)議,提供了持久化褒搔、可靠的消息傳遞機制阶牍,確保消息在發(fā)送和接收之間進行可靠傳輸喷面,即使在出現(xiàn)故障的情況下也能保證消息的安全性。
靈活性:支持多種消息傳遞模式荸恕,允許開發(fā)人員根據(jù)應用程序的需求來選擇合適的消息模式乖酬,實現(xiàn)靈活的消息傳遞。同時支持水平擴展融求,可以在需要時添加更多的節(jié)點來處理更多的消息咬像。
應答模式:支持消息應答機制,確保消息在處理過程中不會丟失生宛。如果一個消費者在處理消息時掛掉县昂,RabbitMQ會將該消息重新分配給其他消費者進行處理。
以上是關于RabbitMQ的常見模式及其特點的簡要介紹陷舅。如需更詳細的信息倒彰,請參考RabbitMQ的官方文檔或相關教程。
40.rabbitmq如何實現(xiàn)消息的可靠性
三方面:發(fā)送者,rabbitMQ,消費者
發(fā)送者:兩種方式:
1.發(fā)送者重連:有的時候由于網(wǎng)絡波動,可能會出現(xiàn)發(fā)送者連接MQ失敗的情況,通過配置我們可以開啟連接失敗后的重連機制
spring:
? rabbitmq:
? ? connection-timeout: 1s? # 設置MQ連接超時時間
? ? template:
? ? ? retry:
? ? ? ? enabled: true #開啟超時重試機制
? ? ? ? initial-interval: 1000ms? #失敗后的初始等待時間
? ? ? ? multipliter: 1? # 失敗后下次的等待時長倍數(shù),下次等待時長 = initial-interval * multipliter
? ? ? ? max-attempts: 3 #最大重試次數(shù)
當網(wǎng)絡不穩(wěn)定的時候,利用重試機制可以有效提高消息發(fā)送的成功率.不過,SpringAMQP提供的重試機制是阻塞式的重試,也就是說多次重試等待的過程中,當前線程是被阻塞的,會影響業(yè)務性能.
如果對于業(yè)務性能有要求,建議禁用重試機制.如果一定要使用,請合理配置等待時長和重試次數(shù),當然也可以考慮使用異步線程來執(zhí)行發(fā)送消息的代碼.
2.發(fā)送者確認
41.Java中的訪問修飾符有哪些,各自的范圍會什么?
Java中的訪問修飾符用于控制類莱睁、變量待讳、方法和構造器的訪問權限。Java提供了四種訪問修飾符:private仰剿、default(也稱為包級私有)创淡、protected和public。下面是它們各自的訪問范圍:
private(私有)
訪問范圍:只在定義該成員的類內(nèi)部可見南吮。
成員變量和成員方法都可以被聲明為private琳彩。
private是最嚴格的訪問級別。
default(默認部凑,也稱為包級私有)
訪問范圍:在同一個包(package)內(nèi)的類可見露乏。
如果一個類、變量涂邀、方法或構造器沒有指定訪問修飾符瘟仿,則它默認使用default訪問級別。
default訪問級別僅允許同包內(nèi)的類訪問比勉。
protected(受保護)
訪問范圍:在同一個包內(nèi)的類可見猾骡,以及在其他包中的子類也可見。
protected可以修飾成員變量敷搪、成員方法、構造器以及內(nèi)部類幢哨。
protected提供了比default更寬松的訪問權限赡勘,允許子類訪問父類的protected成員。
public(公共)
訪問范圍:對所有類可見捞镰,無論它們是否在同一個包中闸与。
public可以修飾類毙替、變量、方法践樱、構造器和接口厂画。
public訪問級別是最寬松的,允許任何類訪問拷邢。
注意:
類只能被聲明為public或default(默認袱院,沒有修飾符)。
接口默認是public的瞭稼,但也可以顯式地聲明為public忽洛。
成員變量、成員方法和構造器都可以被聲明為private环肘、default欲虚、protected或public。
頂層類(即不是內(nèi)部類的類)不能是private或protected的悔雹,它們只能是public或default的复哆。
枚舉常量默認是public static final的,因此它們總是可以被訪問的腌零。
局部變量(在方法或代碼塊中定義的變量)不能有訪問修飾符梯找,因為它們的可見性由它們所在的作用域決定。