<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          來銀行面試了,有點(diǎn)簡單?

          共 24210字,需瀏覽 49分鐘

           ·

          2024-07-30 16:42

          圖解學(xué)習(xí)網(wǎng)站:https://xiaolincoding.com

          大家好,我是小林。

          準(zhǔn)備 8 月份,7 月份不少互聯(lián)網(wǎng)公司都開啟秋招提前批了,等到 8 月份之后,陸陸續(xù)續(xù)就會有更多的互聯(lián)網(wǎng)公司開始開展秋招了。

          但是也不是說開始就一個月內(nèi)結(jié)束,秋招整體上還是比較長的,根據(jù)去年的經(jīng)驗,能從 8 月份持續(xù)到 12 月份。

          不少同學(xué)就好奇,國企和銀行秋招大概是什么時間段開始呢?我翻了下去年整理的秋招公司列表,發(fā)現(xiàn)大部分銀行和國企公司集中在 9 月份開展秋招。

          今年的話,大概率也是 9 月份開始銀行和國企的秋招,想要沖銀行的同學(xué),8 月份可要好好準(zhǔn)備了,8 月份一過,銀行秋招就開始了。

          銀行的面試難度比互聯(lián)網(wǎng)大廠難度低很多,面試時長大概在 15-30 分鐘,面試過程中被問的一些問題:

          • 技術(shù)問題:Java(基礎(chǔ)、集合、并發(fā)、JVM、Spring)、MySQL(索引+事務(wù))、Redis(問的不算多)、網(wǎng)絡(luò)(HTTP+TCP)、算法(排序算法)
          • 軟問題:校園經(jīng)歷、學(xué)習(xí)經(jīng)歷、職業(yè)發(fā)展、銀行的認(rèn)識、遇到的困難的解決等等。

          面試難度相比互聯(lián)網(wǎng)大廠小了很多,面試時間普遍是 10 多分鐘,就問幾個技術(shù)問題,而且,問的問題也相對比較簡單一些,妥妥羨慕了。

          銀行的薪資雖然比不了大廠,但是年包也有15w-25w,不怎么加班,工作強(qiáng)度低,還是比較舒服的。

          這次給大家分享三家銀行的Java 軟開的面經(jīng),主要是平安銀行、泰隆銀行、杭州銀行,給準(zhǔn)備沖銀行的同學(xué)做一個參考。

          大家看看難度如何?


          平安銀行

          面試內(nèi)容:

          • 自我介紹
          • 校內(nèi)學(xué)生工作經(jīng)歷
          • 期望的工作環(huán)境
          • Java多線程開發(fā)需要注意什么?
          • Java的final作用是什么?
          • mysql的索引介紹一下?
          • Java內(nèi)存泄漏怎么排查?
          • JVM結(jié)構(gòu)介紹一下?
          • SpringBoot了解哪些注解?
          • 對平安銀行的了解?

          接下來針對技術(shù)八股部分, 給大家解析一下

          Java多線程開發(fā)需要注意什么?

          要保證多線程是安全的,不要出現(xiàn)數(shù)據(jù)競爭造成的數(shù)據(jù)混亂的問題。

          Java的線程安全在三個方面體現(xiàn):

          • 原子性:提供互斥訪問,同一時刻只能有一個線程對數(shù)據(jù)進(jìn)行操作,在Java中使用了atomic和synchronized這兩個關(guān)鍵字來確保原子性;
          • 可見性:一個線程對主內(nèi)存的修改可以及時地被其他線程看到,在Java中使用了synchronized和volatile這兩個關(guān)鍵字確保可見性;
          • 有序性:一個線程觀察其他線程中的指令執(zhí)行順序,由于指令重排序,該觀察結(jié)果一般雜亂無序,在Java中使用了happens-before原則來確保有序性。

          除了需要保證多線程安全之外,還需要避免死鎖的問題。

          死鎖只有同時滿足以下四個條件才會發(fā)生:

          • 互斥條件:互斥條件是指多個線程不能同時使用同一個資源
          • 持有并等待條件:持有并等待條件是指,當(dāng)線程 A 已經(jīng)持有了資源 1,又想申請資源 2,而資源 2 已經(jīng)被線程 C 持有了,所以線程 A 就會處于等待狀態(tài),但是線程 A 在等待資源 2 的同時并不會釋放自己已經(jīng)持有的資源 1
          • 不可剝奪條件:不可剝奪條件是指,當(dāng)線程已經(jīng)持有了資源 ,在自己使用完之前不能被其他線程獲取,線程 B 如果也想使用此資源,則只能在線程 A 使用完并釋放后才能獲取。
          • 環(huán)路等待條件:環(huán)路等待條件指的是,在死鎖發(fā)生的時候,兩個線程獲取資源的順序構(gòu)成了環(huán)形鏈

          避免死鎖問題就只需要破環(huán)其中一個條件就可以,最常見的并且可行的就是使用資源有序分配法,來破環(huán)環(huán)路等待條件

          那什么是資源有序分配法呢?線程 A 和 線程 B 獲取資源的順序要一樣,當(dāng)線程 A 是先嘗試獲取資源 A,然后嘗試獲取資源 B 的時候,線程 B 同樣也是先嘗試獲取資源 A,然后嘗試獲取資源 B。也就是說,線程 A 和 線程 B 總是以相同的順序申請自己想要的資源。

          Java的final作用是什么?

          final關(guān)鍵字主要有三個作用:

          1. 修飾變量:當(dāng)一個變量被聲明為final時,它的值就不能被改變。這表示該變量是一個常量(constant)。final變量常用于存儲不應(yīng)改變的數(shù)據(jù),如配置參數(shù)或常量值。示例:
          public class FinalExample {
              final int MY_CONSTANT = 10// 常量
              final String MY_STRING; // 可以稍后初始化,但一旦初始化后不可更改
          }
          1. 修飾方法final方法不能在子類中被重寫(Override)。如果一個方法被聲明為final,那么它的子類就不能提供這個方法的另一個實現(xiàn)版本。這有助于確保方法的實現(xiàn)是固定的,不能被改變。示例:
          public class ParentClass {
              final void myFinalMethod() {
                  // 方法實現(xiàn)
              }
          }
          1. 修飾類:當(dāng)使用final修飾一個類時,該類不能被繼承。一個final類通常代表了一個不會更改的、獨(dú)立的類,如String類或工具類等。這樣做的目的是為了確保該類的完整性和安全。示例:
          public final class FinalClass {
              // 類定義和成員方法等
          }

          綜上,final關(guān)鍵字在Java中用于確保數(shù)據(jù)、方法和類的不可變性

          mysql的索引介紹一下?

          MySQL可以按照四個角度來分類索引。

          • 按「數(shù)據(jù)結(jié)構(gòu)」分類:B+tree索引、Hash索引、Full-text索引
          • 按「物理存儲」分類:聚簇索引(主鍵索引)、二級索引(輔助索引)
          • 按「字段特性」分類:主鍵索引、唯一索引、普通索引、前綴索引
          • 按「字段個數(shù)」分類:單列索引、聯(lián)合索引

          MySQL 默認(rèn)的存儲引擎是 InnoDB ,InnoDB 存儲引擎是用了B+樹作為了索引的數(shù)據(jù)結(jié)構(gòu)。

          B+Tree 是一種多叉樹,葉子節(jié)點(diǎn)才存放數(shù)據(jù),非葉子節(jié)點(diǎn)只存放索引,而且每個節(jié)點(diǎn)里的數(shù)據(jù)是按主鍵順序存放的。每一層父節(jié)點(diǎn)的索引值都會出現(xiàn)在下層子節(jié)點(diǎn)的索引值中,因此在葉子節(jié)點(diǎn)中,包括了所有的索引值信息,并且每一個葉子節(jié)點(diǎn)都有兩個指針,分別指向下一個葉子節(jié)點(diǎn)和上一個葉子節(jié)點(diǎn),形成一個雙向鏈表。

          主鍵索引的 B+Tree 如圖所示:比如,我們執(zhí)行了下面這條查詢語句:

          select * from product where id5;

          這條語句使用了主鍵索引查詢 id 號為 5 的商品。查詢過程是這樣的,B+Tree 會自頂向下逐層進(jìn)行查找:

          • 將 5 與根節(jié)點(diǎn)的索引數(shù)據(jù) (1,10,20) 比較,5 在 1 和 10 之間,所以根據(jù) B+Tree的搜索邏輯,找到第二層的索引數(shù)據(jù) (1,4,7);
          • 在第二層的索引數(shù)據(jù) (1,4,7)中進(jìn)行查找,因為 5 在 4 和 7 之間,所以找到第三層的索引數(shù)據(jù)(4,5,6);
          • 在葉子節(jié)點(diǎn)的索引數(shù)據(jù)(4,5,6)中進(jìn)行查找,然后我們找到了索引值為 5 的行數(shù)據(jù)。

          數(shù)據(jù)庫的索引和數(shù)據(jù)都是存儲在硬盤的,我們可以把讀取一個節(jié)點(diǎn)當(dāng)作一次磁盤 I/O 操作。那么上面的整個查詢過程一共經(jīng)歷了 3 個節(jié)點(diǎn),也就是進(jìn)行了 3 次 I/O 操作。B+Tree 存儲千萬級的數(shù)據(jù)只需要 3-4 層高度就可以滿足,這意味著從千萬級的表查詢目標(biāo)數(shù)據(jù)最多需要 3-4 次磁盤 I/O,所以B+Tree 相比于 B 樹和二叉樹來說,最大的優(yōu)勢在于查詢效率很高,因為即使在數(shù)據(jù)量很大的情況,查詢一個數(shù)據(jù)的磁盤 I/O 依然維持在 3-4次。

          Java內(nèi)存泄漏怎么排查?

          內(nèi)存泄漏是指在程序中申請的內(nèi)存空間,在不需要時沒有被正確釋放,導(dǎo)致這些內(nèi)存空間無法被垃圾回收器回收,從而造成內(nèi)存的浪費(fèi),甚至引起程序的崩潰。內(nèi)存泄漏通常是由于程序設(shè)計或者實現(xiàn)中的錯誤導(dǎo)致的。下面是一些排查內(nèi)存泄漏的方法和思路:

          • 借助工具進(jìn)行分析:可以使用一些內(nèi)存分析工具,如VisualVM、MAT等,通過查看堆內(nèi)存的使用情況和對象實例的情況,找到內(nèi)存泄漏的根源。這些工具可以生成內(nèi)存快照,幫助我們找到哪些對象占用了大量的內(nèi)存空間,以及哪些對象沒有被及時回收等信息,從而找到代碼中存在的問題。
          • 檢查代碼邏輯:通常內(nèi)存泄漏是由于程序設(shè)計或者實現(xiàn)中的錯誤導(dǎo)致的。我們需要仔細(xì)檢查代碼邏輯,尤其是在使用容器類、線程、文件IO等功能時,要特別注意資源的釋放和關(guān)閉。檢查代碼是否存在循環(huán)引用或者對象被多個對象引用的情況,是否存在線程死鎖等問題,以此來定位內(nèi)存泄漏的根源。
          • 通過日志分析定位問題:通過添加適當(dāng)?shù)娜罩荆梢杂涗洺绦虻倪\(yùn)行狀態(tài)、對象的創(chuàng)建和銷毀等信息,從而定位內(nèi)存泄漏的原因。通過分析日志,我們可以找到哪些對象沒有被正確釋放,或者哪些操作導(dǎo)致了內(nèi)存泄漏等信息。
          • 檢查JVM參數(shù):JVM提供了一些參數(shù),可以幫助我們分析內(nèi)存使用情況。比如可以通過-XX:+HeapDumpOnOutOfMemoryError參數(shù),在發(fā)生內(nèi)存溢出時生成內(nèi)存快照,通過分析內(nèi)存快照可以找到內(nèi)存泄漏的根源。還可以通過-XX:+PrintGCDetails參數(shù)打印GC日志,分析GC的情況,找到內(nèi)存泄漏的原因。

          舉個例子,假設(shè)有一個線程池的代碼,由于線程池中的任務(wù)沒有被正確關(guān)閉,導(dǎo)致線程沒有被釋放,最終導(dǎo)致內(nèi)存泄漏。我們可以通過VisualVM工具來查看線程池的使用情況,然后,通過觀察線程池中線程的狀態(tài),可以確定是否存在線程阻塞或等待的情況,進(jìn)而找出具體的問題所在。同時,可以通過VisualVM查看線程的CPU占用情況和內(nèi)存使用情況,從而定位是否存在內(nèi)存泄漏等問題。

          如果發(fā)現(xiàn)存在內(nèi)存泄漏的情況,可以使用VisualVM或其他內(nèi)存分析工具來進(jìn)行分析。首先,需要對內(nèi)存進(jìn)行快照,并對快照進(jìn)行分析,找出哪些對象占用了過多的內(nèi)存。其次,需要確定這些對象是否可以被垃圾回收。如果是不能被垃圾回收的對象,那么需要分析出它們的引用鏈,找出哪些地方持有了對這些對象的引用,以便及時進(jìn)行處理。

          此外,還可以通過代碼審查來發(fā)現(xiàn)潛在的內(nèi)存泄漏問題。一些常見的內(nèi)存泄漏問題包括未關(guān)閉的數(shù)據(jù)庫連接、未關(guān)閉的IO流、靜態(tài)變量未被正確清理等。對于這些問題,可以通過添加合適的try-finally代碼塊、使用try-with-resources語句、顯式調(diào)用close方法等方式來進(jìn)行修復(fù)。

          JVM結(jié)構(gòu)介紹一下?

          根據(jù) JVM8 規(guī)范,JVM 運(yùn)行時內(nèi)存共分為虛擬機(jī)棧、堆、元空間、程序計數(shù)器、本地方法棧五個部分。還有一部分內(nèi)存叫直接內(nèi)存,屬于操作系統(tǒng)的本地內(nèi)存,也是可以直接操作的。JVM的內(nèi)存結(jié)構(gòu)主要分為以下幾個部分:

          • 元空間:元空間的本質(zhì)和永久代類似,都是對JVM規(guī)范中方法區(qū)的實現(xiàn)。不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機(jī)中,而是使用本地內(nèi)存。
          • Java 虛擬機(jī)棧:每個線程有一個私有的棧,隨著線程的創(chuàng)建而創(chuàng)建。棧里面存著的是一種叫“棧幀”的東西,每個方法會創(chuàng)建一個棧幀,棧幀中存放了局部變量表(基本數(shù)據(jù)類型和對象引用)、操作數(shù)棧、方法出口等信息。棧的大小可以固定也可以動態(tài)擴(kuò)展。
          • 本地方法棧:與虛擬機(jī)棧類似,區(qū)別是虛擬機(jī)棧執(zhí)行java方法,本地方法站執(zhí)行native方法。在虛擬機(jī)規(guī)范中對本地方法棧中方法使用的語言、使用方法與數(shù)據(jù)結(jié)構(gòu)沒有強(qiáng)制規(guī)定,因此虛擬機(jī)可以自由實現(xiàn)它。
          • 程序計數(shù)器:程序計數(shù)器可以看成是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。在任何一個確定的時刻,一個處理器(對于多內(nèi)核來說是一個內(nèi)核)都只會執(zhí)行一條線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要一個獨(dú)立的程序計數(shù)器,我們稱這類內(nèi)存區(qū)域為“線程私有”內(nèi)存。
          • 堆內(nèi)存:堆內(nèi)存是 JVM 所有線程共享的部分,在虛擬機(jī)啟動的時候就已經(jīng)創(chuàng)建。所有的對象和數(shù)組都在堆上進(jìn)行分配。這部分空間可通過 GC 進(jìn)行回收。當(dāng)申請不到空間時會拋出 OutOfMemoryError。堆是JVM內(nèi)存占用最大,管理最復(fù)雜的一個區(qū)域。其唯一的用途就是存放對象實例:所有的對象實例及數(shù)組都在對上進(jìn)行分配。jdk1.8后,字符串常量池從永久代中剝離出來,存放在隊中。
          • 直接內(nèi)存:直接內(nèi)存并不是虛擬機(jī)運(yùn)行時數(shù)據(jù)區(qū)的一部分,也不是Java 虛擬機(jī)規(guī)范中農(nóng)定義的內(nèi)存區(qū)域。在JDK1.4 中新加入了NIO(New Input/Output)類,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的I/O 方式,它可以使用native 函數(shù)庫直接分配堆外內(nèi)存,然后通脫一個存儲在Java堆中的DirectByteBuffer 對象作為這塊內(nèi)存的引用進(jìn)行操作。這樣能在一些場景中顯著提高性能,因為避免了在Java堆和Native堆中來回復(fù)制數(shù)據(jù)。

          SpringBoot了解哪些注解?

          1、@SpringBootApplication

          這是 Spring Boot 最最最核心的注解,用在 Spring Boot 主類上,標(biāo)識這是一個 Spring Boot 應(yīng)用,用來開啟 Spring Boot 的各項能力。其實這個注解就是 @SpringBootConfiguration@EnableAutoConfiguration@ComponentScan 這三個注解的組合,也可以用這三個注解來代替 @SpringBootApplication 注解。

          2、@EnableAutoConfiguration

          允許 Spring Boot 自動配置注解,開啟這個注解之后,Spring Boot 就能根據(jù)當(dāng)前類路徑下的包或者類來配置 Spring Bean。如:當(dāng)前類路徑下有 Mybatis 這個 JAR 包,MybatisAutoConfiguration 注解就能根據(jù)相關(guān)參數(shù)來配置 Mybatis 的各個 Spring Bean。

          3、@Configuration

          這是 Spring 3.0 添加的一個注解,用來代替 applicationContext.xml 配置文件,所有這個配置文件里面能做到的事情都可以通過這個注解所在類來進(jìn)行注冊。

          4、@SpringBootConfiguration

          這個注解就是 @Configuration 注解的變體,只是用來修飾是 Spring Boot 配置而已,或者可利于 Spring Boot 后續(xù)的擴(kuò)展。

          5、@ComponentScan

          這是 Spring 3.1 添加的一個注解,用來代替配置文件中的 component-scan 配置,開啟組件掃描,即自動掃描包路徑下的 @Component 注解進(jìn)行注冊 bean 實例到 context 中。

          泰隆銀行

          面試內(nèi)容:

          • 自我介紹
          • 項目亮點(diǎn)。
          • 常見排序算法,復(fù)雜度。快排和冒泡排序?qū)崿F(xiàn)原理。
          • wesocket和http的區(qū)別是什么?
          • 瀏覽器輸入url到頁面展示出來的全過程?
          • 訪問地址,網(wǎng)絡(luò)不通怎么排查?
          • 介紹一下網(wǎng)絡(luò)模型?
          • http和tcp分別屬于什么層?在第幾層?
          • mysql速度慢,怎么優(yōu)化?
          • 樂觀鎖和悲觀鎖區(qū)別是什么?
          • 介紹一下spring的兩大特性
          • jvm內(nèi)存模型介紹一下

          接下來針對技術(shù)八股部分, 給大家解析一下

          說一下常見排序算法的時間復(fù)雜度?

          • 冒泡排序:通過相鄰元素的比較和交換,每次將最大(或最小)的元素逐步“冒泡”到最后(或最前)。時間復(fù)雜度:最好情況下O(n),最壞情況下O(n^2),平均情況下O(n^2),空間復(fù)雜度:O(1)。
          • 插入排序:將待排序元素逐個插入到已排序序列的合適位置,形成有序序列。時間復(fù)雜度:最好情況下O(n),最壞情況下O(n^2),平均情況下O(n^2),空間復(fù)雜度:O(1)。
          • 選擇排序:通過不斷選擇未排序部分的最小(或最大)元素,并將其放置在已排序部分的末尾(或開頭)。時間復(fù)雜度:最好情況下O(n^2),最壞情況下O(n^2),平均情況下O(n^2),空間復(fù)雜度:O(1)。
          • 快速排序):通過選擇一個基準(zhǔn)元素,將數(shù)組劃分為兩個子數(shù)組,使得左子數(shù)組的元素都小于(或等于)基準(zhǔn)元素,右子數(shù)組的元素都大于(或等于)基準(zhǔn)元素,然后對子數(shù)組進(jìn)行遞歸排序。時間復(fù)雜度:最好情況下O(nlogn),最壞情況下O(n^2),平均情況下O(nlogn),空間復(fù)雜度:最好情況下O(logn),最壞情況下O(n)。
          • 歸并排序:將數(shù)組不斷分割為更小的子數(shù)組,然后將子數(shù)組進(jìn)行合并,合并過程中進(jìn)行排序。時間復(fù)雜度:最好情況下O(nlogn),最壞情況下O(nlogn),平均情況下O(nlogn)。空間復(fù)雜度:O(n)。
          • 堆排序:通過將待排序元素構(gòu)建成一個最大堆(或最小堆),然后將堆頂元素與末尾元素交換,再重新調(diào)整堆,重復(fù)該過程直到排序完成。時間復(fù)雜度:最好情況下O(nlogn),最壞情況下O(nlogn),平均情況下O(nlogn)。空間復(fù)雜度:O(1)。

          介紹一下快排的原理

          快排使用了分治策略的思想,所謂分治,顧名思義,就是分而治之,將一個復(fù)雜的問題,分成兩個或多個相似的子問題,在把子問題分成更小的子問題,直到更小的子問題可以簡單求解,求解子問題,則原問題的解則為子問題解的合并。

          快排的過程簡單的說只有三步:

          • 首先從序列中選取一個數(shù)作為基準(zhǔn)數(shù)
          • 將比這個數(shù)大的數(shù)全部放到它的右邊,把小于或者等于它的數(shù)全部放到它的左邊 (一次快排 partition
          • 然后分別對基準(zhǔn)的左右兩邊重復(fù)以上的操作,直到數(shù)組完全排序

          具體按以下步驟實現(xiàn):

          • 1,創(chuàng)建兩個指針分別指向數(shù)組的最左端以及最右端
          • 2,在數(shù)組中任意取出一個元素作為基準(zhǔn)
          • 3,左指針開始向右移動,遇到比基準(zhǔn)大的停止
          • 4,右指針開始向左移動,遇到比基準(zhǔn)小的元素停止,交換左右指針?biāo)赶虻脑?
          • 5,重復(fù)3,4,直到左指針超過右指針,此時,比基準(zhǔn)小的值就都會放在基準(zhǔn)的左邊,比基準(zhǔn)大的值會出現(xiàn)在基準(zhǔn)的右邊
          • 6,然后分別對基準(zhǔn)的左右兩邊重復(fù)以上的操作,直到數(shù)組完全排序

          注意這里的基準(zhǔn)該如何選擇?最簡單的一種做法是每次都是選擇最左邊的元素作為基準(zhǔn),但這對幾乎已經(jīng)有序的序列來說,并不是最好的選擇,它將會導(dǎo)致算法的最壞表現(xiàn)。還有一種做法,就是選擇中間的數(shù)或通過 Math.random() 來隨機(jī)選取一個數(shù)作為基準(zhǔn)。

          640.gif

          代碼實現(xiàn):

          public class QuickSort {
              // 快速排序算法
              public void quickSort(int[] arr, int low, int high) {
                  if (low < high) {
                      int pi = partition(arr, low, high);

                      // 遞歸排序左半部分
                      quickSort(arr, low, pi - 1);
                      // 遞歸排序右半部分
                      quickSort(arr, pi + 1, high);
                  }
              }

              // 劃分函數(shù),用于找到基準(zhǔn)元素的正確位置
              int partition(int[] arr, int low, int high) {
                  int pivot = arr[high]; // 選擇最后一個元素作為基準(zhǔn)
                  int i = low - 1// 初始化較小元素的索引

                  for (int j = low; j < high; j++) {
                      if (arr[j] < pivot) {
                          i++;
                          // 交換元素
                          int temp = arr[i];
                          arr[i] = arr[j];
                          arr[j] = temp;
                      }
                  }

                  // 將基準(zhǔn)元素放到正確的位置
                  int temp = arr[i + 1];
                  arr[i + 1] = arr[high];
                  arr[high] = temp;

                  return i + 1// 返回基準(zhǔn)元素的位置
              }

              public static void main(String[] args) {
                  int[] arr = {1078915};
                  QuickSort quickSort = new QuickSort();
                  quickSort.quickSort(arr, 0, arr.length - 1);
                  System.out.println("Sorted array:");
                  for (int value : arr) {
                      System.out.print(value + " ");
                  }
              }
          }

          介紹一下冒泡排序的實現(xiàn)原理

          冒泡排序會重復(fù)地遍歷要排序的數(shù)列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。遍歷數(shù)列的工作是重復(fù)地進(jìn)行直到?jīng)]有再需要交換,也就是說該數(shù)列已經(jīng)排序完成。

          冒泡排序的實現(xiàn)原理如下:

          1. 比較相鄰的元素:從第一個元素開始,比較相鄰的兩個元素。如果第一個元素比第二個元素大(或小),則交換這兩個元素的位置。
          2. 多次遍歷:持續(xù)遍歷列表,直到?jīng)]有更多的元素需要交換。此時,最大的元素(或最小的元素)會“浮”到列表的一端。
          3. 繼續(xù)此過程:這個過程一直重復(fù)直到整個列表都被排序。隨著列表中最大的元素被移到正確的位置(在列表的一端),然后再次進(jìn)行完整的遍歷以移動下一個最大(或最小)的元素。

          這個過程的關(guān)鍵是每一步都將當(dāng)前未排序的部分的最大(或最小)元素移動到其正確的位置。這樣在每一次迭代中,最小的(或最大的)元素會被"冒泡"到正確的位置,這也是這種算法被稱為冒泡排序的原因。冒泡排序的時間復(fù)雜度是O(n^2),其中n是待排序的元素數(shù)量。這是因為它需要進(jìn)行兩層嵌套循環(huán),外層循環(huán)控制排序的輪數(shù),內(nèi)層循環(huán)則是用來在每一輪中進(jìn)行元素的比較和交換。最壞情況下和平均情況下,都需要遍歷整個列表兩次,所以是O(n^2)。然而,冒泡排序的最好情況(即輸入數(shù)組已經(jīng)是有序的)時間復(fù)雜度是O(n),但在實際應(yīng)用中這種情況較為少見。因此,通常認(rèn)為冒泡排序的時間復(fù)雜度為O(n^2)。

          wesocket和http的區(qū)別是什么?

          • 全雙工和半雙工:TCP 協(xié)議本身是全雙工的,但我們最常用的 HTTP/1.1,雖然是基于 TCP 的協(xié)議,但它是半雙工的,對于大部分需要服務(wù)器主動推送數(shù)據(jù)到客戶端的場景,都不太友好,因此我們需要使用支持全雙工的 WebSocket 協(xié)議。
          • 應(yīng)用場景區(qū)別:在 HTTP/1.1 里,只要客戶端不問,服務(wù)端就不答。基于這樣的特點(diǎn),對于登錄頁面這樣的簡單場景,可以使用定時輪詢或者長輪詢的方式實現(xiàn)服務(wù)器推送(comet)的效果。對于客戶端和服務(wù)端之間需要頻繁交互的復(fù)雜場景,比如網(wǎng)頁游戲,都可以考慮使用 WebSocket 協(xié)議。

          瀏覽器輸入url到頁面展示出來的全過程?

          • 解析URL:分析 URL 所需要使用的傳輸協(xié)議和請求的資源路徑。如果輸入的 URL 中的協(xié)議或者主機(jī)名不合法,將會把地址欄中輸入的內(nèi)容傳遞給搜索引擎。如果沒有問題,瀏覽器會檢查 URL 中是否出現(xiàn)了非法字符,則對非法字符進(jìn)行轉(zhuǎn)義后在進(jìn)行下一過程。
          • 緩存判斷:瀏覽器會判斷所請求的資源是否在緩存里,如果請求的資源在緩存里且沒有失效,那么就直接使用,否則向服務(wù)器發(fā)起新的請求。
          • DNS解析:如果資源不在本地緩存,首先需要進(jìn)行DNS解析。瀏覽器會向本地DNS服務(wù)器發(fā)送域名解析請求,本地DNS服務(wù)器會逐級查詢,最終找到對應(yīng)的IP地址。
          • 獲取MAC地址:當(dāng)瀏覽器得到 IP 地址后,數(shù)據(jù)傳輸還需要知道目的主機(jī) MAC 地址,因為應(yīng)用層下發(fā)數(shù)據(jù)給傳輸層,TCP 協(xié)議會指定源端口號和目的端口號,然后下發(fā)給網(wǎng)絡(luò)層。網(wǎng)絡(luò)層會將本機(jī)地址作為源地址,獲取的 IP 地址作為目的地址。然后將下發(fā)給數(shù)據(jù)鏈路層,數(shù)據(jù)鏈路層的發(fā)送需要加入通信雙方的 MAC 地址,本機(jī)的 MAC 地址作為源 MAC 地址,目的 MAC 地址需要分情況處理。通過將 IP 地址與本機(jī)的子網(wǎng)掩碼相結(jié)合,可以判斷是否與請求主機(jī)在同一個子網(wǎng)里,如果在同一個子網(wǎng)里,可以使用 APR 協(xié)議獲取到目的主機(jī)的 MAC 地址,如果不在一個子網(wǎng)里,那么請求應(yīng)該轉(zhuǎn)發(fā)給網(wǎng)關(guān),由它代為轉(zhuǎn)發(fā),此時同樣可以通過 ARP 協(xié)議來獲取網(wǎng)關(guān)的 MAC 地址,此時目的主機(jī)的 MAC 地址應(yīng)該為網(wǎng)關(guān)的地址。
          • 建立TCP連接:主機(jī)將使用目標(biāo) IP地址和目標(biāo)MAC地址發(fā)送一個TCP SYN包,請求建立一個TCP連接,然后交給路由器轉(zhuǎn)發(fā),等路由器轉(zhuǎn)到目標(biāo)服務(wù)器后,服務(wù)器回復(fù)一個SYN-ACK包,確認(rèn)連接請求。然后,主機(jī)發(fā)送一個ACK包,確認(rèn)已收到服務(wù)器的確認(rèn),然后 TCP 連接建立完成。
          • HTTPS 的 TLS 四次握手:如果使用的是 HTTPS 協(xié)議,在通信前還存在 TLS 的四次握手。
          • 發(fā)送HTTP請求:連接建立后,瀏覽器會向服務(wù)器發(fā)送HTTP請求。請求中包含了用戶需要獲取的資源的信息,例如網(wǎng)頁的URL、請求方法(GET、POST等)等。
          • 服務(wù)器處理請求并返回響應(yīng):服務(wù)器收到請求后,會根據(jù)請求的內(nèi)容進(jìn)行相應(yīng)的處理。例如,如果是請求網(wǎng)頁,服務(wù)器會讀取相應(yīng)的網(wǎng)頁文件,并生成HTTP響應(yīng)。

          訪問地址,網(wǎng)絡(luò)不通怎么排查?

          最直接的辦法就是抓包,排查的思路大概有:

          1. 先確定是服務(wù)端的問題,還是客戶端的問題。先確認(rèn)瀏覽器是否可以訪問其他網(wǎng)站,如果不可以,說明客戶端網(wǎng)絡(luò)自身的問題,然后檢查客戶端網(wǎng)絡(luò)配置(連接wifi正不正常,有沒有插網(wǎng)線);如果可以正常其他網(wǎng)頁,說明客戶端網(wǎng)絡(luò)是可以正常上網(wǎng)的。
          2. 如果客戶端網(wǎng)絡(luò)沒問題,就抓包確認(rèn) DNS 是否解析出了 IP 地址,如果沒有解析出來,說明域名寫錯了,如果解析出了 IP 地址,抓包確認(rèn)有沒有和服務(wù)端建立三次握手,如果能成功建立三次握手,并且發(fā)出了 HTTP 請求,但是就是沒有顯示頁面,可以查看服務(wù)端返回的響應(yīng)碼:
            • 如果是404錯誤碼,檢查輸入的url是否正確;
            • 如果是500,說明服務(wù)器此時有問題;
            • 如果是200,F(xiàn)12看看前端代碼有問題導(dǎo)致瀏覽器沒有渲染出頁面。
          3. 如果客戶端網(wǎng)絡(luò)是正常的,但是訪問速度很慢,導(dǎo)致很久才顯示出來。這時候要看客戶端的網(wǎng)口流量是否太大的了,導(dǎo)致tcp發(fā)生丟包之類的問題。

          總之就是一層一層有沒有插網(wǎng)線,網(wǎng)絡(luò)配置是否正確、DNS有沒有解析出 IP地址、TCP有沒有三次握手、HTTP返回的響應(yīng)碼是什么。

          推薦閱讀:網(wǎng)站顯示不出來,怎么排查?

          介紹一下網(wǎng)絡(luò)模型?

          OSI七層模型

          為了使得多種設(shè)備能通過網(wǎng)絡(luò)相互通信,和為了解決各種不同設(shè)備在網(wǎng)絡(luò)互聯(lián)中的兼容性問題,國際標(biāo)準(zhǔn)化組織制定了開放式系統(tǒng)互聯(lián)通信參考模型(_Open System Interconnection Reference Model_),也就是 OSI 網(wǎng)絡(luò)模型,該模型主要有 7 層,分別是應(yīng)用層、表示層、會話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層以及物理層。每一層負(fù)責(zé)的職能都不同,如下:

          • 應(yīng)用層,負(fù)責(zé)給應(yīng)用程序提供統(tǒng)一的接口;
          • 表示層,負(fù)責(zé)把數(shù)據(jù)轉(zhuǎn)換成兼容另一個系統(tǒng)能識別的格式;
          • 會話層,負(fù)責(zé)建立、管理和終止表示層實體之間的通信會話;
          • 傳輸層,負(fù)責(zé)端到端的數(shù)據(jù)傳輸;
          • 網(wǎng)絡(luò)層,負(fù)責(zé)數(shù)據(jù)的路由、轉(zhuǎn)發(fā)、分片;
          • 數(shù)據(jù)鏈路層,負(fù)責(zé)數(shù)據(jù)的封幀和差錯檢測,以及 MAC 尋址;
          • 物理層,負(fù)責(zé)在物理網(wǎng)絡(luò)中傳輸數(shù)據(jù)幀;

          由于 OSI 模型實在太復(fù)雜,提出的也只是概念理論上的分層,并沒有提供具體的實現(xiàn)方案。

          事實上,我們比較常見,也比較實用的是四層模型,即 TCP/IP 網(wǎng)絡(luò)模型,Linux 系統(tǒng)正是按照這套網(wǎng)絡(luò)模型來實現(xiàn)網(wǎng)絡(luò)協(xié)議棧的。

          TCP/IP模型

          TCP/IP協(xié)議被組織成四個概念層,其中有三層對應(yīng)于ISO參考模型中的相應(yīng)層。ICP/IP協(xié)議族并不包含物理層和數(shù)據(jù)鏈路層,因此它不能獨(dú)立完成整個計算機(jī)網(wǎng)絡(luò)系統(tǒng)的功能,必須與許多其他的協(xié)議協(xié)同工作。TCP/IP 網(wǎng)絡(luò)通常是由上到下分成 4 層,分別是應(yīng)用層,傳輸層,網(wǎng)絡(luò)層和網(wǎng)絡(luò)接口層

          • 應(yīng)用層 支持 HTTP、SMTP 等最終用戶進(jìn)程
          • 傳輸層 處理主機(jī)到主機(jī)的通信(TCP、UDP)
          • 網(wǎng)絡(luò)層 尋址和路由數(shù)據(jù)包(IP 協(xié)議)
          • 鏈路層 通過網(wǎng)絡(luò)的物理電線、電纜或無線信道移動比特

          http和tcp分別屬于什么層?在第幾層?

          • http是在應(yīng)用層,在OSI七層模型中的第七層
          • tcp 是在傳輸層,在OSI七層模型中的第四層

          mysql速度慢,怎么優(yōu)化?

          • 分析查詢語句:使用EXPLAIN命令分析SQL執(zhí)行計劃,找出慢查詢的原因,比如是否使用了全表掃描,是否存在索引未被利用的情況等,并根據(jù)相應(yīng)情況對索引進(jìn)行適當(dāng)修改。
          • 創(chuàng)建或優(yōu)化索引:根據(jù)查詢條件創(chuàng)建合適的索引,特別是經(jīng)常用于WHERE子句的字段、Orderby 排序的字段、Join 連表查詢的字典、 group by的字段,并且如果查詢中經(jīng)常涉及多個字段,考慮創(chuàng)建聯(lián)合索引,使用聯(lián)合索引要符合最左匹配原則,不然會索引失效
          • 避免索引失效:比如不要用左模糊匹配、函數(shù)計算、表達(dá)式計算等等。
          • 查詢優(yōu)化:避免使用SELECT *,只查詢真正需要的列;使用覆蓋索引,即索引包含所有查詢的字段;聯(lián)表查詢最好要以小表驅(qū)動大表,并且被驅(qū)動表的字段要有索引,當(dāng)然最好通過冗余字段的設(shè)計,避免聯(lián)表查詢。
          • 分頁優(yōu)化:針對 limit n,y 深分頁的查詢優(yōu)化,可以把Limit查詢轉(zhuǎn)換成某個位置的查詢:select * from tb_sku where id>20000 limit 10,該方案適用于主鍵自增的表,
          • 優(yōu)化數(shù)據(jù)庫表:如果單表的數(shù)據(jù)超過了千萬級別,考慮是否需要將大表拆分為小表,減輕單個表的查詢壓力。也可以將字段多的表分解成多個表,有些字段使用頻率高,有些低,數(shù)據(jù)量大時,會由于使用頻率低的存在而變慢,可以考慮分開。
          • 使用緩存技術(shù):引入緩存層,如Redis,存儲熱點(diǎn)數(shù)據(jù)和頻繁查詢的結(jié)果,但是要考慮緩存一致性的問題,對于讀請求會選擇旁路緩存策略,對于寫請求會選擇先更新 db,再刪除緩存的策略。

          樂觀鎖和悲觀鎖區(qū)別是什么?

          樂觀鎖:

          • 基本思想:樂觀鎖假設(shè)多個事務(wù)之間很少發(fā)生沖突,因此在讀取數(shù)據(jù)時不會加鎖,而是在更新數(shù)據(jù)時檢查數(shù)據(jù)的版本(如使用版本號或時間戳),如果版本匹配則執(zhí)行更新操作,否則認(rèn)為發(fā)生了沖突。
          • 使用場景:樂觀鎖適用于讀多寫少的場景,可以減少鎖的競爭,提高并發(fā)性能。例如,數(shù)據(jù)庫中的樂觀鎖機(jī)制可以用于處理并發(fā)更新同一行數(shù)據(jù)的情況。

          悲觀鎖:

          • 基本思想:悲觀鎖假設(shè)多個事務(wù)之間會頻繁發(fā)生沖突,因此在讀取數(shù)據(jù)時會加鎖,防止其他事務(wù)對數(shù)據(jù)進(jìn)行修改,直到當(dāng)前事務(wù)完成操作后才釋放鎖。
          • 使用場景:悲觀鎖適用于寫多的場景,通過加鎖保證數(shù)據(jù)的一致性。例如,數(shù)據(jù)庫中的行級鎖機(jī)制可以用于處理并發(fā)更新同一行數(shù)據(jù)的情況。

          樂觀鎖適用于讀多寫少的場景,通過版本控制來處理沖突;而悲觀鎖適用于寫多的場景,通過加鎖來避免沖突。

          介紹一下spring的兩大特性?

          Spring IoC和AOP 區(qū)別:

          • IoC:即控制反轉(zhuǎn)的意思,它是一種創(chuàng)建和獲取對象的技術(shù)思想,依賴注入(DI)是實現(xiàn)這種技術(shù)的一種方式。傳統(tǒng)開發(fā)過程中,我們需要通過new關(guān)鍵字來創(chuàng)建對象。使用IoC思想開發(fā)方式的話,我們不通過new關(guān)鍵字創(chuàng)建對象,而是通過IoC容器來幫我們實例化對象。通過IoC的方式,可以大大降低對象之間的耦合度。
          • AOP:是面向切面編程,能夠?qū)⒛切┡c業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯封裝起來,以減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度。Spring AOP 就是基于動態(tài)代理的,如果要代理的對象,實現(xiàn)了某個接口,那么 Spring AOP 會使用 JDK Proxy,去創(chuàng)建代理對象,而對于沒有實現(xiàn)接口的對象,就無法使用 JDK Proxy 去進(jìn)行代理了,這時候 Spring AOP 會使用 Cglib 生成一個被代理對象的子類來作為代理。

          在 Spring 框架中,IOC 和 AOP 結(jié)合使用,可以更好地實現(xiàn)代碼的模塊化和分層管理。例如:

          • 通過 IOC 容器管理對象的依賴關(guān)系,然后通過 AOP 將橫切關(guān)注點(diǎn)統(tǒng)一切入到需要的業(yè)務(wù)邏輯中。
          • 使用 IOC 容器管理 Service 層和 DAO 層的依賴關(guān)系,然后通過 AOP 在 Service 層實現(xiàn)事務(wù)管理、日志記錄等橫切功能,使得業(yè)務(wù)邏輯更加清晰和可維護(hù)。

          jvm內(nèi)存模型介紹一下

          前面已經(jīng)寫過,不做重復(fù)。

          杭州銀行

          面試內(nèi)容:

          • 自我介紹
          • 大學(xué)學(xué)習(xí)的專業(yè)課都是什么
          • 有沒有學(xué)習(xí)過Java?
          • 然后又問了我的項目
          • Spring三件套框架說一下?
          • HashMap的底層實現(xiàn)原理?
          • HashMap和HashSet區(qū)別?
          • HashSet如何檢查重復(fù)?
          • ==和equals區(qū)別?
          • equals如何判斷兩個對象相同?

          接下來針對技術(shù)八股部分, 給大家解析一下

          Spring三件套框架說一下?

          Spring三件套,也稱為Spring開發(fā)三劍客,是指Spring框架的核心組件,包括Spring框架、Spring Boot和Spring Cloud。

          1. Spring框架:Spring框架是一個輕量級的開源Java框架,主要用于簡化Java應(yīng)用程序的開發(fā)。它提供了一種開發(fā)企業(yè)級應(yīng)用的綜合解決方案,通過IoC(控制反轉(zhuǎn))和AOP(面向切面編程)等特性,使應(yīng)用開發(fā)更加靈活、簡單、高效。Spring框架提供了許多功能模塊,如Spring Core、Spring MVC、Spring Data、Spring Security等,能滿足不同應(yīng)用場景下的需求。
          2. Spring Boot:Spring Boot是基于Spring框架的快速開發(fā)框架,旨在簡化Spring應(yīng)用程序的搭建和部署。它通過默認(rèn)配置和自動化配置的方式,大大減少了開發(fā)者在應(yīng)用程序配置上的工作量,提高了開發(fā)效率。Spring Boot還集成了常用的功能模塊,如Web開發(fā)、數(shù)據(jù)庫訪問、消息隊列等,開發(fā)者只需通過少量的配置即可快速構(gòu)建出可部署的應(yīng)用程序。
          3. Spring Cloud:Spring Cloud是基于Spring Boot的微服務(wù)框架,用于構(gòu)建分布式系統(tǒng)和云原生應(yīng)用。它提供了多個工具和組件,如服務(wù)發(fā)現(xiàn)、配置管理、消息總線等,幫助開發(fā)者構(gòu)建可伸縮、彈性和高可用的分布式應(yīng)用。Spring Cloud還集成了諸如Netflix的開源組件,如Eureka、Ribbon、Hystrix等,提供了完善的微服務(wù)解決方案。

          HashMap的底層實現(xiàn)原理?

          在 JDK 1.7 版本之前, HashMap 數(shù)據(jù)結(jié)構(gòu)是數(shù)組和鏈表,HashMap通過哈希算法將元素的鍵(Key)映射到數(shù)組中的槽位(Bucket)。如果多個鍵映射到同一個槽位,它們會以鏈表的形式存儲在同一個槽位上,因為鏈表的查詢時間是O(n),所以沖突很嚴(yán)重,一個索引上的鏈表非常長,效率就很低了。所以在 JDK 1.8 版本的時候做了優(yōu)化,當(dāng)一個鏈表的長度超過8的時候就轉(zhuǎn)換數(shù)據(jù)結(jié)構(gòu),不再使用鏈表存儲,而是使用紅黑樹,查找時使用紅黑樹,時間復(fù)雜度O(log n),可以提高查詢性能,但是在數(shù)量較少時,即數(shù)量小于6時,會將紅黑樹轉(zhuǎn)換回鏈表。

          HashMap和HashSet區(qū)別?

          • HashMap線程不安全,效率高一點(diǎn),可以存儲null的key和value,null的key只能有一個,null的value可以有多個。默認(rèn)初始容量為16,每次擴(kuò)充變?yōu)樵瓉?倍。創(chuàng)建時如果給定了初始容量,則擴(kuò)充為2的冪次方大小。底層數(shù)據(jù)結(jié)構(gòu)為數(shù)組+鏈表,插入元素后如果鏈表長度大于閾值(默認(rèn)為8),先判斷數(shù)組長度是否小于64,如果小于,則擴(kuò)充數(shù)組,反之將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時間。
          • HashTable線程安全,效率低一點(diǎn),其內(nèi)部方法基本都經(jīng)過synchronized修飾,不可以有null的key和value。默認(rèn)初始容量為11,每次擴(kuò)容變?yōu)樵瓉淼?n+1。創(chuàng)建時給定了初始容量,會直接用給定的大小。底層數(shù)據(jù)結(jié)構(gòu)為數(shù)組+鏈表。它基本被淘汰了,要保證線程安全可以用ConcurrentHashMap。

          HashSet如何檢查重復(fù)?

          當(dāng)把對象加入HashSet時,HashSet會先計算對象的hashcode值來判斷對象加入的位置,同時也會與其他加入的對象的hashcode值作比較,如果沒有相符的hashcode,HashSet會假設(shè)對象沒有重復(fù)出現(xiàn)。

          但是如果發(fā)現(xiàn)有相同hashcode值的對象,這時會調(diào)用equals()方法來檢查hashcode相等的對象是否真的相同。如果兩者相同,HashSet就不會讓加入操作成功。

          hashCode()與equals()的相關(guān)規(guī)定:

          • 如果兩個對象相等,則hashcode一定也是相同的
          • 兩個對象相等,對兩個equals方法返回true
          • 兩個對象有相同的hashcode值,它們也不一定是相等的
          • 綜上,equals方法被覆蓋過,則hashCode方法也必須被覆蓋
          • hashCode()的默認(rèn)行為是對堆上的對象產(chǎn)生獨(dú)特值。如果沒有重寫hashCode(),則該class的兩個對象無論如何都不會相等(即使這兩個對象指向相同的數(shù)據(jù))。

          ==和equals區(qū)別?

          == 對于基本類型來說是值比較,對于引用類型來說是比較的是引用;而 equals 默認(rèn)情況下是引用比較,只是很多類重新了 equals 方法,比如 String、Integer 等把它變成了值比較,所以一般情況下 equals 比較的是值是否相等。

          • 對于字符串變量來說,使用"=="和"equals"比較字符串時,其比較方法不同。"=="比較兩個變量本身的值,即兩個對象在內(nèi)存中的首地址,"equals"比較字符串包含內(nèi)容是否相同。
          • 對于非字符串變量來說,如果沒有對equals()進(jìn)行重寫的話,"==" 和 "equals"方法的作用是相同的,都是用來比較對象在堆內(nèi)存中的首地址,即用來比較兩個引用變量是否指向同一個對象。

          equals如何判斷兩個對象相同?

          默認(rèn)情況下,equals() 方法只是比較兩個對象的內(nèi)存地址是否相同,即比較引用是否相同。以下是Object類中equals()方法的源代碼:

          public boolean equals(Object o) {
              return (this == o);
          }

          這行代碼使用==運(yùn)算符來比較當(dāng)前對象與傳入的參數(shù)對象是否為同一個對象的引用。

          在大多數(shù)情如果要判斷對象的內(nèi)容是否相同,則需要重寫 equals() 方法,則通過用戶自定義的邏輯進(jìn)行比較,例如比較某些屬性值是否相同。

          例如,如果你有一個Person類,它有nameage兩個屬性,你可以這樣重寫equals()方法:

          public class Person {
              private String name;
              private int age;

              // ... 其他方法 ...

              @Override
              public boolean equals(Object o) {
                  if (this == o) return true// 如果是同一個對象引用,直接返回true
                  if (o == null || getClass() != o.getClass()) return false// 如果是null或者類型不同,返回false
                  Person person = (Person) o; // 強(qiáng)制類型轉(zhuǎn)換
                  return age == person.age && 
                         (name != null ? name.equals(person.name) : person.name == null); // 比較name屬性時注意null值處理
              }
          }

          當(dāng)你需要比較兩個Person對象時,只需調(diào)用它們的equals()方法并傳入另一個對象作為參數(shù):

          Person person1 = new Person(/* ... */); // 假設(shè)已經(jīng)初始化好了person1的屬性
          Person person2 = new Person(/* ... */); // 假設(shè)已經(jīng)初始化好了person2的屬性
          if (person1.equals(person2)) {
              // 兩個對象的內(nèi)容相同
          else {
              // 不同
          }

          注意:在重寫equals()方法時,通常還需要同時重寫hashCode()方法,因為它們一起用于Java的哈希表等數(shù)據(jù)結(jié)構(gòu)中的鍵值對的比較和存儲。

          記住:比較對象的“相等性”應(yīng)當(dāng)始終根據(jù)具體的業(yè)務(wù)需求和類設(shè)計來決定如何實現(xiàn)。有時我們不僅比較屬性值是否相同,還可能涉及其他復(fù)雜條件或規(guī)則。

          推薦閱讀:

          終于成了!網(wǎng)站又整了個大的!

          瀏覽 26
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产AV直播 | 青青草网 | 99精品国产综合久久久久久欧美 | 亚洲成人免费视频 | 黄色视频网站一级片 |