1. 程式人生 > 其它 >面試常見題型(二)

面試常見題型(二)

簡單工廠和抽象工廠的區別

簡單工廠:把所有的產品都交由工廠的create()方法去建立

  • Factory:即工廠類, 簡單工廠模式的核心部分,負責實現建立所有產品的內部邏輯;工廠類可以被外界直接呼叫,建立所需物件

  • Product:抽象類產品, 它是工廠類所建立的所有物件的父類,封裝了各種產品物件的公有方法,它的引入將提高系統的靈活性,使得在工廠類中只需定義一個通用的工廠方法,因為所有建立的具體產品物件都是其子類物件

  • ConcreteProduct:具體產品, 它是簡單工廠模式的建立目標,所有被建立的物件都充當這個角色的某個具體類的例項。它要實現抽象產品中宣告的抽象方法

工廠模式:先用總的工廠去涵蓋所有型別的工廠,再通過對應型別去建立產品

  • Product:抽象產品,定義工廠方法所建立的物件的介面,也就是實際需要使用的物件的介面

  • ConcreteProduct:具體產品,具體的Product介面的實現物件

  • Factory:工廠介面,也可以叫 Creator(建立器),申明工廠方法,通常返回一個 Product 型別的例項物件

  • ConcreteFactory:工廠實現,或者叫 ConcreteCreator(建立器物件),覆蓋 Factory 定義的工廠方法,返回具體的 Product 例項

抽象工廠模式:與工廠方法類似,但在抽象工廠模式中,有一個產品族的概念:所謂的產品族,是指位於不同產品等級結構中功能相關聯的產品組成的家族。即工廠模式下,不同型別工廠下的產品型別也是不同的,但是抽象工廠模式下不同型別工廠下的產品型別可以相同

  • AbstractFactory:抽象工廠,用於宣告生成抽象產品的方法

  • ConcreteFactory:具體工廠,實現抽象工廠定義的方法,具體實現一系列產品物件的建立

  • AbstractProduct:抽象產品,定義一類產品物件的介面

  • ConcreteProduct:具體產品,通常在具體工廠裡,會選擇具體的產品實現,來建立符合抽象工廠定義的方法返回的產品型別的物件。

  • Client:客戶端,使用抽象工廠來獲取一系列所需要的產品物件

例項:

jdk,jre,jvm的區別

使用人群分類:JDK是給開發人員用的,JRE和JVM是普通使用者用的。

1、JDK

  JDK是Java開發工具包,是Sun Microsystems針對Java開發員的產品。

  JDK中包含JRE,在JDK的安裝目錄下有一個名為jre的目錄,裡面有兩個資料夾bin和lib,在這裡可以認為bin裡的就是jvm,lib中則是jvm工作所需要的類庫,而jvm和 lib和起來就稱為jre。

  JDK是整個JAVA的核心,包括了Java執行環境JRE(Java Runtime Envirnment)、一堆Java工具(javac/java/jdb等)和Java基礎的類庫(即Java API 包括rt.jar)。

  ①SE(J2SE),standard edition,標準版,是我們通常用的一個版本,從JDK 5.0開始,改名為Java SE。

  ②EE(J2EE),enterprise edition,企業版,使用這種JDK開發J2EE應用程式,從JDK 5.0開始,改名為Java EE。

  ③ME(J2ME),micro edition,主要用於移動裝置、嵌入式裝置上的java應用程式,從JDK 5.0開始,改名為Java ME。

2、JRE

  是執行基於Java語言編寫的程式所不可缺少的執行環境。也是通過它,Java的開發者才得以將自己開發的程式釋出到使用者手中,讓使用者使用。

  JRE中包含了Java virtual machine(JVM),runtime class libraries和Java application launcher,這些是執行Java程式的必要元件。

  與大家熟知的JDK不同,JRE是Java執行環境,並不是一個開發環境,所以沒有包含任何開發工具(如編譯器和偵錯程式),只是針對於使用Java程式的使用者。

3、JVM

  就是我們常說的java虛擬機器,它是整個java實現跨平臺的最核心的部分,所有的java程式會首先被編譯為.class的類檔案,這種類檔案可以在虛擬機器上執行。

  也就是說class並不直接與機器的作業系統相對應,而是經過虛擬機器(相當於中間層)間接與作業系統互動,由虛擬機器將程式解釋給本地系統執行。

  只有JVM還不能成class的執行,因為在解釋class的時候JVM需要呼叫解釋所需要的類庫lib,而jre包含lib類庫。

  JVM遮蔽了與具體作業系統平臺相關的資訊,使得Java程式只需生成在Java虛擬機器上執行的目的碼(位元組碼),就可以在多種平臺上不加修改地執行。

HTTP1.0和HTTP1.1的區別

1.1 長連線(Persistent Connection)
HTTP1.1支援長連線和請求的流水線處理,在一個TCP連線上可以傳送多個HTTP請求和響應,減少了建立和關閉連線的消耗和延遲,在HTTP1.1中預設開啟長連線keep-alive,一定程度上彌補了HTTP1.0每次請求都要建立連線的缺點。HTTP1.0需要使用keep-alive引數來告知伺服器端要建立一個長連線。

1.2 節約頻寬
HTTP1.0中存在一些浪費頻寬的現象,例如客戶端只是需要某個物件的一部分,而伺服器卻將整個物件送過來了,並且不支援斷點續傳功能。HTTP1.1支援只發送header資訊(不帶任何body資訊),如果伺服器認為客戶端有許可權請求伺服器,則返回100,客戶端接收到100才開始把請求body傳送到伺服器;如果返回401,客戶端就可以不用傳送請求body了節約了頻寬。

1.3 HOST域
在HTTP1.0中認為每臺伺服器都繫結一個唯一的IP地址,因此,請求訊息中的URL並沒有傳遞主機名(hostname),HTTP1.0沒有host域。隨著虛擬主機技術的發展,在一臺物理伺服器上可以存在多個虛擬主機(Multi-homed Web Servers),並且它們共享一個IP地址。HTTP1.1的請求訊息和響應訊息都支援host域,且請求訊息中如果沒有host域會報告一個錯誤(400 Bad Request)。

HTTP1.1和HTTP2.0的區別

  1. HTTP/2採用二進位制格式而非文字格式
  2. HTTP/2是完全多路複用的,而非有序並阻塞的——只需一個連線即可實現並行
  3. 使用報頭壓縮,HTTP/2降低了開銷
  4. HTTP/2讓伺服器可以將響應主動“推送”到客戶端快取中

有哪些穩定和不穩定排序

  • 穩定排序:氣泡排序,插入排序
  • 不穩定排序:選擇排序 希爾排序 堆排序 快速排序

epoll相對select優點

fd:檔案描述符

1.select的控制代碼數目受限,在linux/posix_types.h標頭檔案有這樣的宣告:#define __FD_SETSIZE 1024 表示select最多同時監聽1024個fd。而epoll沒有,它的限制是最大的開啟檔案控制代碼數目。

2.epoll的最大好處是不會隨著FD的數目增長而降低效率,在selec中採用輪詢處理,其中的資料結構類似一個數組的資料結構,而epoll是維護一個佇列,直接看佇列是不是空就可以了。epoll只會對"活躍"的socket進行操作---這是因為在核心實現中epoll是根據每個fd上面的callback函式實現的。那麼,只有"活躍"的socket才會主動的去呼叫 callback函式(把這個控制代碼加入佇列),其他idle狀態控制代碼則不會,在這點上,epoll實現了一個"偽"AIO。但是如果絕大部分的I/O都是“活躍的”,每個I/O埠使用率很高的話,epoll效率不一定比select高(可能是要維護佇列複雜)。

3.使用mmap加速核心與使用者空間的訊息傳遞。無論是select,poll還是epoll都需要核心把FD訊息通知給使用者空間,如何避免不必要的記憶體拷貝就很重要,在這點上,epoll是通過核心於使用者空間mmap同一塊記憶體實現的。

堆排序

性質:將需排序的資料看成一個完全二叉樹,所以對於每個節點(i)來說:

  • 父節點:parent=(i-2)/2;
  • 左子節點:c1=2i+1;
  • 右子節點:c2=2i+2;

初始化堆

初始化堆,從最後一個非葉子節點,進行heapify操作(將父節節點與子進行比較,維護父節點為最大,如何遞迴維護交換的節點)

最後一個非葉子節點=最後一個葉子節點的父節點,根據以上性質,可以得到最後一個非葉子節點=(n-1-2)/2

初始化堆後,就可進行堆排序

將堆的頭節點跟最後一個節點交換,然後截斷,隨後在進行heapify操作,然後重複該操作即可完成堆排序。

該陣列從邏輯上講就是一個堆結構,我們用簡單的公式來描述一下堆的定義就是:

大頂堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]

小頂堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

MyBatis中xml檔案的標籤

configuration、environments、transactionManager(JDBC)、dataSource、mappers

MyBatis與Spring Data JPA的區別

JPA預設使用hibernate作為ORM實現,所以,一般使用Spring Data JPA即會使用hibernate。我們再看看hibernate的官方概念,Hibernate是一個開放原始碼的物件關係對映框架,它對JDBC進行了非常輕量級的物件封裝,它將POJO與資料庫表建立對映關係,是一個全自動的orm框架,hibernate可以自動生成SQL語句,自動執行,使得Java程式設計師可以隨心所欲的使用物件程式設計思維來操縱資料庫。

MyBatis 是一款優秀的持久層框架,它支援定製化 SQL、儲存過程以及高階對映。MyBatis 避免了幾乎所有的 JDBC 程式碼和手動設定引數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和對映原生資訊,將介面和 Java 的 POJOs(Plain Old Java Objects,普通的 Java物件)對映成資料庫中的記錄。

這樣看,Spring Data JPA與MyBatis對比,起始也就是hibernate與MyBatis對比。所以,我們直接來比較後兩者。

從基本概念和框架目標上看,兩個框架差別還是很大的。hibernate是一個自動化更強、更高階的框架,畢竟在java程式碼層面上,省去了絕大部分sql編寫,取而代之的是用面向物件的方式操作關係型資料庫的資料。而MyBatis則是一個能夠靈活編寫sql語句,並將sql的入參和查詢結果對映成POJOs的一個持久層框架。所以,從表面上看,hibernate能方便、自動化更強,而MyBatis 在Sql語句編寫方面則更靈活自由。

MySQL插入一條語句如何寫?插入1000條?

insert into tbl_name values (...),(...),(...);

MyBatis 使用foreach標籤

ES的分片

分片(shard): 因為 ES 是個分散式的搜尋引擎, 所以索引通常都會分解成不同部分, 而這些分佈在不同節點的資料就是分片. ES自動管理和組織分片, 並在必要的時候對分片資料進行再平衡分配, 所以使用者基本上不用擔心分片的處理細節.

分片數過多會導致:

1、  會導致開啟比較多的檔案
2、  分片是儲存在不同機器上的,分片數越多,機器之間的互動也就越多;

分片數太少導致:

單個分片索引過大,降低整體的檢索速率

Kafka

https://blog.csdn.net/lzb348110175/article/details/100764105

JavaGC新老年代的劃分

Young:1/3

Old:2/3

SQL優化

1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0

3.應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

4.應儘量避免在 where 子句中使用 or 來連線條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20

5.in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3

6.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'

7.應儘量避免在 where 子句中對欄位進行表示式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2

8.應儘量避免在where子句中對欄位進行函式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
應改為:
select id from t where name like 'abc%'

9.不要在 where 子句中的“=”左邊進行函式、算術運算或其他表示式運算,否則系統將可能無法正確使用索引。

10.在使用索引欄位作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應儘可能的讓欄位順序與索引順序相一致。

11.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類程式碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)

12.很多時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)

13.並不是所有索引對查詢都有效,SQL是根據表中資料來進行查詢優化的,當索引列有大量資料重複時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

14.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,
因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

15.儘量使用數字型欄位,若只含數值資訊的欄位儘量不要設計為字元型,這會降低查詢和連線的效能,並會增加儲存開銷。
這是因為引擎在處理查詢和連線時會逐個比較字串中每一個字元,而對於數字型而言只需要比較一次就夠了。

16.儘可能的使用 varchar 代替 char ,因為首先變長欄位儲存空間小,可以節省儲存空間,
其次對於查詢來說,在一個相對較小的欄位內搜尋效率顯然要高些。

17.任何地方都不要使用 select * from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。

18.避免頻繁建立和刪除臨時表,以減少系統表資源的消耗。

19.臨時表並不是不可使用,適當地使用它們可以使某些例程更有效,例如,當需要重複引用大型表或常用表中的某個資料集時。但是,對於一次性事件,最好使用匯出表。

20.在新建臨時表時,如果一次性插入資料量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,
以提高速度;如果資料量不大,為了緩和系統表的資源,應先create table,然後insert。

21.如果使用到了臨時表,在儲存過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。

22.儘量避免使用遊標,因為遊標的效率較差,如果遊標操作的資料超過1萬行,那麼就應該考慮改寫。

23.使用基於遊標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

24.與臨時表一樣,遊標並不是不可使用。對小型資料集使用 FAST_FORWARD 遊標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的資料時。
在結果集中包括“合計”的例程通常要比使用遊標執行的速度快。如果開發時間允許,基於遊標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

25.儘量避免大事務操作,提高系統併發能力。

26.儘量避免向客戶端返回大資料量,若資料量過大,應該考慮相應需求是否合理。

synchronized和 ReentrantLock的原理

Java 物件頭

一個物件在記憶體中包含三部分:物件頭,例項資料和對齊填充。其中 Java 物件頭包含兩部分:

Class Metadata Address (型別指標)。儲存類的元資料的指標。虛擬機器通過這個指標找到它是哪個類的例項。

Mark Word(標記欄位)。存出一些物件自身執行時的資料。包括雜湊碼,GC 分代年齡,鎖狀態標誌等。

Monitor

Mark Word 有一個欄位指向 monitor 物件。monitor 中記錄了鎖的持有執行緒,等待的執行緒佇列等資訊。前面說的每個物件都有一個鎖和一個等待佇列,就是在這裡實現的。

monitor 物件由 C++ 實現。其中有三個關鍵欄位:

_owner 記錄當前持有鎖的執行緒
_EntryList 是一個佇列,記錄所有阻塞等待鎖的執行緒
_WaitSet 也是一個佇列,記錄呼叫 wait() 方法並還未被通知的執行緒。

mvcc

每行資料有兩個欄位:一個是createTime,一個是deleteTime

  • 有個事務,新增一條記錄時,createTime=當前事務號
  • 有個事務刪除一條記錄時,deleteTime=當前事務號
  • 有個事務update時,會插入一條update的記錄,createTime=當前事務號,舊記錄的 deleteTime=當前事務號
  • 有個事務select時,會檢視當前事務號大於createTime和小於deleteTime的記錄

innodb中幻讀與mvcc和間隙鎖分析

(事務隔離級別rr)面試官大大認為innodb就是靠mvcc解決的幻讀,而我固執的認為絕對是間隙鎖解決了這個問題。

面畢,查了一些資料,並且自己時間之後的分析和結論如下。

首先讀分為:
快照讀
select * from table where ?;

當前讀:特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;

對於快照讀來說,幻讀的解決是依賴mvcc解決。而對於當前讀則依賴於gap-lock解決。

如何檢視端口占用

netstat -tunlp用於顯示tcp,udp的埠和程序等相關情況

命令裡的t,u,n,l,p均有不同含義:

-t 僅顯示和tcp相關的

-u 僅顯示和udp相關的

-n 不限時別名,能顯示數字的全部轉換為數字

-l 僅顯示出於Listen(監聽)狀態的

-p 顯示建立這些連線的程式名

SQL中INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN區別

1.inner join,在兩張表進行連線查詢時,只保留兩張表中完全匹配的結果集。

2.left join,在兩張表進行連線查詢時,會返回左表所有的行,即使在右表中沒有匹配的記錄。

3.right join,在兩張表進行連線查詢時,會返回右表所有的行,即使在左表中沒有匹配的記錄。

4.full join,在兩張表進行連線查詢時,返回左表和右表中所有沒有匹配的行。

TCP的拆包和粘包

https://www.cnblogs.com/panchanggui/p/9518735.html

AQS的詳解

https://www.jianshu.com/p/da9d051dcc3d

AQS是AbstractQueuedSynchronizer的簡稱。AQS提供了一種實現阻塞鎖和一系列依賴FIFO等待佇列的同步器的框架,如下圖所示。AQS為一系列同步器依賴於一個單獨的原子變數(state)的同步器提供了一個非常有用的基礎。子類們必須定義改變state變數的protected方法,這些方法定義了state是如何被獲取或釋放的。鑑於此,本類中的其他方法執行所有的排隊和阻塞機制。子類也可以維護其他的state變數,但是為了保證同步,必須原子地操作這些變數。

AbstractQueuedSynchronizer中對state的操作是原子的,且不能被繼承。所有的同步機制的實現均依賴於對改變數的原子操作。為了實現不同的同步機制,我們需要建立一個非共有的(non-public internal)擴充套件了AQS類的內部輔助類來實現相應的同步邏輯。AbstractQueuedSynchronizer並不實現任何同步介面,它提供了一些可以被具體實現類直接呼叫的一些原子操作方法來重寫相應的同步邏輯。AQS同時提供了互斥模式(exclusive)和共享模式(shared)兩種不同的同步邏輯。一般情況下,子類只需要根據需求實現其中一種模式,當然也有同時實現兩種模式的同步類,如ReadWriteLock。接下來將詳細介紹AbstractQueuedSynchronizer的提供的一些具體實現方法。

state狀態

AbstractQueuedSynchronizer維護了一個volatile int型別的變數,使用者表示當前同步狀態。volatile雖然不能保證操作的原子性,但是保證了當前變數state的可見性。state的訪問方式有三種:

  • getState()
  • setState()
  • compareAndSetState()

最後,總結一下acquire()的流程:

  1. 呼叫自定義同步器的tryAcquire()嘗試直接去獲取資源,如果成功則直接返回;沒成功,則addWaiter()將該執行緒加入等待佇列的尾部,並標記為獨佔模式;

  2. acquireQueued()使執行緒在等待佇列中休息,有機會時(輪到自己,會被unpark())會去嘗試獲取資源。獲取到資源後才返回。如果在整個等待過程中被中斷過,則返回true,否則返回false。

  3. 如果執行緒在等待過程中被中斷過,它是不響應的。只是獲取資源後才再進行自我中斷selfInterrupt(),將中斷補上。

top k

https://blog.csdn.net/wufaliang003/article/details/82940218