第一次面阿里,難繃!
共 17837字,需瀏覽 36分鐘
·
2024-05-27 15:30
圖解學習網站:https://xiaolincoding.com
大家好,我是小林。
今天分享的是一位讀者的阿里巴巴Java后端的面經,阿里畢竟是 Java 大廠,這次的面試重點是以 Java 為主,MySQL+網絡為輔。
感覺問的問題還挺多的,面試時長有 1小時+,壓力不小,面試官一直追問。
面試考察的內容,我?guī)痛蠹伊_列一下:
-
MySQL:事務、數據庫文件、索引、MVCC -
網絡:HTTP報文、HTTP狀態(tài)碼 -
Java 框架:mybatis、springIoc、spirngAop、springMVC -
Java八股:設計模式、多線程并發(fā)問題、線程池、集合、面向對象
問題記錄
MySQL
可重復讀,已提交讀,這兩個隔離級別表現的現象是什么,區(qū)別是什么樣的?
-
讀提交,指一個事務提交之后,它做的變更才能被其他事務看到,會有不可重復讀、幻讀的問題。 -
可重復讀,指一個事務執(zhí)行過程中看到的數據,一直跟這個事務啟動時看到的數據是一致的,MySQL InnoDB 引擎的默認隔離級別,解決了不可重復讀的問題,并且以很大程度上避免幻讀現象的發(fā)生。
數據管理里,數據文件大體分成哪幾種數據文件?
我們每創(chuàng)建一個 database(數據庫) 都會在 /var/lib/mysql/ 目錄里面創(chuàng)建一個以 database 為名的目錄,然后保存表結構和表數據的文件都會存放在這個目錄里。比如,我這里有一個名為 my_test 的 database,該 database 里有一張名為 t_order 數據庫表。然后,我們進入 /var/lib/mysql/my_test 目錄,看看里面有什么文件?
[root@xiaolin ~]#ls /var/lib/mysql/my_test
db.opt
t_order.frm
t_order.ibd
可以看到,共有三個文件,這三個文件分別代表著:
-
db.opt,用來存儲當前數據庫的默認字符集和字符校驗規(guī)則。 -
t_order.frm ,t_order 的表結構會保存在這個文件。在 MySQL 中建立一張表都會生成一個.frm 文件,該文件是用來保存每個表的元數據信息的,主要包含表結構定義。 -
t_order.ibd,t_order 的表數據會保存在這個文件。表數據既可以存在共享表空間文件(文件名:ibdata1)里,也可以存放在獨占表空間文件(文件名:表名字.ibd)。這個行為是由參數 innodb_file_per_table 控制的,若設置了參數 innodb_file_per_table 為 1,則會將存儲的數據、索引等信息單獨存儲在一個獨占表空間,從 MySQL 5.6.6 版本開始,它的默認值就是 1 了,因此從這個版本之后, MySQL 中每一張表的數據都存放在一個獨立的 .ibd 文件。
日志文件是分成了哪幾種?
-
redo log 重做日志,是 Innodb 存儲引擎層生成的日志,實現了事務中的持久性,主要用于掉電等故障恢復; -
undo log 回滾日志,是 Innodb 存儲引擎層生成的日志,實現了事務中的原子性,主要用于事務回滾和 MVCC。 -
bin log 二進制日志,是 Server 層生成的日志,主要用于數據備份和主從復制; -
relay log 中繼日志,用于主從復制場景下,slave通過io線程拷貝master的bin log后本地生成的日志 -
慢查詢日志,用于記錄執(zhí)行時間過長的sql,需要設置閾值后手動開啟
說下MVCC機制的原理?
MVCC就是多版本并發(fā)控制,實現了讀寫的并發(fā)控制,在mysql通過readview 隱藏字段和undolog實現了,比如在可重復讀里面,比如開啟了一個事務,就生成了一個readview,然后記錄現在active的事務,判斷查詢的數據在這個事務可不可讀。
索引的類型有哈希索引,B+樹索引,而hash索引的時間復雜度是o1,那為什么我們一般情況下不使用哈希索引,而使用b+樹索引呢?
-
哈希索引的key是經過hash運算得出的,即跟實際數據的值沒有關系,因此哈希索引不適用于范圍查詢和排序操作 -
容易導致全表掃描,因為可能存在不同的key經過hash運算后值相同 -
索引列上的值相同的話,易造成hash沖突,效率低下
對一個慢sql怎么去排查?
-
可通過開啟mysql的慢日志查詢,設置好時間閾值,進行捕獲慢 sql -
針對慢 sql,進行 explian 去查看執(zhí)行計劃
索引字段是不是建的越多越好?
不是,建的的越多會占用越多的空間,而且在寫入頻繁的場景下,對于B+樹的維護所付出的性能消耗也會越大
網絡
http協議的報文的格式有了解嗎?
分請求報文和響應報文來說明。請求報文:在這里插入圖片描述
-
請求行:包含請求方法、請求目標(URL或URI)和HTTP協議版本。 -
請求頭部:包含關于請求的附加信息,如Host、User-Agent、Content-Type等。 -
空行:請求頭部和請求體之間用空行分隔。 -
請求體:可選,包含請求的數據,通常用于POST請求等需要傳輸數據的情況。
響應報文:
-
狀態(tài)行:包含HTTP協議版本、狀態(tài)碼和狀態(tài)信息。 -
響應頭部:包含關于響應的附加信息,如Content-Type、Content-Length等。 -
空行:響應頭部和響應體之間用空行分隔。 -
響應體:包含響應的數據,通常是服務器返回的HTML、JSON等內容。
http常用的狀態(tài)碼?
HTTP 狀態(tài)碼分為 5 大類:1XX:表示消息狀態(tài)碼;2XX:表示成功狀態(tài)碼;3XX:表示重定向狀態(tài)碼;4XX:表示客戶端錯誤狀態(tài)碼;5XX:表示服務端錯誤狀態(tài)碼。五大類 HTTP 狀態(tài)碼 其中常見的具體狀態(tài)碼有:200:請求成功;301:永久重定向;302:臨時重定向;404:無法找到此頁面;405:請求的方法類型不支持;500:服務器內部出錯。
Java框架
java這一塊對框架都是熟悉的吧?
還行,用過SSM。
MyBatis運用了哪些常見的設計模式?
-
建造者模式(Builder),如:SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder等; -
工廠模式,如:SqlSessionFactory、ObjectFactory、MapperProxyFactory; -
單例模式,例如ErrorContext和LogFactory; -
代理模式,Mybatis實現的核心,比如MapperProxy、ConnectionLogger,用的jdk的動態(tài)代理;還有executor.loader包使用了cglib或者javassist達到延遲加載的效果; -
組合模式,例如SqlNode和各個子類ChooseSqlNode等; -
模板方法模式,例如BaseExecutor和SimpleExecutor,還有BaseTypeHandler和所有的子類例如IntegerTypeHandler; -
適配器模式,例如Log的Mybatis接口和它對jdbc、log4j等各種日志框架的適配實現; -
裝飾者模式,例如Cache包中的cache.decorators子包中等各個裝飾者的實現; -
迭代器模式,例如迭代器模式PropertyTokenizer;
MyBatis中創(chuàng)建了一個Mapper接口,在寫一個xml文件,java的接口是要實現的,為什么這沒有實現呢?
因為執(zhí)行Sql所需要的所有的JDBC操作都在Mybatis的MapperProxy中實現了,所以不需要實現類。
與傳統的JDBC相比,MyBatis的優(yōu)點?
-
基于 SQL 語句編程,相當靈活,不會對應用程序或者數據庫的現有設計造成任 何影響,SQL 寫在 XML 里,解除 sql 與程序代碼的耦合,便于統一管理;提供 XML 標簽,支持編寫動態(tài) SQL 語句,并可重用。 -
與 JDBC 相比,減少了 50%以上的代碼量,消除了 JDBC 大量冗余的代碼,不 需要手動開關連接; -
很好的與各種數據庫兼容,因為 MyBatis 使用 JDBC 來連接數據庫,所以只要 JDBC 支持的數據庫 MyBatis 都支持。 -
能夠與 Spring 很好的集成,開發(fā)效率高 -
提供映射標簽,支持對象與數據庫的 ORM 字段關系映射;提供對象關系映射 標簽,支持對象關系組件維護。
還記得JDBC連接數據庫的步驟嗎?
使用Java JDBC連接數據庫的一般步驟如下:
-
加載數據庫驅動程序:在使用JDBC連接數據庫之前,需要加載相應的數據庫驅動程序。可以通過 Class.forName("com.mysql.jdbc.Driver") 來加載MySQL數據庫的驅動程序。不同數據庫的驅動類名會有所不同。 -
建立數據庫連接:使用 DriverManager 類的 getConnection(url, username, password) 方法來連接數據庫,其中url是數據庫的連接字符串(包括數據庫類型、主機、端口等)、username是數據庫用戶名,password是密碼。 -
創(chuàng)建 Statement 對象:通過 Connection 對象的 createStatement() 方法創(chuàng)建一個 Statement 對象,用于執(zhí)行 SQL 查詢或更新操作。 -
執(zhí)行 SQL 查詢或更新操作:使用 Statement 對象的 executeQuery(sql) 方法來執(zhí)行 SELECT 查詢操作,或者使用 executeUpdate(sql) 方法來執(zhí)行 INSERT、UPDATE 或 DELETE 操作。 -
處理查詢結果:如果是 SELECT 查詢操作,通過 ResultSet 對象來處理查詢結果??梢允褂?ResultSet 的 next() 方法遍歷查詢結果集,然后通過 getXXX() 方法獲取各個字段的值。 -
關閉連接:在完成數據庫操作后,需要逐級關閉數據庫連接相關對象,即先關閉 ResultSet,再關閉 Statement,最后關閉 Connection。
以下是一個簡單的示例代碼:
import java.sql.*;
public class Main {
public static void main(String[] args) {
try {
// 加載數據庫驅動程序
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立數據庫連接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydatabase", "username", "password");
// 創(chuàng)建 Statement 對象
Statement statement = connection.createStatement();
// 執(zhí)行 SQL 查詢
ResultSet resultSet = statement.executeQuery("SELECT * FROM mytable");
// 處理查詢結果
while (resultSet.next()) {
// 處理每一行數據
}
// 關閉資源
resultSet.close();
statement.close();
connection.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
請注意,在實際應用中,需要進行異常處理以確保資源的正確釋放,以及使用 try-with-resources 來簡化代碼和確保資源的及時關閉。
怎么理解SpringIoc?
IOC:Inversion Of Control,即控制反轉,是一種設計思想。在傳統的 Java SE 程序設計中,我們直接在對象內部通過 new 的方式來創(chuàng)建對象,是程序主動創(chuàng)建依賴對象;
而在Spring程序設計中,IOC 是有專門的容器去控制對象。
所謂控制就是對象的創(chuàng)建、初始化、銷毀。
-
創(chuàng)建對象:原來是 new 一個,現在是由 Spring 容器創(chuàng)建。 -
初始化對象:原來是對象自己通過構造器或者 setter 方法給依賴的對象賦值,現在是由 Spring 容器自動注入。 -
銷毀對象:原來是直接給對象賦值 null 或做一些銷毀操作,現在是 Spring 容器管理生命周期負責銷毀對象。
總結:IOC 解決了繁瑣的對象生命周期的操作,解耦了我們的代碼。所謂反轉:其實是反轉的控制權,前面提到是由 Spring 來控制對象的生命周期,那么對象的控制就完全脫離了我們的控制,控制權交給了 Spring 。這個反轉是指:我們由對象的控制者變成了 IOC 的被動控制者。
如果讓你設計一個SpringIoc,你覺得會從哪些方面考慮這個設計?
-
Bean的生命周期管理:需要設計Bean的創(chuàng)建、初始化、銷毀等生命周期管理機制,可以考慮使用工廠模式和單例模式來實現。 -
依賴注入:需要實現依賴注入的功能,包括屬性注入、構造函數注入、方法注入等,可以考慮使用反射機制和XML配置文件來實現。 -
Bean的作用域:需要支持多種Bean作用域,比如單例、原型、會話、請求等,可以考慮使用Map來存儲不同作用域的Bean實例。 -
AOP功能的支持:需要支持AOP功能,可以考慮使用動態(tài)代理機制和切面編程來實現。 -
異常處理:需要考慮異常處理機制,包括Bean創(chuàng)建異常、依賴注入異常等,可以考慮使用try-catch機制來處理異常。 -
配置文件加載:需要支持從不同的配置文件中加載Bean的相關信息,可以考慮使用XML、注解或者Java配置類來實現。
Spring給我們提供了很多擴展點,這些有了解嗎?
Spring框架提供了許多擴展點,使得開發(fā)者可以根據需求定制和擴展Spring的功能。以下是一些常用的擴展點:
-
BeanFactoryPostProcessor:允許在Spring容器實例化bean之前修改bean的定義。常用于修改bean屬性或改變bean的作用域。 -
BeanPostProcessor:可以在bean實例化、配置以及初始化之后對其進行額外處理。常用于代理bean、修改bean屬性等。 -
PropertySource:用于定義不同的屬性源,如文件、數據庫等,以便在Spring應用中使用。 -
ImportSelector和ImportBeanDefinitionRegistrar:用于根據條件動態(tài)注冊bean定義,實現配置類的模塊化。 -
Spring MVC中的HandlerInterceptor:用于攔截處理請求,可以在請求處理前、處理中和處理后執(zhí)行特定邏輯。 -
Spring MVC中的ControllerAdvice:用于全局處理控制器的異常、數據綁定和數據校驗。 -
Spring Boot的自動配置:通過創(chuàng)建自定義的自動配置類,可以實現對框架和第三方庫的自動配置。 -
自定義注解:創(chuàng)建自定義注解,用于實現特定功能或約定,如權限控制、日志記錄等。
servlet有寫過簡單的代碼嗎?
沒用框架之前,就用的servlet,用了框架就用的框架
大致了解SpringMVC的處理流程嗎?
Spring MVC的工作流程如下:
-
用戶發(fā)送請求至前端控制器DispatcherServlet -
DispatcherServlet收到請求調用處理器映射器HandlerMapping。 -
處理器映射器根據請求url找到具體的處理器,生成處理器執(zhí)行鏈HandlerExecutionChain(包括處理器對象和處理器攔截器)一并返回給DispatcherServlet。 -
DispatcherServlet根據處理器Handler獲取處理器適配器HandlerAdapter執(zhí)行HandlerAdapter處理一系列的操作,如:參數封裝,數據格式轉換,數據驗證等操作 -
執(zhí)行處理器Handler(Controller,也叫頁面控制器)。 -
Handler執(zhí)行完成返回ModelAndView -
HandlerAdapter將Handler執(zhí)行結果ModelAndView返回到DispatcherServlet -
DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器 -
ViewReslover解析后返回具體View -
DispatcherServlet對View進行渲染視圖(即將模型數據model填充至視圖中)。 -
DispatcherServlet響應用戶。
Handlermapping 和 handleradapter有了解嗎?
HandlerMapping:
-
作用:HandlerMapping負責將請求映射到處理器(Controller)。 -
功能:根據請求的URL、請求參數等信息,找到處理請求的 Controller。 -
類型:Spring提供了多種HandlerMapping實現,如BeanNameUrlHandlerMapping、RequestMappingHandlerMapping等。 -
工作流程:根據請求信息確定要請求的處理器(Controller)。HandlerMapping可以根據URL、請求參數等規(guī)則確定對應的處理器。
HandlerAdapter:
-
作用:HandlerAdapter負責調用處理器(Controller)來處理請求。 -
功能:處理器(Controller)可能有不同的接口類型(Controller接口、HttpRequestHandler接口等),HandlerAdapter根據處理器的類型來選擇合適的方法來調用處理器。 -
類型:Spring提供了多個HandlerAdapter實現,用于適配不同類型的處理器。 -
工作流程:根據處理器的接口類型,選擇相應的HandlerAdapter來調用處理器。
工作流程:
-
當客戶端發(fā)送請求時,HandlerMapping根據請求信息找到對應的處理器(Controller)。 -
HandlerAdapter根據處理器的類型選擇合適的方法來調用處理器。 -
處理器執(zhí)行相應的業(yè)務邏輯,生成ModelAndView。 -
HandlerAdapter將處理器的執(zhí)行結果包裝成ModelAndView。 -
視圖解析器根據ModelAndView找到對應的視圖進行渲染。 -
將渲染后的視圖返回給客戶端。
HandlerMapping和HandlerAdapter協同工作,通過將請求映射到處理器,并調用處理器來處理請求,實現了請求處理的流程。它們的靈活性使得在Spring MVC中可以支持多種處理器和處理方式,提高了框架的擴展性和適應性。
SpringAOP主要想解決什么問題
它的目的是對于面向對象思維的一種補充,而不是像引入命令式、函數式編程思維讓他順應另一種開發(fā)場景。在我個人的理解下AOP更像是一種對于不支持多繼承的彌補,除開對象的主要特征(我更喜歡叫“強共性”)被抽象為了一條繼承鏈路,對于一些“弱共性”,AOP可以統一對他們進行抽象和集中處理。
舉一個簡單的例子,打印日志。需要打印日志可能是許多對象的一個共性,這在企業(yè)級開發(fā)中十分常見,但是日志的打印并不反應這個對象的主要共性。而日志的打印又是一個具體的內容,它并不抽象,所以它的工作也不可以用接口來完成。而如果利用繼承,打印日志的工作又橫跨繼承樹下面的多個同級子節(jié)點,強行侵入到繼承樹內進行歸納會干擾這些強共性的區(qū)分。
這時候,我們就需要AOP了。AOP首先在一個Aspect(切面)里定義了一些Advice(增強),其中包含具體實現的代碼,同時整理了切入點,切入點的粒度是方法。最后,我們將這些Advice織入到對象的方法上,形成了最后執(zhí)行方法時面對的完整方法。
SpringAOP的原理了解嗎
Spring AOP的實現依賴于動態(tài)代理技術。動態(tài)代理是在運行時動態(tài)生成代理對象,而不是在編譯時。它允許開發(fā)者在運行時指定要代理的接口和行為,從而實現在不修改源碼的情況下增強方法的功能。Spring AOP支持兩種動態(tài)代理:
-
基于JDK的動態(tài)代理:使用java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口實現。這種方式需要代理的類實現一個或多個接口。 -
基于CGLIB的動態(tài)代理:當被代理的類沒有實現接口時,Spring會使用CGLIB庫生成一個被代理類的子類作為代理。CGLIB(Code Generation Library)是一個第三方代碼生成庫,通過繼承方式實現代理。
動態(tài)代理和靜態(tài)代理的區(qū)別
代理是一種常用的設計模式,目的是:為其他對象提供一個代理以控制對某個對象的訪問,將兩個類的關系解耦。代理類和委托類都要實現相同的接口,因為代理真正調用的是委托類的方法。區(qū)別:
-
靜態(tài)代理:由程序員創(chuàng)建或者是由特定工具創(chuàng)建,在代碼編譯時就確定了被代理的類是一個靜態(tài)代理。靜態(tài)代理通常只代理一個類; -
動態(tài)代理:在代碼運行期間,運用反射機制動態(tài)創(chuàng)建生成。動態(tài)代理代理的是一個接口下的多個實現類。
Java八股
代理模式和適配器模式有什么區(qū)別?
-
目的不同:代理模式主要關注控制對對象的訪問,而適配器模式則用于接口轉換,使不兼容的類能夠一起工作。 -
結構不同:代理模式一般包含抽象主題、真實主題和代理三個角色,適配器模式包含目標接口、適配器和被適配者三個角色。 -
應用場景不同:代理模式常用于添加額外功能或控制對對象的訪問,適配器模式常用于讓不兼容的接口協同工作。
java線程的生命周期有了解嗎?
源自《Java并發(fā)編程藝術》
線程狀態(tài)有New, RUNNABLE, BLOCK, WAITING, TIMED_WAITING, THERMINATED
-
NEW:新建狀態(tài),線程被創(chuàng)建且未啟動,此時還未調用 start 方法。 -
RUNNABLE: 運行狀態(tài)。其表示線程正在JVM中執(zhí)行,但是這個執(zhí)行,不一定真的在跑,也可能在排隊等CPU。 -
BLOCKED:阻塞狀態(tài)。線程等待獲取鎖,鎖還沒獲得。 -
WAITING: 等待狀態(tài)。線程內run方法運行完語句Object.wait()/Thread.join()進入該狀態(tài)。 -
TIMED_WAITING:限期等待。在一定時間之后跳出狀態(tài)。調用Thread.sleep(long) Object.wait(long) Thread.join(long)進入狀態(tài)。其中這些參數代表等待的時間。 -
TERMINATED:結束狀態(tài)。線程調用完run方法進入該狀態(tài)。
使用多線程要注意哪些問題?
要保證多線程的允許是安全,不要出現數據競爭造成的數據混亂的問題。
Java的線程安全在三個方面體現:
-
原子性:提供互斥訪問,同一時刻只能有一個線程對數據進行操作,在Java中使用了atomic和synchronized這兩個關鍵字來確保原子性; -
可見性:一個線程對主內存的修改可以及時地被其他線程看到,在Java中使用了synchronized和volatile這兩個關鍵字確??梢娦?; -
有序性:一個線程觀察其他線程中的指令執(zhí)行順序,由于指令重排序,該觀察結果一般雜亂無序,在Java中使用了happens-before原則來確保有序性。
保證數據的一致性有哪些方案呢?
-
事務管理:使用數據庫事務來確保一組數據庫操作要么全部成功提交,要么全部失敗回滾。通過ACID(原子性、一致性、隔離性、持久性)屬性,數據庫事務可以保證數據的一致性。 -
鎖機制:使用鎖來實現對共享資源的互斥訪問。在 Java 中,可以使用 synchronized 關鍵字、ReentrantLock 或其他鎖機制來控制并發(fā)訪問,從而避免并發(fā)操作導致數據不一致。 -
版本控制:通過樂觀鎖的方式,在更新數據時記錄數據的版本信息,從而避免同時對同一數據進行修改,進而保證數據的一致性。
線程池有了解嗎?線程池大概的原理?
線程池是為了減少頻繁的創(chuàng)建線程和銷毀線程帶來的性能損耗。
線程池分為核心線程池,線程池的最大容量,還有等待任務的隊列,提交一個任務,如果核心線程沒有滿,就創(chuàng)建一個線程,如果滿了,就是會加入等待隊列,如果等待隊列滿了,就會增加線程,如果達到最大線程數量,如果都達到最大線程數量,就會按照一些丟棄的策略進行處理。線程池的構造函數有7個參數:
-
corePoolSize:線程池核心線程數量。默認情況下,線程池中線程的數量如果 <= corePoolSize,那么即使這些線程處于空閑狀態(tài),那也不會被銷毀。 -
maximumPoolSize:線程池中最多可容納的線程數量。當一個新任務交給線程池,如果此時線程池中有空閑的線程,就會直接執(zhí)行,如果沒有空閑的線程且當前線程池的線程數量小于corePoolSize,就會創(chuàng)建新的線程來執(zhí)行任務,否則就會將該任務加入到阻塞隊列中,如果阻塞隊列滿了,就會創(chuàng)建一個新線程,從阻塞隊列頭部取出一個任務來執(zhí)行,并將新任務加入到阻塞隊列末尾。如果當前線程池中線程的數量等于maximumPoolSize,就不會創(chuàng)建新線程,就會去執(zhí)行拒絕策略。 -
keepAliveTime:當線程池中線程的數量大于corePoolSize,并且某個線程的空閑時間超過了keepAliveTime,那么這個線程就會被銷毀。 -
unit:就是keepAliveTime時間的單位。 -
workQueue:工作隊列。當沒有空閑的線程執(zhí)行新任務時,該任務就會被放入工作隊列中,等待執(zhí)行。 -
threadFactory:線程工廠??梢杂脕斫o線程取名字等等 -
handler:拒絕策略。當一個新任務交給線程池,如果此時線程池中有空閑的線程,就會直接執(zhí)行,如果沒有空閑的線程,就會將該任務加入到阻塞隊列中,如果阻塞隊列滿了,就會創(chuàng)建一個新線程,從阻塞隊列頭部取出一個任務來執(zhí)行,并將新任務加入到阻塞隊列末尾。如果當前線程池中線程的數量等于maximumPoolSize,就不會創(chuàng)建新線程,就會去執(zhí)行拒絕策略。
ArrayList和LinkedList有什么區(qū)別
-
底層數據結構:ArrayList使用數組作為底層數據結構,而LinkedList使用雙向鏈表作為底層數據結構 -
隨機訪問性能:ArrayList支持通過索引直接訪問元素,因為底層數組的連續(xù)存儲特性,所以時間復雜度為O(1)。而LinkedList需要從頭或尾部開始遍歷鏈表,時間復雜度為O(n)。 -
插入和刪除操作:ArrayList在尾部插入和刪除元素的時間復雜度為O(1),因為它只需要調整數組的長度即可。但在中間或頭部插入和刪除元素時,需要將后續(xù)元素進行移動,時間復雜度為O(n)。而LinkedList在任意位置插入和刪除元素的時間復雜度為O(1),因為只需要調整節(jié)點的指針即可。 -
內存占用:ArrayList在每個元素中都存儲了實際的數據,而LinkedList在每個節(jié)點中存儲了數據和前后節(jié)點的指針。因此,相同數量的元素情況下,LinkedList通常比ArrayList占用更多的內存空間。
ArrayList線程安全嗎?把ArrayList變成線程安全有哪些方法?
不是線程安全的,ArrayList變成線程安全的方式有:
-
使用Collections類的synchronizedList方法將ArrayList包裝成線程安全的List:
List<String> synchronizedList = Collections.synchronizedList(arrayList);
-
使用CopyOnWriteArrayList類代替ArrayList,它是一個線程安全的List實現:
CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>(arrayList);
-
使用Vector類代替ArrayList,Vector是線程安全的List實現:
Vector<String> vector = new Vector<>(arrayList);
對面向對象的理解?
以下是我對Java面向對象編程的理解,封裝、繼承、多態(tài)和抽象性是Java面向對象編程的四大特性。這些特性使得代碼更具可重用性、可維護性、可擴展性和靈活性。
-
封裝:封裝是將數據和行為組合在一個單元中的概念。Java使用類(Class)作為封裝的基本單元,通過類可以將數據和方法組合在一起,隱藏對象的內部狀態(tài),并只通過公共接口暴露對象的行為。 -
繼承:繼承是一種機制,允許一個類(子類)繼承另一個類(父類)的屬性和方法。子類可以重用父類的實現并定義自己的特定行為。Java中的繼承支持單繼承,但一個類可以實現多個接口(接口多繼承)。 -
多態(tài):多態(tài)性是允許在不同對象上使用相同的操作符或方法,可以根據具體對象的類型來執(zhí)行不同的操作。Java中實現多態(tài)性的方式包括方法重載(Overloading)和方法重寫(Overriding)。 -
接口與抽象類:接口和抽象類是Java中實現多態(tài)的重要機制。接口定義了行為的規(guī)范,類實現接口以應用這些行為。抽象類提供了一種具有未實現方法的類,必須由其子類實現這些方法。
其他
-
讀書中遇到最難的技術是什么,怎么克服的? -
有沒有什么強項在面試中還沒有展現的? -
反問
面試總結
-
感覺:面試官有引導,大多問的是八股,會的就回答的比較流暢,不熟悉的就磕磕巴巴,面試官給的反饋基礎還行,但是深度不夠,對剛剛設計模式的對比回答不滿意,和mybatis的原理回答也不太滿意 -
不足之處:對框架還是不夠熟練,回答不夠全面,經常被面試官問還有呢,但就回答不上來了,網絡這方面看了就忘。
推薦閱讀:
