日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

面试题—开发篇

發布時間:2024/4/15 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试题—开发篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一、Java 基礎

二、容器

三、多線程

四、反射

五、對象拷貝

六、Java Web

七、異常

八、網絡

九、設計模式

十、Spring/Spring MVC

十一、Spring Boot/Spring Cloud

十二、Hibernate

十三、Mybatis

十四、RabbitMQ

十五、Kafka

十六、Zookeeper

十七、MySql

十八、Redis

十九、JVM


一、Java 基礎

1.JDK 和 JRE 有什么區別?

  • JRE:Java Runtime Environment,是Java運行環境,如果你不需要開發只需要運行Java程序,那么你可以安裝JRE。例如程序員開發出的程序最終賣給了用戶,用戶不用開發,只需要運行程序,所以用戶在電腦上安裝JRE即可。
  • JDK:Java Development Kit,它是Java開發運行環境,在程序員的電腦上當然要安裝JDK;JDK包含了JRE。

2.== 和 equals 的區別是什么?

  • ==:比較的對象引用,也就是內存地址是否相等
  • equals:比較的是值

2.Java重寫equals()

  • 保證具有對稱性、傳遞性、一致性(自反性和非空性自動滿足)
public class ColorPoint{private Point point;private Color color;public ColorPoint(int x, int y, Color color){point = new Point(x, y);this.color = color;}//返回一個與該有色點在同一位置上的普通Point對象public Point asPoint(){return point;}public boolean equals(Object o){if(o == this)return true;if(!(o instanceof ColorPoint))return false;ColorPoint cp = (ColorPoint)o;return cp.point.equals(point)&&cp.color.equals(color);} }

3.hashCode()方法的作用是什么?

  • Java Set中的元素是不可重復的,可兩個元素是否重復應該依據什么來判斷呢?這就是Object.equals方法了。但是,如果每增加一個元素就檢查一次,那么當元素很多時,后添加到集合中的元素比較的次數就非常多了。如果集合中現在已經有1000個元素,那么第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大降低效率。???于是,Java采用了哈希表的原理。哈希算法將數據依特定算法直接指定到一個地址上。如果詳細講解哈希算法,那需要更多的文章篇幅,我在這里就不介紹了。初學者可以這樣理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能并不是)。??這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了,就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。所以這里存在一個沖突解決的問題。這樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。??

3.兩個對象的 hashCode()相同,則 equals()也一定為 tr? ? ? ue,對嗎?

  • 不對,存在hash沖突

4.final 在 java 中有什么作用?

  • 終態,修飾類不能被繼承、修飾函數不能被重寫、修飾變量則變量只能讀不能寫;

5.java 中的 Math.round(-1.5) 等于多少?

  • Math.round()是四舍五入函數,返回值為int型

6.String 屬于基礎的數據類型嗎?

  • 不是,是封裝類型

7.java 中操作字符串都有哪些類?它們之間有什么區別?

  • String:不可變對象,不能修改
  • StringBuffer:長度可變,線程安全
  • StringBulider:長度可變,線程不安全

8.String str1="i"、String str2="i"與 String str3=new String(“i”)一樣嗎?

  • str1與str2一樣,str1與str3不一樣。
  • String str="i"; 因為String 是final類型的,所以“i”應該是在常量池。
  • new String("i");則是新建對象放到堆內存中。

9.如何將字符串反轉?

  • StringBuilder(str).reverse().toString();

10.String 類的常用方法都有那些?

  • length()、toCharArray()、split(String)、contains(String)、startsWith(String)、endsWith(String)、toUpperCase()、replace(String,String)、substring(int,int)、trim()、charAt(int)、indexOf(String)

11.抽象類必須要有抽象方法嗎?

  • 抽象類不一定有抽象方法;但是包含一個抽象方法的類一定是抽象類。(有抽象方法就是抽象類)
  • 在abstract class 中可以有自己的數據成員,也可以有非abstarct的成員方法,而在interface中,只能夠有靜態的不能被修改的數據成員(也就是必須是static final的,不過在 interface中一般不定義數據成員),所有的成員方法都是abstract的。

12.普通類和抽象類有哪些區別?

  • 抽象類不能被實例化

13.抽象類能使用 final 修飾嗎?

  • 抽象方法不能用final修飾,因為子類需要重寫抽象方法,如果被final修飾則無法重寫

14.接口和抽象類有什么區別?

相同點:

  • 都不能實例化對象
  • 都可以包含抽象方法,而且抽象方法必須被繼承的類全部實現。

不同點:

  • 抽象類和接口都不能直接實例化,如果要實例化,抽象類變量必須指向實現所有抽象方法的子類對象,接口變量必須指向實現所有接口方法的類對象。
  • 接口只能做方法申明,抽象類中可以做方法申明,也可以做方法實現
  • 接口里定義的變量只能是公共的靜態的常量,抽象類中的變量是普通變量
  • 抽象方法只能申明,不能實現,接口是設計的結果 ,抽象類是重構的結果
  • 抽象類里可以沒有抽象方法
  • 抽象方法要被實現,所以不能是靜態的,也不能是私有的。
  • 接口可繼承接口,并可多繼承接口,但類只能單根繼承。

15.java 中 IO 流分為幾種?

  • BIO:同步阻塞I/O模式
  • NIO:同步非阻塞的I/O模型
  • AIO:異步非阻塞的IO模型。異步 IO 是基于事件和回調機制實現的,也就是應用操作之后會直接返回,不會堵塞在那里,當后臺處理完成,操作系統會通知相應的線程進行后續的操作。

二、容器

18.java 容器都有哪些?

  • ArrayList、LinkedList、Set、TreeSet、HashMap、TreeMap、Deque、PriorityQueue

19.Collection 和 Collections 有什么區別?

  • java.util.Collection 是一個集合接口;
  • java.util.Collections 是一個包裝類。它包含有各種有關集合操作的靜態方法(對集合的搜索、排序、線程安全化等),此類不能實例化,就像一個工具類,服務于Java的Collection框架。

20.List、Set、Map 之間的區別是什么?

  • List:有序集合
  • Set:不重復集合,LinkedHashSet按照插入排序,SortedSet可排序,HashSet無序
  • Map:鍵值對集合

21.HashMap 和 Hashtable 有什么區別?

  • Hashtable:底層數組+鏈表實現,無論key還是value都不能為null,線程安全
  • HashMap :底層數組+鏈表或數組加紅黑樹實現,可以存儲null鍵和null值,線程不安全

22.如何決定使用 HashMap 還是 TreeMap?

  • 不需要排序使用HashMap,需要排序使用TreeMap

23.說一下 HashMap 的實現原理?

  • 用于存儲Key-value集合的數據結構;底層用數組加鏈表或數組加紅黑樹實現,當鏈表長度超過8時轉為紅黑樹;初識容量是16,擴容是2倍容量擴容;當數組大小使用率75%時觸發擴容

24.說一下 HashSet 的實現原理?

  • HashSet是一個HashMap實例,都是一個存放鏈表的數組。HashSet中不允許有重復元素,這是因為HashSet是基于HashMap實現的,HashSet中的元素都存放在HashMap的key上面,而value中的值都是統一的一個固定對象private static final Object PRESENT = new Object();
  • HashSet中add方法調用的是底層HashMap中的put()方法,而如果是在HashMap中調用put,首先會判斷key是否存在,如果key存在則修改value值,如果key不存在這插入這個key-value。而在set中,因為value值沒有用,也就不存在修改value值的說法,因此往HashSet中添加元素,首先判斷元素(也就是key)是否存在,如果不存在這插入,如果存在著不插入,這樣HashSet中就不存在重復值。
  • 所以判斷key是否存在就要重寫元素的類的equals()和hashCode()方法,當向Set中添加對象時,首先調用此對象所在類的hashCode()方法,計算次對象的哈希值,此哈希值決定了此對象在Set中存放的位置;若此位置沒有被存儲對象則直接存儲,若已有對象則通過對象所在類的equals()比較兩個對象是否相同,相同則不能被添加。

25.ArrayList 和 LinkedList 的區別是什么?

  • ArrayList:底層是數組,查找快,增加刪除慢
  • LinkedList:底層是鏈表,查找慢,增加刪除快

26.如何實現數組和 List 之間的轉換?

  • 數組轉 List ,使用 JDK 中 java.util.Arrays 工具類的 asList 方法
  • List 轉數組,使用 List 的toArray方法

27.ArrayList 和 Vector 的區別是什么?

  • Vector:線程安全的動態數組,雖然是線程安全的,但性能較差,一般情況下使用ArrayList,除非特殊需求;
  • ArrayList:線程不安全

28.Array 和 ArrayList 有何區別?

  • Array:可以包含基本類型和對象類型,大小是固定的
  • ArrayList:只能包含對象類型,大小是動態變化的。
  • ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。

29.在 Queue 中 poll()和 remove()有什么區別?

  • 異常處理方式不一樣,offer()/peek()/poll()異常時返回null或false;add()/element()/remove()拋出異常30.哪些集合類是線程安全的?

31.迭代器 Iterator 是什么?

  • 用于順序訪問集合對象的元素,無需知道集合對象的底層實現。

32.Iterator 怎么使用?有什么特點?

  • 使用方法iterator()要求容器返回一個Iterator。Iterator將準備好返回序列的第一個元素。
  • 使用next()獲得序列中的下一個元素
  • 使用hasNext()檢查序列中是否還有元素。
  • 使用remove()將迭代器新近返回的元素刪除。

32.List如何一邊遍歷,一邊刪除?

  • 使用迭代器的remove()方法
  • 使用for正循環遍歷,每次刪除時修改下標i=i-1
public static void main(String[] args) {List<String> platformList = new ArrayList<>();platformList.add("博客園");platformList.add("CSDN");platformList.add("掘金");Iterator<String> iterator = platformList.iterator();while (iterator.hasNext()) {String platform = iterator.next();if (platform.equals("博客園")) {iterator.remove();}}System.out.println(platformList); }

33.Iterator 和 ListIterator 有什么區別?

  • ListIterator 繼承 Iterator
  • ListIterator 比 Iterator多方法
  • 使用范圍不同,Iterator可以迭代所有集合;ListIterator 只能用于List及其子類

34.怎么確保一個集合不能被修改?

  • 首先我們要清楚,集合(map,set,list…)都是引用類型,所以我們如果用final修飾的話,集合里面的內容還是可以修改的。可以采用Collections包下的unmodifiableMap方法,通過這個方法返回的map,是不可以修改的

35.unmodifiableMap不能修改的原理:

  • 當調用其讀相關方法(size、isEmpty、get)時,間接調用的是成員屬性m的對應方法。
  • 當調用其修改相關方法(put、remove、clear)時,直接拋出UnsupportedOperationException異常,不讓修改。

三、多線程

35.并行和并發有什么區別?

  • 并行:進程并行執行,多核cpu并行執行多個進程
  • 并發:一個進程的多個線程并發,并發只是看起來像同時執行,其實是輪流使用cpu的

36.線程和進程的區別?

1)功能不同

  • 進程就是運行中的程序,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。
  • 線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。

2)工作原理不同

  • 進程是線程的容器。程序是指令、數據及其組織形式的描述,進程是程序的實體。
  • 線程是獨立調度和分派的基本單位。線程可以為操作系統內核調度的內核線程,如Win32線程;由用戶進程自行調度的用戶線程,如Linux平臺的POSIX Thread;或者由內核與用戶進程,如Windows 7的線程,進行混合調度。

3)作用不同

  • 進程是操作系統中最基本、重要的概念。是多道程序系統出現后,為了刻畫系統內部出現的動態情況,描述系統內部各道程序的活動規律引進的一個概念,所有多道程序設計操作系統都建立在進程的基礎上。
  • 通常在一個進程中可以包含若干個線程,它們可以利用進程所擁有的資源。在引入線程的操作系統中,通常都是把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調度的基本單位。

36.python協程是什么?與線程有什么區別?

  • 進程上的一把鎖,python程序運行時,只有一個線程可以獲取這把鎖,這也是python為什么是偽并發的原因

37.守護線程是什么?

  • java里線程分2種,守護線程、用戶線程。守護線程是專門用于服務其他的線程,比如垃圾回收線程,就是最典型的守護線程。
  • 如果其他的線程(即用戶自定義線程)都執行完畢,連main線程也執行完畢,那么jvm就會退出(即停止運行)——此時,連jvm都停止運行了,守護線程當然也就停止執行了。
  • 當線程只剩下守護線程的時候,JVM就會退出;補充一點如果還有其他的任意一個用戶線程還在,JVM就不會退出。

37.使用守護線程需要注意什么?

  • thread.setDaemon(true)必須在thread.start()之前設置,否則會跑出一個IllegalThreadStateException異常。你不能把正在運行的常規線程設置為守護線程。
  • 在Daemon線程中產生的新線程也是Daemon的。
  • 守護線程不能用于去訪問固有資源,比如讀寫操作或者計算邏輯。因為它會在任何時候甚至在一個操作的中間發生中斷。
  • Java自帶的多線程框架,比如ExecutorService,會將守護線程轉換為用戶線程,所以如果要使用后臺線程就不能用Java的線程池。

38.創建線程有哪幾種方式?

  • 兩種,繼承Thread類或者實現Runnable接口,因為Java不允許多繼承,但允許實現多個接口,所以推薦使用實現Runnable接口的方式

39.說一下 runnable 和 callable 有什么區別?

  • 兩者最大的不同點是:實現Callable接口的任務線程能返回執行結果;而實現Runnable接口的任務線程不能返回結果;
  • Callable接口的call()方法允許拋出異常;而Runnable接口的run()方法的異常只能在內部消化,不能繼續上拋;

39.callable創建線程的demo

public class CallableImpl implements Callable<String> {private String acceptStr;public CallableImpl(String acceptStr) {this.acceptStr = acceptStr;}@Overridepublic String call() throws Exception {// 任務阻塞 1 秒Thread.sleep(1000);return this.acceptStr + " append some chars and return it!";}public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<String> callable = new CallableImpl("my callable test!");FutureTask<String> task = new FutureTask<>(callable);long beginTime = System.currentTimeMillis();// 創建線程new Thread(task).start();// 調用get()阻塞主線程,反之,main線程不會阻塞String result = task.get();long endTime = System.currentTimeMillis();System.out.println("hello : " + result);System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!");} }

40.線程有哪些狀態?

  • 創建(new)、就緒(runnable)、運行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)

41.sleep() 和 wait() 有什么區別?

  • wait、notify/notifyAll是Object的本地final方法,wait使當前線程阻塞,前提是必須先獲得鎖,所以只能在synchronized鎖范圍內里使用wait、notify/notifyAll方法,
  • sleep方法是Thead類的靜態方法,sleep可以在任何地方使用,
  • sleep() 和 wait() 都會釋放cpu資源,但sleep()不會釋放鎖,wait()會釋放鎖

42.notify()和 notifyAll()有什么區別?

  • notify():喚醒等待線程
  • notifyAll():喚醒所有等待線程,但最終也只有一個線程能夠獲得鎖

42.選擇使用notify還是notifyAll()?

  • notify方法和notifyAll()方法兩者非常相似,到底該用哪一個,老實說,這個選擇有點困難。選擇notify的話,因為要喚醒的線程比較少(only one),程序的處理速度當然比notifyAll略勝一籌。但是選擇notify時,若這部分處理不好,可能會出現程序掛掉的危險。一般說來,選擇notifyAll所寫出來的程序代碼會比notify可靠。除非你能確定程序員對程序代碼的意義和能力限度一清二楚,否則選擇notifyAll應該是比較穩扎穩打。

43.線程的 run()和 start()有什么區別?

  • ?start() 方法是用來啟動線程的,輪到該線程執行時,會自動調用 run();
  • 直接調用 run() 方法,無法達到啟動多線程的目的,相當于主線程線性執行 Thread 對象的 run() 方法。
  • 一個線程對線的 start() 方法只能調用一次,多次調用會拋出 java.lang.IllegalThreadStateException 異常;run() 方法沒有限制。

44.創建線程池有哪幾種方式?

  • 通過Executors工廠方法創建
  • 通過new?ThreadPoolExecutor(int?corePoolSize, int?maximumPoolSize, long?keepAliveTime,?TimeUnit?unit,?BlockingQueue<Runnable>?workQueue)自定義創建
  • 推薦:使用ThreadPoolExecutor方式創建線程池(阿里不允許使用Executors,使用ThreadPoolExecutor可以避免資源耗盡的風險)
//創建使用單個線程的線程池 ExecutorService es1 = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) {es1.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "正在執行任務");}}); } //創建使用固定線程數的線程池 ExecutorService es2 = Executors.newFixedThreadPool(3); //創建一個會根據需要創建新線程的線程池 ExecutorService es3 = Executors.newCachedThreadPool(); //創建擁有固定線程數量的定時線程任務的線程池 ScheduledExecutorService es4 = Executors.newScheduledThreadPool(2); //創建只有一個線程的定時線程任務的線程池 ScheduledExecutorService es5 = Executors.newSingleThreadScheduledExecutor();ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 20, 2, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5)); for (int i = 0; i < size; i++) {poolExecutor.execute(new DemoTask(i));Console.log("poolSize:" + poolExecutor.getPoolSize()); }

46.線程池中 submit()和 execute()方法有什么區別?

  • 參數不同:execute() 參數 Runnable ;submit() 參數 (Runnable) 或 (Runnable 和 結果 T) 或 (Callable)
  • 返回值不同:execute() 沒有返回值;而 submit() 有返回值,submit() 的返回值 Future 調用get方法時,可以捕獲處理異常
  • 總結:推薦使用submit()

45.線程池都有哪些狀態?

  • RUNNING
  • SHUTDOWN:不接受新的任務提交,但是會繼續處理等待隊列中的任務。調用shutdown()方法時變為這個狀態
  • STOP:不接受新的任務提交,不再處理等待隊列中的任務,中斷正在執行任務的線程。調用shutdownNow()方法時變為這個狀態
  • TIDYING:所有的任務都銷毀了,workCount 為 0,線程池的狀態在轉換為 TIDYING 狀態時,會執行鉤子方法 terminated()。因為terminated()在ThreadPoolExecutor類中是空的,所以用戶想在線程池變為TIDYING時進行相應的處理;可以通過重載terminated()函數來實現。?
  • TERMINATED

47.在 java 程序中怎么保證多線程的運行安全?

  • JDK Atomic開頭的原子類、synchronized、LOCK,可以解決原子性問題
  • synchronized、volatile、LOCK,可以解決可見性問題
  • Happens-Before 規則可以解決有序性問題

48.多線程鎖的升級原理是什么?

  • 資源競爭加劇是會進行鎖升級,升級方向是無鎖-偏向鎖-輕量級鎖-重量級鎖

49.什么是死鎖?

  • 兩個線程互相等待對方的資源

50.怎么防止死鎖?

  • 破壞產生的死鎖的4個條件
  • 超時退出,釋放資深資源
  • 降低鎖的使用粒度,盡量不要幾個功能用同一把鎖
  • 盡量減少同步的代碼塊。

51.ThreadLocal 是什么?有哪些使用場景?

52.說一下 synchronized 底層實現原理?

  • 通過調用底層的monitor鎖互斥訪問共享資源。一個進程只有一把monitor鎖,所以當一個線程獲得進入synchronized代碼塊時,其他線程進不去其他被synchronized修飾的代碼塊

53.synchronized 和 volatile 的區別是什么?

  • synchronized:加鎖,底層通過monitor鎖互斥訪問共享資源
  • volatile:無鎖,通過CAS操作互斥訪問共享

54.synchronized 和 Lock(ReentrantLock )有什么區別?

  • 最關鍵的區別是synchronized同一時間只允許一個線程訪問互斥代碼塊(即使這些互斥代碼塊不是同一個代碼塊);Lock允許多個線程同時訪問不同加了Lock的代碼塊

56.說一下 atomic 的原理?

  • cas機制:每次修改變量值的時候,都會比較工作內存中的舊值與主存的舊值是否相等,相等說明沒有其他線程修改過,可以修改;弊端是cas自璇操作耗費cpu資源,和ABA問題

四、反射

57.什么是反射?

  • 定義:運行時獲取類的信息以及運行時根據類名創建實例等。
  • 應用場景:Spring AOP
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; public class Test01 {public static void main(String[] args) throws ClassNotFoundException {String a = "java.lang.String";// 根據一類的全名字符串來獲得一個類的類對象Class<?> clazz = Class.forName(a);// 獲得傳遞過來的類的所有方法Method[] methods = clazz.getDeclaredMethods();for (Method m: methods) {System.out.println(m);}// 獲得類的所有屬性Field[] declaredFields = clazz.getDeclaredFields();for(Field d : declaredFields) {System.out.println(d);}// 獲得類的所有構造器Constructor<?>[] constructors = clazz.getDeclaredConstructors();for (Constructor c : constructors) {System.out.println(c);}} }

58.什么是 java 序列化?什么情況下需要序列化?

  • 序列化是將 Java 對象轉換成字節流的過程。反序列化是將字節流轉換成 Java 對象的過程。
  • 當?Java 對象需要在網絡上傳輸 或者 持久化存儲到文件中時,就需要對 Java 對象進行序列化處理。深拷貝也可以借助序列化實現
  • 序列化的實現:類實現 Serializable 接口,這個接口沒有需要實現的方法。實現 Serializable 接口是為了告訴 jvm 這個類的對象可以被序列化。
@SuppressWarnings("resource")public static void main(String[] args) throws IOException,ClassNotFoundException {//序列化ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("TestSerializable.obj"));oos.writeObject("測試序列化");oos.writeObject(618);TestSerializable test = new TestSerializable(1, "ConstXiong");oos.writeObject(test);//反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("TestSerializable.obj"));System.out.println((String)ois.readObject());System.out.println((Integer)ois.readObject());System.out.println((TestSerializable)ois.readObject());}

59.動態代理是什么?有哪些應用?

  • 當想要給實現了某個接口的類中的方法,加一些額外的處理,比如說加日志,加事務等。可以給這個類創建一個代理,故名思議就是創建一個新的類,這個類不僅包含原來類方法的功能,而且還在原來的基礎上添加了額外處理的新類。這個代理類并不是定義好的,是動態生成的。具有解耦意義,靈活,擴展性強。
  • 動態代理的應用:Spring的AOP,加事務,加權限,加日志。

60.怎么實現動態代理?

  • jdk動態代理:jdk動態代理是由Java內部的反射機制來實現的,目標類基于統一的接口InvocationHandler
  • cglib動態代理,cglib動態代理底層則是借助asm來實現的,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。
package com.example.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyInvocationHandler implements InvocationHandler {private Object target;/*** 綁定委托對象并返回一個代理類** @param target* @return*/public Object bind(Object target) {this.target = target;//取得代理對象return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this); //要綁定接口(這是一個缺陷,cglib彌補了這一缺陷)}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if ("getName".equals(method.getName())) {System.out.println("------before " + method.getName() + "------");Object result = method.invoke(target, args);System.out.println("------after " + method.getName() + "------");return result;} else {Object result = method.invoke(target, args);return result;}} }package com.example.jdk; import com.example.service.UserService; import com.example.service.impl.UserServiceImpl; /*** 測試類*/ public class RunJDK {public static void main(String[] args) {MyInvocationHandler proxy = new MyInvocationHandler();UserService userServiceProxy = (UserService) proxy.bind(new UserServiceImpl());System.out.println(userServiceProxy.getName(1));System.out.println(userServiceProxy.getAge(1));} }

五、對象拷貝

61.為什么要使用克隆?

  • 想對一個對象進行處理,又想保留原有的數據進行接下來的操作,就需要克隆了。

62.如何實現對象克隆?

  • 通過拷貝構造方法實現淺拷貝
class Person{private Age age;private String name;public Person(Age age,String name) {this.age=age;this.name=name;}//拷貝構造方法public Person(Person p) {this.name=p.name;this.age=p.age; }
  • 通過重寫clone()方法進行淺拷貝
class Student implements Cloneable{//學生類的成員變量(屬性),其中一個屬性為類的對象private String name;private Age aage;private int length;//重寫Object類的clone方法public Object clone() {Object obj=null;//調用Object類的clone方法,返回一個Object實例try {obj= super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return obj;} }

63.深拷貝和淺拷貝區別是什么?

  • 淺克隆后的對象中非基本對象和原對象指向同一塊內存,因此對這些非基本對象的修改會同時更改克隆前后的對象
  • 深克隆可以實現完全的克隆,可以用重寫clone()方法或序列化的方式實現。

六、Java Web

64.jsp 和 servlet 有什么區別?

65.jsp 有哪些內置對象?作用分別是什么?

66.說一下 jsp 的 4 種作用域?

67.session 和 cookie 有什么區別?

68.說一下 session 的工作原理?

69.如果客戶端禁止 cookie 能實現 session 還能用嗎?

70.spring mvc 和 struts 的區別是什么?

71.什么是sql 注入,如何避免?

SQL注入是一種注入攻擊,可以執行惡意SQL語句。

  • 防止措施:不要使用動態SQL:避免將用戶提供的輸入直接放入SQL語句中;最好使用準備好的語句和參數化查詢,這樣更安全。
  • 補救措施:數據庫中敏感數據加密存儲
  • 降低損失:限制數據庫權限和特權:將數據庫用戶的功能設置為最低要求;這將限制攻擊者在設法獲取訪問權限時可以執行的操作。
  • 避免直接向用戶顯示數據庫錯誤:攻擊者可以使用這些錯誤消息來獲取有關數據庫的信息。
  • 定期測試與數據庫交互的Web應用程序:這樣做可以幫助捕獲可能允許SQL注入的新錯誤或回歸

72.什么是 XSS 攻擊,如何避免?

攻擊者往 web 頁面里插入惡意的 HTML 代碼(Javascript、css、html 標簽等),當用戶瀏覽該頁面時,嵌入其中的 HTML 代碼會被執行,從而達到惡意攻擊用戶的目的。如盜取用戶 cookie 執行一系列操作,破壞頁面結構、重定向到其他網站等。?

  • 預防思路:web 頁面中可由用戶輸入的地方,如果對輸入的數據轉義、過濾處理;后臺輸出頁面的時候,也需要對輸出內容進行轉義、過濾處理(因為攻擊者可能通過其他方式把惡意腳本寫入數據庫);前端對 html 標簽屬性、css 屬性賦值的地方進行校驗

73.什么是 CSRF 攻擊,如何避免?

簡單地說,是攻擊者通過一些技術手段欺騙用戶的瀏覽器去訪問一個自己曾經認證過的網站并運行一些操作(如發郵件,發消息,甚至財產操作如轉賬和購買商品)。

  • 預防思路:檢查HTTP頭的Referer字段;添加校驗token

七、異常

74.throw 和 throws 的區別?

throw:

  • 表示方法內拋出某種異常對象
  • 如果異常對象是非 RuntimeException 則需要在方法申明時加上throws 語句向上拋出異常
  • 執行到 throw 語句則后面的語句塊不再執行

throws:

  • 方法的定義上使用 throws 表示這個方法可能拋出某種異常
  • 需要由方法的調用者進行異常處理

75.final、finally、finalize 有什么區別?

  • final可以用來修飾類、方法、變量,分別有不同的意義所在,final修飾的class代表不可繼續擴展,final修飾的變量代表不可修改,final修飾的方法代表不可重寫。?
  • finally則是java保證某一段重點代碼一定要被執行的修飾符,例如:我們需要用try塊讓JDBC保證連接,保證unlock鎖等動作
  • finalize()是Object中的方法,當垃圾回收器將要回收對象所占內存之前被調用,即當一個對象被虛擬機宣告死亡時會先調用它finalize()方法,讓此對象處理它生前的最后事情

76.try-catch-finally 中哪個部分可以省略?

  • catch 和 finally 語句塊可以省略其中一個。

77.try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎?

會執行

  • 不管有沒有異常,finally中的代碼都會執行
  • 當try、catch中有return時,finally中的代碼依然會繼續執行
  • finally是在return后面的表達式運算之后執行的,此時并沒有返回運算之后的值,而是把值保存起來,不管finally對該值做任何的改變,返回的值都不會改變,依然返回保存起來的值。也就是說方法的返回值是在finally運算之前就確定了的。
  • 如果return的數據是引用數據類型,而在finally中對該引用數據類型的屬性值的改變起作用,try中的return語句返回的就是在finally中改變后的該屬性的值。
  • finally代碼中最好不要包含return,程序會提前退出,也就是說返回的值不是try或catch中的值

78.常見的異常類有哪些?

  • NullPointerException、SQLException、IndexOutOfBoundsException、NumberFormatException、FileNotFoundException、IOException
  • IllegalArgumentException、NoSuchMethodException、SecurityException、UnsupportedOperationException、RuntimeExceptionRuntimeException

八、網絡

79.http 響應碼 301 和 302 代表的是什么?有什么區別?

1xx: 信息

消息:描述:
100 Continue服務器僅接收到部分請求,但是一旦服務器并沒有拒絕該請求,客戶端應該繼續發送其余的請求。
101 Switching Protocols服務器轉換協議:服務器將遵從客戶的請求轉換到另外一種協議。
103 Checkpoint用于 PUT 或者 POST 請求恢復失敗時的恢復請求建議。

2xx: 成功

消息:描述:
200 OK請求成功(這是對HTTP請求成功的標準應答。)
201 Created請求被創建完成,同時新的資源被創建。
202 Accepted供處理的請求已被接受,但是處理未完成。
203 Non-Authoritative Information請求已經被成功處理,但是一些應答頭可能不正確,因為使用的是其他文檔的拷貝。
204 No Content請求已經被成功處理,但是沒有返回新文檔。瀏覽器應該繼續顯示原來的文檔。如果用戶定期地刷新頁面,而Servlet可以確定用戶文檔足夠新,這個狀態代碼是很有用的。
205 Reset Content請求已經被成功處理,但是沒有返回新文檔。但瀏覽器應該重置它所顯示的內容。用來強制瀏覽器清除表單輸入內容。
206 Partial Content客戶發送了一個帶有Range頭的GET請求,服務器完成了它。

3xx: 重定向

消息:描述:
300 Multiple Choices多重選擇。鏈接列表。用戶可以選擇某鏈接到達目的地。最多允許五個地址。
301 Moved Permanently所請求的頁面已經轉移至新的 URL 。
302 Found所請求的頁面已經臨時轉移至新的 URL 。
303 See Other所請求的頁面可在別的 URL 下被找到。
304 Not Modified未按預期修改文檔。客戶端有緩沖的文檔并發出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。服務器告訴客戶,原來緩沖的文檔還可以繼續使用。
305 Use Proxy客戶請求的文檔應該通過Location頭所指明的代理服務器提取。
306 Switch Proxy目前已不再使用,但是代碼依然被保留。
307 Temporary Redirect被請求的頁面已經臨時移至新的 URL 。
308 Resume Incomplete用于 PUT 或者 POST 請求恢復失敗時的恢復請求建議。
?

4xx: 客戶端錯誤

消息:描述:
400?Bad Request因為語法錯誤,服務器未能理解請求。
401 Unauthorized合法請求,但對被請求頁面的訪問被禁止。因為被請求的頁面需要身份驗證,客戶端沒有提供或者身份驗證失敗。
402 Payment Required此代碼尚無法使用。
403 Forbidden合法請求,但對被請求頁面的訪問被禁止。
404 Not Found服務器無法找到被請求的頁面。
405 Method Not Allowed請求中指定的方法不被允許。
406 Not Acceptable服務器生成的響應無法被客戶端所接受。
407 Proxy Authentication Required用戶必須首先使用代理服務器進行驗證,這樣請求才會被處理。
408 Request Timeout請求超出了服務器的等待時間。
409 Conflict由于沖突,請求無法被完成。
410 Gone被請求的頁面不可用。
411 Length Required"Content-Length" 未被定義。如果無此內容,服務器不會接受請求。
412 Precondition Failed請求中的前提條件被服務器評估為失敗。
413 Request Entity Too Large由于所請求的實體太大,服務器不會接受請求。
414 Request-URI Too Long由于 URL 太長,服務器不會接受請求。當 POST 請求被轉換為帶有很長的查詢信息的 GET 請求時,就會發生這種情況。
415 Unsupported Media Type由于媒介類型不被支持,服務器不會接受請求。
416 Requested Range Not Satisfiable客戶端請求部分文檔,但是服務器不能提供被請求的部分。
417 Expectation Failed服務器不能滿足客戶在請求中指定的請求頭。

5xx: 服務器錯誤

消息:描述:
500 Internal Server Error請求未完成。服務器遇到不可預知的情況。
501 Not Implemented請求未完成。服務器不支持所請求的功能,或者服務器無法完成請求。
502 Bad Gateway請求未完成。服務器充當網關或者代理的角色時,從上游服務器收到一個無效的響應。
503 Service Unavailable服務器當前不可用(過載或者當機)。
504 Gateway Timeout網關超時。服務器充當網關或者代理的角色時,未能從上游服務器收到一個及時的響應。
505 HTTP Version Not Supported服務器不支持請求中指明的HTTP協議版本。
511 Network Authentication Required用戶需要提供身份驗證來獲取網絡訪問入口。

80.forward 和 redirect 的區別?

  • 直接轉發方式(Forward):客戶端和瀏覽器只發出一次請求,Servlet、HTML、JSP或其它信息資源,由第二個信息資源響應該請求,在請求對象request中,保存的對象對于每個信息資源是共享的。對應RequestDispatcher類的forward()方法
  • 間接轉發方式(Redirect):實際是兩次HTTP請求,服務器端在響應第一次請求的時候,讓瀏覽器再向另外一個URL發出請求,從而達到轉發的目的。HttpServletRequest類的sendRedirect()方法。

80.get 和 post 請求有哪些區別?

  • 短的說:GET產生一個TCP數據包;POST產生兩個TCP數據包。
  • 長的說:
  • 對于GET方式的請求,瀏覽器會把http header和data一并發送出去,服務器響應200(返回數據);
  • 而對于POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data,服務器響應200 ok(返回數據)。

80.瀏覽器輸入url按回車背后經歷了哪些?

  • 解析url,檢測url地址是否合法
  • 瀏覽器先查看瀏覽器緩存-系統緩存-路由器緩存,如果緩存中有,會直接在屏幕中顯示頁面內容。若沒有,則跳到第三步操作。
  • 在發送http請求前,需要域名解析(DNS解析),解析獲取相應的IP地址。
  • 瀏覽器向服務器發起tcp連接,與瀏覽器建立tcp三次握手。
  • 握手成功后,瀏覽器向服務器發送http請求,請求數據包。
  • 服務器處理收到的請求,將數據返回至瀏覽器
  • 瀏覽器收到HTTP響應
  • 瀏覽器解碼響應,如果響應可以緩存,則存入緩存。
  • 瀏覽器發送請求獲取嵌入在HTML中的資源(html,css,javascript,圖片,音樂······),對于未知類型,會彈出對話框。
  • 瀏覽器發送異步請求。
  • 頁面全部渲染結束。

80.cookies機制和session機制的區別

  • cookies數據保存在客戶端,session數據保存在服務器端;
  • cookies可以減輕服務器壓力,但是不安全,容易進行cookies欺騙;
  • session較安全,但占用服務器資源

80.http協議請求方式

  • GET, POST 和 HEAD、OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

80.http和https區別?

HTTP協議傳輸的數據都是未加密的,也就是明文的,因此使用HTTP協議傳輸隱私信息非常不安全,為了保證這些隱私數據能加密傳輸,于是網景公司設計了SSL(Secure Sockets Layer)協議用于對HTTP協議傳輸的數據進行加密,從而就誕生了HTTPS。簡單來說,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全。總的來說: HTTPS=SSL+HTTP。HTTPS和HTTP的區別主要如下:

  • https協議需要到ca申請證書,一般免費證書較少,因而需要一定費用。
  • http和https使用的是完全不同的連接方式,默認端口也不一樣,前者是80,后者是443。(這個只是默認端口不一樣,實際上端口是可以改的)
  • http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

80.http報文

請求報文包含三部分:

  • 請求行:包含請求方法、URI、HTTP版本信息
  • 請求頭部(headers)字段
  • 請求內容實體(body)

響應報文包含三部分:

  • 狀態行:包含HTTP版本、狀態碼、狀態碼的原因短語
  • 響應頭部(headers)字段
  • 響應內容(body)實體

81.簡述 tcp 和 udp的區別?

?TCPUDP
是否需要連接基于連接無連接
對系統資源的要求較多
?流模式數據報模式?
?保證數據正確性、數據順序可能丟包、不保證順序

82.tcp 為什么要三次握手,兩次不行嗎?為什么?

83.說一下tcp 粘包是什么?

  • 發送方發送的多個數據包,到接收方緩沖區首尾相連,粘成一包,被接收。

83.?tcp 粘包是怎么產生的?

  • TCP 協議默認使用?Nagle 算法可能會把多個數據包一次發送到接收方。
  • 應用程讀取緩存中的數據包的速度小于接收數據包的速度,緩存中的多個數據包會被應用程序當成一個包一次讀取。

83.?tcp 粘包怎么解決?

  • 發送方使用 TCP_NODELAY 選項來關閉 Nagle 算法
  • 數據包增加開始符和結束符,應用程序讀取、區分數據包。
  • 在數據包的頭部定義整個數據包的長度,應用程序先讀取數據包的長度,然后讀取整個長度的包字節數據,保證讀取的是單個包且完整。

84.OSI 的七層模型都有哪些?

84.如果已經建立了連接,但是客戶端突然出現故障了怎么辦?

  • TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求后都會重新復位這個計時器,時間通常是設置為2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以后每隔75分鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認為客戶端出了故障,接著就關閉連接。

?84.TCP協議如何保證可靠傳輸

  • 確認應答機制、超時重傳機制、流量控制機制、擁塞控制機制

86.什么是跨域?

  • 域名跨越,比如A工程的前端訪問B工程的后端接口

86.如何實現跨域?

  • jsonp方式:JS設計模式中的一種代理模式。在html頁面中通過相應的標簽從不同域名下加載靜態資源文件是被瀏覽器允許的(從js中調用不行),所以我們可以通過這個“漏洞”來進行跨域。局限是只能get請求。
  • CORS:實現CORS通信的關鍵是服務器基本只需要對服務器動手腳,前端代碼跟同源時一樣,也就是不跨域時一樣。
  • nginx代理跨域:?同源策略是瀏覽器的安全策略,不是HTTP協議的一部分。服務器端調用HTTP接口只是使用HTTP協議,不會執行JS腳本,不需要同源策略,也就不存在跨越問題。通過nginx配置一個代理服務器做跳板機,反向代理訪問domain2接口實現跨域登錄。
  • 注:反向代理:正常我們可以通過內網可以通過代理來訪問外網,這個算是正向代理;反向代理就相當于通過代理讓外網可以訪問到我們內網

87.說一下 JSONP 實現原理?

  • 參考86題

九、設計模式

88.說一下你熟悉的設計模式?

  • 單例模式、責任鏈模式
  • 單例模式優點:內存里只有一個實例減少了內存的開銷、可以避免對資源的多重占用、單例模式設置全局訪問點,可以優化和共享資源的訪問。
  • 單例模式的缺點:沒有接口擴展困難、在并發測試中,單例模式不利于代碼調試、

88.單例模式?

  • 懶漢模式
public class LazySingleton {private static volatile LazySingleton instance = null; //保證 instance 在所有線程中同步private LazySingleton() {} //private 避免類在外部被實例化public static synchronized LazySingleton getInstance() {//getInstance 方法前加同步if (instance == null) {instance = new LazySingleton();}return instance;} }
  • 餓漢模式
public class HungrySingleton {private static final HungrySingleton instance = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return instance;} }

單例模式代碼重點:

  • 構造函數需要用private修飾
  • 懶漢模式需要 volatile修飾,餓漢模式需要final模式修飾

88.原型模式

class Prototype implements Cloneable {public Prototype clone(){Prototype prototype = null;try{prototype = (Prototype)super.clone();}catch(CloneNotSupportedException e){e.printStackTrace();}return prototype; } }class ConcretePrototype extends Prototype{public void show(){System.out.println("原型模式實現類");} }public class Client {public static void main(String[] args){ConcretePrototype cp = new ConcretePrototype();for(int i=0; i< 10; i++){ConcretePrototype clonecp = (ConcretePrototype)cp.clone();clonecp.show();}} }

原型模式主要用于對象的復制,它的核心是就是類圖中的原型類Prototype。Prototype類需要具備以下兩個條件:

  • 實現Cloneable接口。在java語言有一個Cloneable接口,它的作用只有一個,就是在運行時通知虛擬機可以安全地在實現了此接口的類上使用clone方法。在java虛擬機中,只有實現了這個接口的類才可以被拷貝,否則在運行時會拋出CloneNotSupportedException異常。
  • 重寫Object類中的clone方法。Java中,所有類的父類都是Object類,Object類中有一個clone方法,作用是返回對象的一個拷貝,但是其作用域protected類型的,一般的類無法調用,因此,Prototype類需要將clone方法的作用域修改為public類型。
  • 原型模式是一種比較簡單的模式,也非常容易理解,實現一個接口,重寫一個方法即完成了原型模式。在實際應用中,原型模式很少單獨出現。經常與其他模式混用,他的原型類Prototype也常用抽象類來替代。

88.代理模式?

1)代理模式的好處

  • 中介隔離作用:在某些情況下,一個客戶類不想或者不能直接引用一個委托對象,而代理類對象可以在客戶類和委托對象之間起到中介的作用,其特征是代理類和委托類實現相同的接口。
  • 開閉原則,增加功能:代理類除了是客戶類和委托類的中介之外,我們還可以通過給代理類增加額外的功能來擴展委托類的功能,這樣做我們只需要修改代理類而不需要再修改委托類,符合代碼設計的開閉原則。代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后對返回結果的處理等。代理類本身并不真正實現服務,而是同過調用委托類的相關方法,來提供特定的服務。真正的業務功能還是由委托類來實現,但是可以在業務功能執行的前后加入一些公共的服務。例如我們想給項目加入緩存、日志這些功能,我們就可以使用代理類來完成,而沒必要打開已經封裝好的委托類。

2)靜態代理

//第一步:創建服務類接口 public interface BuyHouse {void buyHosue(); }//第二步:實現服務接口 import main.java.proxy.BuyHouse; public class BuyHouseImpl implements BuyHouse {@Overridepublic void buyHosue() {System.out.println("我要買房");} }//第三步:創建代理類 package main.java.proxy.impl; import main.java.proxy.BuyHouse; public class BuyHouseProxy implements BuyHouse {private BuyHouse buyHouse;public BuyHouseProxy(final BuyHouse buyHouse) {this.buyHouse = buyHouse;}@Overridepublic void buyHosue() {System.out.println("買房前準備");buyHouse.buyHosue();System.out.println("買房后裝修");} }//第四步:編寫測試類 import main.java.proxy.impl.BuyHouseImpl; import main.java.proxy.impl.BuyHouseProxy; public class ProxyTest {public static void main(String[] args) {BuyHouse buyHouse = new BuyHouseImpl();buyHouse.buyHosue();BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);buyHouseProxy.buyHosue();} }

靜態代理總結:

  • 優點:可以做到在符合開閉原則的情況下對目標對象進行功能擴展。
  • 缺點:我們得為每一個服務都得創建代理類,工作量太大,不易管理。同時接口一旦發生改變,代理類也得相應修改

3)動態代理

在動態代理中我們不再需要再手動的創建代理類,我們只需要編寫一個動態處理器就可以了。真正的代理對象由JDK再運行時為我們動態的來創建。

//第一步:編寫動態處理器 package main.java.proxy.impl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxyHandler implements InvocationHandler {private Object object;public DynamicProxyHandler(final Object object) {this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("買房前準備");Object result = method.invoke(object, args);System.out.println("買房后裝修");return result;} }//第二步:編寫測試類 package main.java.proxy.test; import main.java.proxy.BuyHouse; import main.java.proxy.impl.BuyHouseImpl; import main.java.proxy.impl.DynamicProxyHandler; import java.lang.reflect.Proxy; public class DynamicProxyTest {public static void main(String[] args) {BuyHouse buyHouse = new BuyHouseImpl();BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), newClass[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse));proxyBuyHouse.buyHosue();} }

88.工廠模式?

  • 工廠模式是什么是創建模式的一種,共分為簡單工廠,工廠方法和抽象工廠三種

1)使用工廠模式的好處是什么?

  • 解耦:把對象的創建和使用的過程分開。就是Class A 想調用 Class B ,那么A只是調用B的方法,而至于B的實例化,就交給工廠類。
  • 降低代碼重復:如果創建對象B的過程都很復雜,需要一定的代碼量,而且很多地方都要用到,那么就會有很多的重復代碼。我們可以這些創建對象B的代碼放到工廠里統一管理。既減少了重復代碼,也方便以后對B的創建過程的修改維護。(當然,我個人覺得也可以把這些創建過程的代碼放到類的構造函數里,同樣可以降低重復率,而且構造函數本身的作用也是初始化對象。不過,這樣也會導致構造函數過于復雜,做的事太多,不符合java 的設計原則。)
  • 減少修改量:由于創建過程都由工廠統一管理,所以發生業務邏輯變化,不需要找到所有需要創建B的地方去逐個修正,只需要在工廠里修改即可,降低維護成本。同理,想把所有調用B的地方改成B的子類B1,只需要在對應生產B的工廠中或者工廠的方法中修改其生產的對象為B1即可,而不需要找到所有的new B()改為new B1()。
  • 減少使用復雜度:另外,因為工廠管理了對象的創建邏輯,使用者并不需要知道具體的創建過程,只管使用即可,減少了使用者因為創建邏輯導致的錯誤。

2)工廠模式的具體分類及實現代碼

  • 產品類代碼如下:
public interface Shape {void draw(); }public class Circle implements Shape {@Overridepublic void draw() {System.out.println("畫一個圓");} }public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("畫一個矩形");} }
  • 簡單工廠

public class ShapeFactory {public Shape getShape(String shapeType){if(shapeType.equalsIgnoreCase("circle")){return new Circle();}else if(shapeType.equalsIgnoreCase("rectangle")){return new Rectangle();}else if(shapeType.equalsIgnoreCase("squere")){return new Squere();}return null;}public Shape getShape(Class clazz) throws Exception{return (Shape) clazz.newInstance();} }
  • 工廠方法

public abstract class ShapeFactory {public abstract Shape getShape(); }public class CircleFactory extends ShapeFactory {@Overridepublic Shape getShape() {return new Circle();} }public class RectangleFactroy extends ShapeFactory {@Overridepublic Shape getShape() {return new Rectangle();} }

3)簡單工廠、工廠方法、抽象工廠的區別是什么?

  • 簡單工廠所有產品由同一個工廠創建
  • 工廠方法每一個產品對應一個工廠

89.簡單工廠和抽象工廠有什么區別?

十、Spring/Spring MVC

90.為什么要使用 spring?

spring 是一個開源的輕量級 JavaBean 容器框架。

  • 輕量:非入侵性的、所依賴的東西少、資源占用少、部署簡單,不同功能選擇不同的 jar 組合
  • 容器:工廠模式實現對 JavaBean 進行管理,通過控制反轉(IOC)將應用程序的配置和依賴性與應用代碼分開
  • 松耦合:通過 xml 配置或注解即可完成 bean 的依賴注入
  • AOP:通過 xml 配置 或注解即可加入面向切面編程的能力,完成切面功能,如:日志,事務...的統一處理
  • 方便集成:通過配置和簡單的對象注入即可集成其他框架,如 Mybatis、Hibernate、Shiro...
  • 豐富的功能:JDBC 層抽象、事務管理、MVC、Java Mail、任務調度、JMX、JMS、JNDI、EJB、動態語言、遠程訪問、Web Service...?

91.解釋一下什么是 aop?

  • 面向切面編程技術:這種在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面的編程。
  • 使用AOP技術,可以將一些系統性相關的編程工作,獨立提取出來,獨立實現,然后通過切面切入進系統。從而避免了在業務邏輯的代碼中混入很多的系統相關的邏輯——比如權限管理,事物管理,日志記錄等等。

92.解釋一下什么是 ioc?

  • 控制反轉,是 spring 的核心,對于 spring 框架來說,就是由 spring 來負責控制對象的生命周期和對象間的關系。 簡單來說,控制指的是當前對象對內部成員的控制權;控制反轉指的是,這種控制權不由當前對象管理了,由其他(類,第三方容器)來管理。

93.spring 有哪些主要模塊?

Spring框架的七大模塊

  • 1. Spring Core:框架的最基礎部分,提供 IoC 容器,對 bean 進行管理。
  • 2.Spring Context:基于 bean,提供上下文信息,擴展出JNDI、EJB、電子郵件、國際化、校驗和調度等功能。
  • 3.Spring DAO:提供了JDBC的抽象層,它可消除冗長的JDBC編碼和解析數據庫廠商特有的錯誤代碼,還提供了聲明性事務管理方法。
  • 4.Spring ORM:提供了常用的“對象/關系”映射APIs的集成層。 其中包括JPA、JDO、Hibernate、MyBatis 等。
  • 5.Spring AOP:提供了符合AOP Alliance規范的面向方面的編程實現。
  • 6.Spring Web:提供了基礎的 Web 開發的上下文信息,可與其他 web 進行集成。
  • 7.Spring Web MVC:提供了 Web 應用的 Model-View-Controller 全功能實現。

94.spring 常用的注入方式有哪些?

  • 構造方法注入,setter注入,基于注解的注入。

95.spring 中的 bean 是線程安全的嗎?

結論是非線程安全的。Spring容器本身并沒有提供Bean的線程安全策略,因此可以說Spring容器中的Bean本身不具備線程安全的特性,但是具體還是要結合具體scope的Bean去研究。Spring 的 bean 作用域(scope)類型

  • singleton:單例,默認作用域。
  • prototype:原型,每次創建一個新對象。
  • request:請求,每次Http請求創建一個新對象,適用于WebApplicationContext環境下。
  • session:會話,同一個會話共享一個實例,不同會話使用不用的實例。
  • global-session:全局會話,所有會話共享一個實例。

線程安全這個問題,要從單例與原型Bean分別進行說明。對于原型Bean,每次創建一個新對象,也就是線程之間并不存在Bean共享,自然是不會有線程安全的問題。對于單例Bean,所有線程都共享一個單例實例Bean,因此是存在資源的競爭。如果單例Bean,是一個無狀態Bean,也就是線程中的操作不會對Bean的成員執行查詢以外的操作,那么這個單例Bean是線程安全的。比如Spring mvc 的 Controller、Service、Dao等,這些Bean大多是無狀態的,只關注于方法本身。

96.spring 支持幾種 bean 的作用域?

  • 5種,參考94題

97.spring 自動裝配 bean 有哪些方式?

98.spring 事務實現方式有哪些?

99.說一下 spring 的事務隔離?

100.說一下 spring mvc 運行流程?

101.spring mvc 有哪些組件?

102.@RequestMapping 的作用是什么?

  • 是一個注解,用來標識 http 請求地址與 Controller 類的方法之間的映射。

103.@Autowired 的作用是什么?與@Resource的區別?

  • @Autowired 是一個注解,它可以對類成員變量、方法及構造函數進行標注,讓 spring 完成 bean 自動裝配的工作。
  • @Resource的作用相當于@Autowired,只不過@Autowired按byType自動注入,而@Resource默認按 byName自動注入罷了。

十一、Spring Boot/Spring Cloud

104.什么是 spring boot?

  • Spring Boot是Spring組件一站式解決方案,主要是簡化了使用Spring的難度,簡省了繁重的配置,提供了各種啟動器,開發者能快速上手。

105.為什么要用 spring boot?

  • 參考104題

106.spring boot 核心配置文件是什么?

  • application.yml:用于 Spring Boot 項目的自動化配置,包括數據庫連接信息、redis連接信息等
  • bootstrap:使用 Spring Cloud Config 配置中心時,這時需要在 bootstrap 配置文件中添加連接到配置中心的配置屬性來加載外部配置中心的配置信息;

107.spring boot 配置文件有哪幾種類型?它們有什么區別?

  • .properties 和 .yml,它們的區別主要是書寫格式不同。 另外,.yml 格式不支持 @PropertySource 注解導入配置。
.propertiesapp.user.name = javastack
.yml

app:

? ? user:
? ? ? ? ?name: javastack

108.spring boot 有哪些方式可以實現熱部署?

109.jpa 和 hibernate 有什么區別?

  • JPA本身是一種規范,它的本質是一種ORM規范(不是ORM框架,因為JPA并未提供ORM實現,只是制定了規范)。
  • JPA是標準接口,Hibernate是實現,并不是對標關系,借用下圖可以看清楚他們之間的關系,Hibernate屬于遵循JPA規范的一種實現,但是JPA是Hibernate遵循的規范之一,Hibernate還有其他實現的規范

110.什么是 spring cloud?

  • 基于Spring Boot用于快速構建分布式系統的通用模式的工具集.使用Spring Cloud開發的應用程序非常適合在Docker或者Pass上部署,所以又叫云原生應用(Cloud Native Application). 云原生可以簡單的理解為面向云環境的軟件架構;

111.spring cloud 斷路器的作用是什么?

  • 在分布式架構中,斷路器模式的作用也是類似的,當某個服務單元發生故障(類似用電器發生短路)之后,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回一個錯誤響應,而不是長時間的等待。這樣就不會使得線程因調用故障服務被長時間占用不釋放,避免了故障在分布式系統中的蔓延。

112.spring cloud 的核心組件有哪些?

  • 服務發現——Netflix Eureka
  • 客服端負載均衡——Netflix Ribbon
  • 斷路器——Netflix Hystrix
  • 服務網關——Netflix Zuul
  • 分布式配置——Spring Cloud Config

十二、Hibernate

113.為什么要使用 hibernate?

114.什么是 ORM 框架?

115.hibernate 中如何在控制臺查看打印的 sql 語句?

116.hibernate 有幾種查詢方式?

117.hibernate 實體類可以被定義為 final 嗎?

118.在 hibernate 中使用 Integer 和 int 做映射有什么區別?

119.hibernate 是如何工作的?

120.get()和 load()的區別?

121.說一下 hibernate 的緩存機制?

122.hibernate 對象有哪些狀態?

123.在 hibernate 中 getCurrentSession 和 openSession 的區別是什么?

124.hibernate 實體類必須要有無參構造函數嗎?為什么?

十三、Mybatis

125.mybatis 中 #{}和 ${}的區別是什么?

126.mybatis 有幾種分頁方式?

127.RowBounds 是一次性查詢全部結果嗎?為什么?

128.mybatis 邏輯分頁和物理分頁的區別是什么?

129.mybatis 是否支持延遲加載?延遲加載的原理是什么?

130.說一下 mybatis 的一級緩存和二級緩存?

131.mybatis 和 hibernate 的區別有哪些?

132.mybatis 有哪些執行器(Executor)?

133.mybatis 分頁插件的實現原理是什么?

134.mybatis 如何編寫一個自定義插件?

十四、RabbitMQ

135.rabbitmq 的使用場景有哪些?

136.rabbitmq 有哪些重要的角色?

  • 生產者:消息的創建者,負責創建和推送數據到消息服務器
  • 消費者:消息的接收方,用于處理數據和確認消息
  • 代理:rabbitmq 本身不生產消息,只是儲存和傳遞消息

137.rabbitmq 有哪些重要的組件?

  • ConnectionFactory(連接管理器):應用程序與 rabbit 之間建立連接的管理器,程序代碼中使用
  • Channel(信道):消息推送使用的通道
  • Exchange(交換器):用于接收、分配消息
  • Queue(隊列):用于存儲生產者的消息
  • RoutingKey(路由鍵):用于把生產者的數據分配到交換器上
  • BindingKey(綁定鍵):用于把交換器的消息綁定到隊列上

138.rabbitmq 中 vhost 的作用是什么?

  • vhost 可以理解為虛擬 broker,即 mini-RabbitMQ server。其內部均含有獨立的 queue、exchange 和 binding 等,但最最重要的是,其擁有的獨立的權限系統,可以做到vhost范圍的用戶控制。從rabbitmq的全局角度,vhost可以作為不同權限隔離的手段,不同的應用可以泡在不同的vhost中

139.rabbitmq 的消息是怎么發送的?

  • 首先客戶端必須連接到 RabbitMQ 服務器才能發布和消費消息,客戶端和 rabbit server 之間會創建一個 tcp 連接,一旦 tcp 打開并通過了認證(認證就是你發送給 rabbit 服務器的用戶名和密碼),你的客戶端和 RabbitMQ 就創建了一條 amqp 信道(channel),信道是創建在“真實” tcp 上的虛擬連接,amqp 命令都是通過信道發送出去的,每個信道都會有一個唯一的 id,不論是發布消息,訂閱隊列都是通過這個信道完成的。

140.rabbitmq 怎么保證消息的穩定性?

  • 提供事務功能
  • 將 channel 設置為 comfirm(確認)模式

141.rabbitmq 怎么避免消息丟失?

  • 消息持久化
  • ack 確認機制
  • 設置集群鏡像模式
  • 消息補償機制

142.要保證消息持久化成功的條件有哪些?

  • 聲明隊列必須設置持久化,將 durable 設為 true
  • 消息推送投遞模式必須設置持久化,deliveryMode 設置為2(持久)
  • 消息已經到達持久化交換器
  • 消息已經到達持久化隊列

143.rabbitmq 持久化有什么缺點?

  • 持久化會降低服務器的吞吐量,因為使用磁盤而非內存存儲,盡可能使用ssd硬盤來緩解吞吐量問題

144.rabbitmq 有幾種廣播類型?

  • fanout:所有 bind 到此 exchange 的 queue 都可以接受消息
  • direct:通過 routingKey 和 exchange 決定那個唯一的 queue 可以接收消息
  • topic:符合表達式的 routing 所綁定的 queue 可以接收消息,* 匹配一個詞,# 匹配一個或多個詞

145.rabbitmq 怎么實現延遲消息隊列?

  • 通過消息過期后進入死信交換器,再由交換器轉發到延遲消費隊列,實現延遲功能
  • 使用 RabbitMQ-delayed-message-exchange 插件實現延遲功能

146.rabbitmq 集群有什么用?

  • 高可用:某個服務器出現問題,整個 rabbitmq 還可以繼續使用
  • 高容量:集群可以承載更多的消息量

147.rabbitmq 節點的類型有哪些?

  • 磁盤節點:消息會存儲到磁盤
  • 內存節點:消息存儲到內存中,重啟服務器消息丟失,性能高于磁盤節點

148.rabbitmq 集群搭建需要注意哪些問題?

  • 個節點之間使用“--link”連接,該屬性不能忽略
  • 個節點使用的 erlang cookie 值必須相同,該值相當于密鑰,用于各節點的認證
  • 整個集群中必須包含一個磁盤節點

149.rabbitmq 每個節點是其他節點的完整拷貝嗎?為什么?

不是完整拷貝,原因:

  • 存儲空間的考慮:如果每個節點都擁有所有隊列的完全拷貝,這樣新增節點不但沒有新增存儲空間,反而增加了更多冗余數據
  • 性能考慮:如果每條消息都需要完整拷貝到每一個集群節點,那新增節點并沒有提升處理消息的能力,最多是保持和單節點相同的性能甚至更糟
  • 150.rabbitmq 集群中唯一一個磁盤節點崩潰了會發生什么情況?

    • 不能創建隊列
    • 不能創建交換器
    • 不能創建綁定
    • 不能創建用戶
    • 不能更改權限
    • 不能添加和刪除集群節點

    唯一磁盤節點奔潰,集群可以保持運行,但不能更改任何東西

    151.rabbitmq 對集群節點停止順序有要求嗎?

    • rabbitmq 對集群定制順序有要求,先關閉內存節點,最后關閉磁盤節點。如果順序相反,會造成消息丟失

    十五、Kafka

    152.kafka 可以脫離 zookeeper 單獨使用嗎?為什么?

    • kafka 不能脫離 zookeeper 單獨使用,因為 kafka 使用 zookeeper 管理和協調 kafka 的節點服務器。

    153.kafka 有幾種數據保留的策略?

    kafka 有兩種數據保存策略:

    • 按照過期時間保留。
    • 按照存儲的消息大小保留。

    154.kafka 同時設置了 7 天和 10G 清除數據,到第五天的時候消息達到了 10G,這個時候 kafka 將如何處理?

    • 這個時候?kafka 會執行數據清除工作,時間和大小不論那個滿足條件,都會清空數據。

    155.什么情況會導致 kafka 運行變慢?

    • cpu 性能瓶頸
    • 磁盤讀寫瓶頸
    • 網絡瓶頸

    156.使用 kafka 集群需要注意什么?

    • 集群的數量不是越多越好,最好不要超過?7 個,因為節點越多,消息復制需要的時間就越長,整個群組的吞吐量就越低。
    • 集群數量最好是單數,因為超過一半故障集群就不能用了,設置為單數容錯率更高。

    156.Kafka性能強于RabbitMQ的原因

    • 頁緩存技術+磁盤順序寫(寫數據):頁緩存Page Cache—操作系統自己管理的內存緩存(os cache),由CPU決定了什么時候將數據寫入磁盤
    • 零拷貝技術(讀數據):?Kafka的設計是直接將操作系統OS Cache中的數據發送到網卡,跳過了兩次拷貝數據的步驟,Socket緩存中僅僅會拷貝一個文件描述符過去,不會拷貝數據到Socket緩存,大大提升了數據讀取性能。

    十六、Zookeeper

    157.zookeeper 是什么?

    • 經典的分布式數據一致性解決方案,致力于為分布式應用提供一個高性能、高可用,且具有嚴格順序訪問控制能力的分布式協調服務。?

    158.zookeeper 都有哪些功能?

    • 分布式應用程序可以基于ZooKeeper實現數據發布與訂閱、負載均衡、命名服務、分布式協調與通知、集群管理、Leader選舉、分布式鎖、分布式隊列等功能。

    159.zookeeper 有幾種部署模式?

    • 單機部署:一般用來檢驗Zookeeper基礎功能,熟悉ZK各種基礎操作及特性;
    • 偽集群部署:在單臺機器上部署集群,方便在本地驗證集群模式下的各種功能;

    集群部署:一般在生產環境使用,具備一致性、分區容錯性;

    159.zookeeper 有幾種角色?

    • 領導者(leader):負責進行投票的發起和決議,更新系統狀態
    • 學習者(learner):包括跟隨者(follower)和觀察者(observer),follower用于接受客戶端請求并想客戶端返回結果,在選主過程中參與投票;Observer可以接受客戶端連接,將寫請求轉發給leader,但observer不參加投票過程,只同步leader的狀態,observer的目的是為了擴展系統,提高讀取速度
    • 客戶端(client),請求發起方

    159.zookeeper為什么需要Observer?

    • Zookeeper需保證高可用和強一致性;為了支持更多的客戶端,需要增加更多Server;Server增多,投票階段延遲增大,影響性能;
    • 權衡伸縮性和高吞吐率,引入Observer。Observer不參與投票;Observers接受客戶端的連接,并將寫請求轉發給leader節點;
    • 加入更多Observer節點,提高伸縮性,同時不影響吞吐率
    • 總結:server有投票權,observer沒有投票權,其他功能一樣

    160.zookeeper 怎么保證主從節點的狀態同步?

    • Zookeeper的核心是原子廣播,這個狀態同步機制保證了leader和server具有相同的系統狀態。實現這個機制的協議叫做Zab協議。Zab協議有兩種模式,它們分別是恢復模式和廣播模式。

    160.恢復模式是什么?什么時候進入恢復模式?

    • 當服務啟動或者在領導者崩潰后,Zab就進入了恢復模式,當領導者被選舉出來,且大多數server的完成了和leader的狀態同步以后,恢復模式就結束了。

    160.廣播模式是什么?什么時候進入廣播模式?

    • 一旦leader已經和多數的follower進行了狀態同步后,leader就可以開始廣播消息了,即進入廣播狀態。這時候當一個server加入zookeeper服務中,它會在恢復模式下啟動,發現leader,并和leader進行狀態同步。待到同步結束,它也參與消息廣播。
    • Zookeeper服務一直維持在Broadcast狀態,直到leader崩潰了或者leader失去了大部分的followers支持。

    160.zookeeper選舉?

    半數通過(大于,不是大于等于),比如3臺機器掛一臺,2>3/2;4臺機器掛2臺 2!>4/2

    • A提案說,我要選自己,B你同意嗎?C你同意嗎?B說,我同意選A;C說,我同意選A。(注意,這里超過半數了,其實在現實世界選舉已經成功了。但是計算機世界是很嚴格,另外要理解算法,要繼續模擬下去。)
    • 接著B提案說,我要選自己,A你同意嗎;A說,我已經超半數同意當選,你的提案無效;C說,A已經超半數同意當選,B提案無效。
    • 接著C提案說,我要選自己,A你同意嗎;A說,我已經超半數同意當選,你的提案無效;B說,A已經超半數同意當選,C的提案無效。
    • 選舉已經產生了Leader,后面的都是follower,只能服從Leader的命令。

    而且這里還有個小細節,就是其實誰先啟動誰當頭。

    160.為什么zookeeper集群的數目一般為奇數個?

    • Leader選舉算法采用了Paxos協議;
    • Paxos核心思想:當多數Server寫成功,則任務數據寫成功。如果有3個Server,則兩個寫成功即可;如果有4或5個Server,則三個寫成功即可。Server數目一般為奇數(3、5、7)如果有3個Server,則最多允許1個Server掛掉;如果有4個Server,則同樣最多允許1個Server掛掉由此,
    • 我們看出3臺服務器和4臺服務器的的容災能力是一樣的,所以為了節省服務器資源,一般我們采用奇數個數,作為服務器部署個數。

    162.集群中有 3 臺服務器,其中一個節點宕機,這個時候 zookeeper 還可以使用嗎?

    • 可以

    160.zookeeper的讀寫機制

    • Zookeeper是一個由多個server組成的集群,一個leader,多個follower
    • 每個server保存一份數據副本
    • 全局數據一致
    • 分布式讀寫
    • 更新請求轉發,由leader實施

    160.數據操作流程

           

    • 1.在Client向Follwer發出一個寫的請求
    • 2.Follwer把請求發送給Leader
    • 3.Leader接收到以后開始發起投票并通知Follwer進行投票
    • 4.Follwer把投票結果發送給Leader
    • 5.Leader將結果匯總,如果需要寫入,則開始寫入同時把寫入操作通知給Follwer,然后commit;
    • 6.Follwer把請求結果返回給Client

    160.Follower主要有四個功能:

    • 向Leader發送請求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
    • 接收Leader消息并進行處理;
    • 接收Client的請求,如果為寫請求,發送給Leader進行投票;
    • 返回Client結果。

    160.zookeeper保證:

    • 更新請求順序進行,來自同一個client的更新請求按其發送順序依次執行
    • 數據更新原子性,一次數據更新要么成功,要么失敗
    • 全局唯一數據視圖,client無論連接到哪個server,數據視圖都是一致的
    • 實時性,在一定事件范圍內,client能讀到最新數據

    160.zookeeper如何保證寫請求順序執行?(數據一致性與Paxos算法)

    • 保持數據的一致性有個原則就是:在一個分布式數據庫系統中,如果各節點的初始狀態一致,每個節點都執行相同的操作序列,那么他們最后能得到一個一致的狀態。
    • Paxos算法解決的就是保證每個節點執行相同的操作序列。好吧,這還不簡單,master維護一個全局寫隊列,所有寫操作都必須放入這個隊列編號,那么無論我們寫多少個節點,只要寫操作是按編號來的,就能保證一致性。沒錯,就是這樣,可是如果master掛了呢。
    • Paxos算法通過投票來對寫操作進行全局編號,同一時刻,只有一個寫操作被批準,同時并發的寫操作要去爭取選票,只有獲得過半數選票的寫操作才會被批準(所以永遠只會有一個寫操作得到批準),其他的寫操作競爭失敗只好再發起一輪投票,就這樣,在日復一日年復一年的投票中,所有寫操作都被嚴格編號排序。編號嚴格遞增,當一個節點接受了一個編號為100的寫操作,之后又接受到編號為99的寫操作(因為網絡延遲等很多不可預見原因),它馬上能意識到自己數據不一致了,自動停止對外服務并重啟同步過程。任何一個節點掛掉都不會影響整個集群的數據一致性(總2n+1臺,除非掛掉大于n臺)。

    161.集群中為什么要有主節點?

    • 在分布式環境中,有些業務邏輯只需要集群中的某一臺機器進行,其他機器可以共享這個結果,這樣可以大大減少重復計算,提高性能,所以就需要主節點

    163.說一下 zookeeper 的通知機制?

    • 客戶端注冊監聽它關心的目錄節點,當節點發生變化時(數據增刪改、子目錄節點增刪改)時,zookeeper就會通知客戶端。通知機制是觀察者(watch)的模式,異步回調的觸發機制。zookeeper支持watch的概念,客戶端可在每個znode節點上設置一個觀察。如被觀察服務端的znode節點有變更,那么watch就會被觸發,這watch所屬的客戶端就會收到一個通知包,被告知節點已經發生變化,把對應的事件通知給設置過的Watcher的Client端。
    • zookeeper所有讀操作:getData(),getChildren()和exists()都有設置watch的選項,watch只會通知一次!

    十七、MySql

    164.數據庫的三范式是什么?

    165.一張自增表里面總共有 7 條數據,刪除了最后 2 條數據,重啟 mysql 數據庫,又插入了一條數據,此時 id 是幾?

    • 一般情況下,我們創建的表的類型是InnoDB,如果新增一條記錄(不重啟mysql的情況下),這條記錄的id是8;但是如果重啟(文中提到的)MySQL的話,這條記錄的ID是6。因為InnoDB表只把自增主鍵的最大ID記錄到內存中,所以重啟數據庫或者對表OPTIMIZE操作,都會使最大ID丟失。
    • 但是,如果我們使用表的類型是MylSAM,那么這條記錄的ID就是8。因為MylSAM表會把自增主鍵的最大ID記錄到數據文件里面,重啟MYSQL后,自增主鍵的最大ID也不會丟失。

    166.如何獲取當前數據庫版本?

    • 在cmd里面輸入 mysql -V 來獲取mysql版本號如圖

    167.說一下 ACID 是什么?

    • Atomicity 原子性:整個事務是一個獨立的單元,要么操作成功,要么操作不成功
    • Consistency 一致性:事務必須要保持和系統處于一致的狀態(如果不一致會導致系統其它的方出現bug)
    • Isolation 隔離性:事務是并發控制機制,他們的交錯也需要一致性,隔離隱藏,一般通過悲觀或者樂觀鎖實現
    • Durability 耐久性:一個成功的事務將永久性地改變系統的狀態,所以在它結束之前,所有導致狀態的變化都記錄在一個持久的事務日志中

    168.char 和 varchar 的區別是什么?

    • char類型的長度是固定的,varchar的長度是可變的。這就表示,存儲字符串'abc',
    • 使用char(10),表示存儲的字符將占10個字節(包括7個空字符)
    • 使用varchar2(10),,則表示只占3個字節,10是最大值,當存儲的字符小于10時,按照實際的長度存儲。

    169.float 和 double 的區別是什么?

    • 01.在內存中占有的字節數不同:單精度浮點數在機內存占4個字節;雙精度浮點數在機內存占8個字節
    • 02.有效數字位數不同:單精度浮點數有效數字8位;雙精度浮點數有效數字16位
    • 03.數值取值范圍:單精度浮點數的表示范圍:-3.40E+38~3.40E+38;雙精度浮點數的表示范圍:-1.79E+308~-1.79E+308
    • 04.在程序中處理速度不同:一般來說,CPU處理單精度浮點數的速度比處理雙精度浮點數快

    170.mysql 的內連接、左連接、右連接有什么區別?

    171.mysql 索引是怎么實現的?

    • Mysql的索引使用B+樹實現,B+樹可以快速搜索到想要的數據。(哈希表、平衡二叉樹、B樹、B+樹都是索引數據結構)

    172.怎么驗證 mysql 的索引是否滿足需求?

    • explain可以檢查你的sql索引命中情況,實際上線后,最好配合監控來看下接口的RT

    173.說一下數據庫的事務隔離?

    數據庫事務的隔離級別有4種,由低到高分別為Read uncommitted 、Read committed 、Repeatable read 、Serializable?

    • Read uncommitted:一個事務可以讀取另一個未提交事務的數據。會產生臟讀
    • Read committed :一個事務要等另一個事務提交后才能讀取數據。讀提交就是若有事務對數據進行更新(UPDATE)操作時,讀操作事務要等待這個更新操作事務提交后才能讀取數據,可以解決臟讀問題。但在這個事例中,出現了一個事務范圍內兩個相同的查詢卻返回了不同數據,這就是不可重復讀。
    • Repeatable read:就是在開始讀取數據(事務開啟)時,不再允許修改操作。重復讀可以解決不可重復讀問題。寫到這里,應該明白的一點就是,不可重復讀對應的是修改,即UPDATE操作。但是可能還會有幻讀問題。因為幻讀問題對應的是插入INSERT操作,而不是UPDATE操作
    • Serializable :Serializable 是最高的事務隔離級別,在該級別下,事務串行化順序執行,可以避免臟讀、不可重復讀與幻讀。但是這種事務隔離級別效率低下,比較耗數據庫性能,一般不使用。

    173.四種隔離級別可能導致的問題:

    • Serializable (串行化):最嚴格的級別,事務串行執行,資源消耗最大;
    • REPEATABLE READ(重復讀) :保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“臟讀取”和“不可重復讀取”的情況,但不能避免“幻讀”,但是帶來了更多的性能損失。
    • READ COMMITTED (提交讀):大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另一個并行事務已修改但未提交的數據,避免了“臟讀取”,但不能避免“幻讀”和“不可重復讀取”。該級別適用于大多數系統。
    • Read Uncommitted(未提交讀) :事務中的修改,即使沒有提交,其他事務也可以看得到,會導致“臟讀”、“幻讀”和“不可重復讀取”。

    174.說一下 mysql 常用的引擎?

    • MyISAM:B+樹結構,葉子結點存的數據的引用。支持全文索引;不支持事務;它是表級鎖;會保存表的具體行數.
    • InnoDB:B+樹結構,葉子結點存的數據。5.6以后才有全文索引;支持事務;它是行級鎖;不會保存表的具體行數.

    175.說一下 mysql 的行鎖和表鎖?

    • MyISAM 只支持表鎖,InnoDB 支持表鎖和行鎖,默認為行鎖。
    • 表級鎖:開銷小,加鎖快,不會出現死鎖。鎖定粒度大,發生鎖沖突的概率最高,并發量最低。
    • 行級鎖:開銷大,加鎖慢,會出現死鎖。鎖力度小,發生鎖沖突的概率小,并發度最高。

    176.說一下樂觀鎖和悲觀鎖?

    • 樂觀鎖:每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在提交更新的時候會判斷一下在此期間別人有沒有去更新這個數據。
    • 悲觀鎖:每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻止,直到這個鎖被釋放。
    • 數據庫的樂觀鎖需要自己實現,在表里面添加一個 version 字段,每次修改成功值加 1,這樣每次修改的時候先對比一下,自己擁有的 version 和數據庫現在的 version 是否一致,如果不一致就不修改,這樣就實現了樂觀鎖。

    177.mysql 問題排查都有哪些手段?

    • 使用 show processlist 命令查看當前所有連接信息。
    • 使用 explain 命令查詢 SQL 語句執行計劃。
    • 開啟慢查詢日志,查看慢查詢的 SQL。

    178.如何做 mysql 的性能優化?

    • 為搜索字段創建索引。
    • 避免使用 select *,列出需要查詢的字段。
    • 避免使用where +<> 和where +null
    • 選擇正確的存儲引擎。
    • 分庫分表
    • 讀寫分離

    十八、Redis

    179.redis 是什么?都有哪些使用場景?

    180.redis 有哪些功能?

    181.redis 和 memecache 有什么區別?

    182.redis 為什么是單線程的?

    183.什么是緩存穿透?怎么解決?

    184.redis 支持的數據類型有哪些?

    185.redis 支持的 java 客戶端都有哪些?

    186.jedis 和 redisson 有哪些區別?

    187.怎么保證緩存和數據庫數據的一致性?

    188.redis 持久化有幾種方式?

    189.redis 怎么實現分布式鎖?

    190.redis 分布式鎖有什么缺陷?

    191.redis 如何做內存優化?

    192.redis 淘汰策略有哪些?

    193.redis 常見的性能問題有哪些?該如何解決?

    十九、JVM

    194.說一下 jvm 的主要組成部分?及其作用?

    • 類加載器(Class?Loader):加載類文件到內存。Class loader只管加載,只要符合文件結構就加載,至于能否運行,它不負責,那是有Exectution Engine 負責的。
    • 執行引擎(Execution Engine):也叫解釋器,負責解釋命令,交由操作系統執行。
    • 本地庫接口(Native Interface):本地接口的作用是融合不同的語言為java所用
    • 運行時數據區(Runtime Data Area)

    195.說一下 jvm 運行時數據區?

    • :堆是java對象的存儲區域,任何用new字段分配的java對象實例和數組,都被分配在堆上;jdk1.7以后,運行時常量池從方法區移到了堆上。
    • 方法區:用于存儲已被虛擬機加載的類信息,常量,靜態變量,即時編譯器編譯后的代碼等數據。
    • 虛擬機棧:虛擬機棧中執行每個方法的時候,都會創建一個棧楨用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
    • 本地方法棧:與虛擬機發揮的作用相似,相比于虛擬機棧為Java方法服務,本地方法棧為虛擬機使用的Native方法服務,執行每個本地方法的時候,都會創建一個棧幀用于存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。
    • 程序計數器:指示Java虛擬機下一條需要執行的字節碼指令。

    196.說一下堆棧的區別?

    • 堆存放的是對象的實例和數組。因此該區更關注的是數據的存儲
    • 棧存放:局部變量,操作數棧,返回結果。該區更關注的是程序方法的執行。

    197.java中類加載器的種類

    • 啟動類加載器(Bootstrap ClassLoader):C++實現,它是屬于虛擬機自身的一部分,主要負責加載<JAVA_HOME>\lib目錄
    • 擴展類加載器(Extension ClassLoader):Java實現的,獨立于虛擬機,主要負責加載<JAVA_HOME>\lib\ext目錄中或被java.ext.dirs系統變量所指定的路徑的類庫。
    • 應用程序類加載器(Application ClassLoader):Java實現的,獨立于虛擬機。主要負責加載用戶類路徑(classPath)上的類庫,如果我們沒有實現自定義的類加載器那這玩意就是我們程序中的默認加載器。

    198.什么是雙親委派模型?說一下類加載的執行過程?

    • 雙親委派的意思是如果一個類加載器需要加載類,那么首先它會把這個類請求委派給父類加載器去完成,每一層都是如此。一直遞歸到頂層,當父加載器無法完成這個請求時,子類才會嘗試去加載。這里的雙親其實就指的是父類,沒有mother。父類也不是我們平日所說的那種繼承關系,只是調用邏輯是這樣。

    200.怎么判斷對象是否可以被回收?

    • 引用計數器:實現簡單、判定效率也挺高的。給對象頭中添加一個引用計數器,當有一個地方引用該對象的時候,引用計數器加一;引用失效的時候減一。當引用計數器為零的時候,該對象便不可能在被使用。當下非常火熱的Python就是使用的這個判斷方式。
    • 可達性分析:

    201.java 中都有哪些引用類型?

    • 強引用:?java 默認的引用類型,如果不特意使用?java.lang.ref?下的類,那么程序中的所有引用都是強引用。有強引用存在的對象永遠都不會被 gc 收集,所以在內存不夠用時,JVM 寧愿拋出 OutOfMemoryError 這樣的錯誤,也不愿意將強引用對象進行回收。
    • 軟引用:軟引用不會保證對象一定不會被回收,只能最大可能保證。如果內存有剩余,那么軟引用對象不會被回收,如果內存不足,那么 gc 會回收軟引用對象。所以這種特性可以用來實現緩存技術。軟引用要用 java.lang.ref.SoftReference 來實現。

    • 弱引用:弱引用一定會被 gc 回收,不管內存是否不足。通過 java.lang.ref.WeakReference 來使用弱引用,WeakHashMap 同樣也利用了弱引用。

    • 虛引用:

    202.說一下 jvm 有哪些垃圾回收算法?

    • 標記-清除:直接將標記為垃圾的內存清除,優點是快,缺點是產生內存碎片
    • 復制:將內存分為兩塊,每次將還存活移動到空閑的一塊
    • 標記-整理:標記后將存活對象移向內存的一端。然后清除端邊界外的對象
    • 分代收集:核心思想是根據對象存活的不同生命周期將內存劃分為不同的域,新生代與復制算法、老年代與標記整理算法

    203.說一下 jvm 有哪些垃圾回收器?

    ?收集器解釋
    新生代收集器

    Serial(英文連續)

    ?

    • 單線程、復制算法、垃圾回收時暫停所有工作線程
    • 優缺點:簡單高效,對于限定單個?CPU?環境來說,沒有線程交互的開銷,
    • java?虛擬機運行在?Client?模式下默認的新生代垃圾收集器

    ParNew(Parallel New)

    • 多線程、復制算法、垃圾回收時暫停所有工作線程(除了使用多線程外,其余的行為和Serial收集器完全一樣)
    • 默認開啟和CPU數目相同的線程數,可以通過-XX:ParallelGCThreads參數來限制垃圾收集器的線程數。
    • java虛擬機運行在Server模式下的新生代的默認垃圾收集器。
    Parallel Scavenge
    • 多線程、復制算法、垃圾回收時暫停所有工作線程(與ParNew差不多)
    • 它重點關注的是程序達到一個可控制的吞吐量, 高吞吐量可以最高效率地利用?CPU?時間,盡快地完成程序的運算任務,主要適用于在后臺運算而不需要太多交互的任務。
    • 自適應調節策略也是?ParallelScavenge?收集器與?ParNew?收集器的一個重要區別。
    老年代收集器

    Serial Old

    • 單線程、標記-整理算法
    • java虛擬機運行在?Client?默認的?java?虛擬機默認的年老代垃圾收集器。在?Server?模式下,主要有兩個用途:

    Parallel Old

    • 多線程、標記-整理算法,Parallel Old?收集器是?Parallel Scavenge?的年老代版本
    • 是為了在年老代同樣提供吞吐量優先的垃圾收集器,如果系統對吞吐量要求比較高,可以優先考慮新生代?Parallel Scavenge?和年老代?Parallel Old?收集器的搭配策略。

    最重要:

    CMS(Concurrent Mark Sweep)

    ?

    • 多線程、標記-清除算法,最主要目標是獲取最短垃圾回收停頓時間,
    • 最短的垃圾收集停頓時間可以為交互比較高的程序提高用戶體驗。
    • CMS?工作機制相比其他的垃圾收集器來說更復雜,整個過程分為以下?4?個階段:
  • 初始標記:只標記 GC Roots 能直接關聯的對象,速度很快,仍然需要暫停所有的工作線程。

  • 并發標記:進行 GC Roots 跟蹤的過程,和用戶線程一起工作,不需要暫停工作線程。

  • 重新標記:為了修正在并發標記期間,因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記 記錄,仍然需要暫停所有的工作線程。

  • 并發清除:清除?GC Roots?不可達對象,和用戶線程一起工作,不需要暫停工作線程。

    • 由于耗時最長的并發標記和并發清除過程中,垃圾收集線程可以和用戶現在一起并發工作,所以總體上來看?CMS?收集器的內存回收和用戶線程是一起并發地執行。

    堆內存垃圾收集器G1(Garbage First )
    • 基于標記-整理算法,不產生內存碎片。
    • 可以非常精確控制停頓時間,在不犧牲吞吐量前提下,實現低停頓垃圾回收。
    • G1?收集器避免全區域垃圾收集,它把堆內存劃分為大小固定的幾個獨立區域,并且跟蹤這些區域 的垃圾收集進度,同時在后臺維護一個優先級列表,每次根據所允許的收集時間,優先回收垃圾最多的區域。
    • 區域劃分和優先級區域回收機制,確保?G1?收集器可以在有限時間獲得最高的垃圾收集效率。
    新生代?Serial?與年老代?Serial Old?搭配垃圾收集過程圖: 新生代?Parallel Scavenge/ParNew?與年老代?Serial Old?搭配垃圾收集過程圖:??

    ?

    新生代?Parallel Scavenge?和年老代?Parallel Old?收集器搭配運行過程圖 CMS?收集器工作過程

    204.詳細介紹一下 CMS 垃圾回收器?

    • 參考204題

    205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么區別?

    • 參考204題

    206.簡述分代垃圾回收器是怎么工作的?

    • 參考204題

    207.說一下 jvm 調優的工具?

    208.常用的 jvm 調優的參數都有哪些?

    總結

    以上是生活随笔為你收集整理的面试题—开发篇的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。