Java學習---面試基礎知識點總結


Java中sleep和wait的區別

① 這兩個方法來自不同的類分別是,sleep來自Thread類,和wait來自Object類。

sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程里調用b的sleep方法,實際上還是a去睡覺,要讓b線程睡覺要在b的代碼中調用sleep。

② 鎖: 最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。

sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其他線程可以占用CPU。一般wait不會加時間限制,因為如果wait線程的運行資源不夠,再出來也沒用,要等待其他線程調用notify/notifyAll喚醒等待池中的所有線程,才會進入就緒隊列等待OS分配系統資源。sleep(milliseconds)可以用時間指定使它自動喚醒過來,如果時間不到只能調用interrupt()強行打斷。

Thread.sleep(0)的作用是“觸發操作系統立刻重新進行一次CPU競爭”。

③ 使用范圍:wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,而sleep可以在任何地方使用。

   synchronized(x){ 

      x.notify() 

     //或者wait() 

   }

JAVA中的幾種基本類型,各占用多少字節?

這48個Java技術點,讓你的面試成功率提升5倍!

下圖單位是bit,非字節 1B=8bit

這48個Java技術點,讓你的面試成功率提升5倍!

String能被繼承嗎?為什么?

不可以,因為String類有final修飾符,而final修飾的類是不能被繼承的,實現細節不允許改變。平常我們定義的String str=”a”;其實和String str=new String(“a”)還是有差異的。

前者默認調用的是String.valueOf來返回String實例對象,至於調用哪個則取決於你的賦值,比如String num=1,調用的是

public static String valueOf(int i) {

return Integer.toString(i);

}

后者則是調用如下部分:

public String(String original) {

this.value = original.value;

this.hash = original.hash;

}

最后我們的變量都存儲在一個char數組中

private final char value[];

String, Stringbuffer, StringBuilder 的區別。

String 字符串常量(final修飾,不可被繼承),String是常量,當創建之后即不能更改。(可以通過StringBuffer和StringBuilder創建String對象(常用的兩個字符串操作類)。)

StringBuffer 字符串變量(線程安全),其也是final類別的,不允許被繼承,其中的絕大多數方法都進行了同步處理,包括常用的Append方法也做了同步處理(synchronized修飾)。其自jdk1.0起就已經出現。其toString方法會進行對象緩存,以減少元素復制開銷。

public synchronized String toString() {

if (toStringCache == null) {

toStringCache = Arrays.copyOfRange(value, 0, count);

}

return new String(toStringCache, true);

}

StringBuilder 字符串變量(非線程安全)其自jdk1.5起開始出現。與StringBuffer一樣都繼承和實現了同樣的接口和類,方法除了沒使用synch修飾以外基本一致,不同之處在於最后toString的時候,會直接返回一個新對象。

public String toString() {

// Create a copy, don’t share the array

return new String(value, 0, count);

}

ArrayList 和 LinkedList 有什么區別。

ArrayList和LinkedList都實現了List接口,有以下的不同點:

1、ArrayList是基於索引的數據接口,它的底層是數組。它可以以O(1)時間復雜度對元素進行隨機訪問。與此對應,LinkedList是以元素列表的形式存儲它的數據,每一個元素都和它的前一個和后一個元素鏈接在一起,在這種情況下,查找某個元素的時間復雜度是O(n)。

2、相對於ArrayList,LinkedList的插入,添加,刪除操作速度更快,因為當元素被添加到集合任意位置的時候,不需要像數組那樣重新計算大小或者是更新索引。

3、LinkedList比ArrayList更占內存,因為LinkedList為每一個節點存儲了兩個引用,一個指向前一個元素,一個指向下一個元素。

講講類的實例化順序,

父類靜態代變量--->父類靜態代碼塊--->子類靜態變量--->子類靜態代碼塊---->父類非靜態變量(父類實例成員變量)--->
父類構造函數--->子類非靜態變量(子類實例成員變量)--->子類構造函數。

測試demo:http://blog.csdn.net/u014042066/article/details/77574956

參閱我的博客《深入理解類加載》:http://blog.csdn.net/u014042066/article/details/77394480

用過哪些 Map 類,都有什么區別

hashMap是線程不安全的,HashMap是數組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實現的,采用哈希表來存儲的,

參照該鏈接:https://zhuanlan.zhihu.com/p/21673805

JAVA8 的 ConcurrentHashMap 為什么放棄了分段鎖,有什么問題嗎,如果你來設計,你如何設計。

參照:https://yq.aliyun.com/articles/36781

有沒有有順序的 Map 實現類, 如果有, 他們是怎么保證有序的。

TreeMap和LinkedHashMap是有序的(TreeMap默認升序,LinkedHashMap則記錄了插入順序)。

參照:http://uule.iteye.com/blog/1522291

抽象類和接口的區別,類可以繼承多個類么,接口可以繼承多個接口么,類可以實現多個接口么。

1、抽象類和接口都不能直接實例化,如果要實例化,抽象類變量必須指向實現所有抽象方法的子類對象,接口變量必須指向實現所有接口方法的類對象。

2、抽象類要被子類繼承,接口要被類實現。

3、接口只能做方法申明,抽象類中可以做方法申明,也可以做方法實現

4、接口里定義的變量只能是公共的靜態的常量,抽象類中的變量是普通變量。

5、抽象類里的抽象方法必須全部被子類所實現,如果子類不能全部實現父類抽象方法,那么該子類只能是抽象類。同樣,一個實現接口的時候,如不能全部實現接口方法,那么該類也只能為抽象類。

6、抽象方法只能申明,不能實現。abstract void abc();不能寫成abstract void abc(){}。

7、抽象類里可以沒有抽象方法

8、如果一個類里有抽象方法,那么這個類只能是抽象類

9、抽象方法要被實現,所以不能是靜態的,也不能是私有的。

10、接口可繼承接口,並可多繼承接口,但類只能單根繼承。

繼承和聚合的區別在哪。

繼承指的是一個類(稱為子類、子接口)繼承另外的一個類(稱為父類、父接口)的功能,並可以增加它自己的新功能的能力,繼承是類與類或者接口與接口之間最常見的關系;在Java中此類關系通過關鍵字extends明確標識,在設計時一般沒有爭議性;

這48個Java技術點,讓你的面試成功率提升5倍!

聚合是關聯關系的一種特例,他體現的是整體與部分、擁有的關系,即has-a的關系,此時整體與部分之間是可分離的,他們可以具有各自的生命周期,部分可以屬於多個整體對象,也可以為多個整體對象共享;比如計算機與CPU、公司與員工的關系等;表現在代碼層面,和關聯關系是一致的,只能從語義級別來區分;

這48個Java技術點,讓你的面試成功率提升5倍!

參考:http://www.cnblogs.com/jiqing9006/p/5915023.html

講講你理解的 nio和 bio 的區別是啥,談談 reactor 模型。

IO是面向流的,NIO是面向緩沖區的

參考:https://zhuanlan.zhihu.com/p/23488863

http://developer.51cto.com/art/201103/252367.htm

http://www.jianshu.com/p/3f703d3d804c

反射的原理,反射創建類實例的三種方式是什么

參照:http://www.jianshu.com/p/3ea4a6b57f87?amp

http://blog.csdn.net/yongjian1092/article/details/7364451

反射中,Class.forName 和 ClassLoader 區別。

https://my.oschina.net/gpzhang/blog/486743

描述動態代理的幾種實現方式,分別說出相應的優缺點。

Jdk cglib jdk底層是利用反射機制,需要基於接口方式,這是由於

Proxy.newProxyInstance(target.getClass().getClassLoader(),

target.getClass().getInterfaces(), this);

Cglib則是基於asm框架,實現了無反射機制進行代理,利用空間來換取了時間,代理效率高於jdk

http://lrd.ele.me/2017/01/09/dynamic_proxy/

動態代理與 cglib 實現的區別

同上(基於invocationHandler和methodInterceptor)

為什么 CGlib 方式可以對接口實現代理。

同上

final 的用途

類、變量、方法

http://www.importnew.com/7553.html

寫出三種單例模式實現。

懶漢式單例,餓漢式單例,雙重檢查等

參考:https://my.oschina.net/dyyweb/blog/609021

如何在父類中為子類自動完成所有的 hashcode 和 equals 實現?這么做有何優劣。

同時復寫hashcode和equals方法,優勢可以添加自定義邏輯,且不必調用超類的實現。

參照:http://java-min.iteye.com/blog/1416727

談談訪問修飾符 public、private、protected、default 在應用設計中的作用。

訪問修飾符,主要標示修飾塊的作用域,方便隔離防護

同一個類 同一個包 不同包的子類 不同包的非子類

  • 1
  • 2

Private √

Default √ √

Protected √ √ √

Public √ √ √ √

public: Java語言中訪問限制最寬的修飾符,一般稱之為“公共的”。被其修飾的類、屬性以及方法不

僅可以跨類訪問,而且允許跨包(package)訪問。

private: Java語言中對訪問權限限制的最窄的修飾符,一般稱之為“私有的”。被其修飾的類、屬性以

及方法只能被該類的對象訪問,其子類不能訪問,更不能允許跨包訪問。

protect: 介於public 和 private 之間的一種訪問修飾符,一般稱之為“保護形”。被其修飾的類、

屬性以及方法只能被類本身的方法及子類訪問,即使子類在不同的包中也可以訪問。

default:即不加任何訪問修飾符,通常稱為“默認訪問模式“。該模式下,只允許在同一個包中進行訪

問。

深拷貝和淺拷貝區別。

http://www.oschina.net/translate/java-copy-shallow-vs-deep-in-which-you-will-swim

數組和鏈表數據結構描述,各自的時間復雜度

http://blog.csdn.net/snow_wu/article/details/53172721

error 和 exception 的區別,CheckedException,RuntimeException 的區別

http://blog.csdn.net/woshixuye/article/details/8230407

請列出 5 個運行時異常。

同上

在自己的代碼中,如果創建一個 java.lang.String 對象,這個對象是否可以被類加載器加載?為什么

類加載無須等到“首次使用該類”時加載,jvm允許預加載某些類。。。。

http://www.cnblogs.com/jasonstorm/p/5663864.html

Object 對象中 hashCode 和 equals 方法的理解。在什么場景下需要重新實現這兩個方法。

參考上邊試題

在 jdk1.5 中,引入了泛型,泛型的存在是用來解決什么問題。

泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數,泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,以提高代碼的重用率

http://baike.baidu.com/item/java%E6%B3%9B%E5%9E%8B

這樣的 a.hashcode() 有什么用,與 a.equals(b)有什么關系。

hashcode

hashcode()方法提供了對象的hashCode值,是一個native方法,返回的默認值與System.identityHashCode(obj)一致。

通常這個值是對象頭部的一部分二進制位組成的數字,具有一定的標識對象的意義存在,但絕不定於地址。

作用是:用一個數字來標識對象。比如在HashMap、HashSet等類似的集合類中,如果用某個對象本身作為Key,即要基於這個對象實現Hash的寫入和查找,那么對象本身如何實現這個呢?就是基於hashcode這樣一個數字來完成的,只有數字才能完成計算和對比操作。

hashcode是否唯一

hashcode只能說是標識對象,在hash算法中可以將對象相對離散開,這樣就可以在查找數據的時候根據這個key快速縮小數據的范圍,但hashcode不一定是唯一的,所以hash算法中定位到具體的鏈表后,需要循環鏈表,然后通過equals方法來對比Key是否是一樣的。

equals與hashcode的關系

equals相等兩個對象,則hashcode一定要相等。但是hashcode相等的兩個對象不一定equals相等。

https://segmentfault.com/a/1190000004520827

有沒有可能 2 個不相等的對象有相同的 hashcode。

Java 中的 HashSet 內部是如何工作的。

底層是基於hashmap實現的

http://wiki.jikexueyuan.com/project/java-collection/hashset.html

什么是序列化,怎么序列化,為什么序列化,反序列化會遇到什么問題,如何解決。

http://www.importnew.com/17964.html

Java中HashMap和HashTable的區別

① 歷史原因: Hashtable是給予陳舊的Dictonary類的,  HashMap是Java1.2引進的Map接口的一個實現

② HashMap允許空的鍵值對, 而HashTable不允許

③ HashTable同步,而HashMap非同步,效率上比HashTable要高

Java中synchronized 和 ReentrantLock 有什么不同?

相似點:

這兩種同步方式有很多相似之處,它們都是加鎖方式同步,而且都是阻塞式的同步,也就是說當如果一個線程獲得了對象鎖,進入了同步塊,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待,而進行線程阻塞和喚醒的代價是比較高的(操作系統需要在用戶態與內核態之間來回切換,代價很高,不過可以通過對鎖優化進行改善)。

區別:

這兩種方式最大區別就是對於Synchronized來說,它是java語言的關鍵字,是原生語法層面的互斥,需要jvm實現。而ReentrantLock它是JDK 1.5之后提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally語句塊來完成。

Synchronized進過編譯,會在同步塊的前后分別形成monitorenter和monitorexit這個兩個字節碼指令。在執行monitorenter指令時,首先要嘗試獲取對象鎖。如果這個對象沒被鎖定,或者當前線程已經擁有了那個對象鎖,把鎖的計算器加1,相應的,在執行monitorexit指令時會將鎖計算器就減1,當計算器為0時,鎖就被釋放了。如果獲取對象鎖失敗,那當前線程就要阻塞,直到對象鎖被另一個線程釋放為止。

由於ReentrantLock是java.util.concurrent包下提供的一套互斥鎖,相比Synchronized,ReentrantLock類提供了一些高級功能,主要有以下3項:

1.等待可中斷,持有鎖的線程長期不釋放的時候,正在等待的線程可以選擇放棄等待,這相當於Synchronized來說可以避免出現死鎖的情況。

2.公平鎖,多個線程等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock默認的構造函數是創建的非公平鎖,可以通過參數true設為公平鎖,但公平鎖表現的性能不是很好。

3.鎖綁定多個條件,一個ReentrantLock對象可以同時綁定對個對象。

什么情況下會發生棧內存溢出。

如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常。 如果虛擬機在動態擴展棧時無法申請到足夠的內存空間,則拋出OutOfMemoryError異常。

參照:http://wiki.jikexueyuan.com/project/java-vm/storage.html

JVM 的內存結構,Eden 和 Survivor 比例。

這48個Java技術點,讓你的面試成功率提升5倍!

eden 和 survior 是按8比1分配的

http://blog.csdn.net/lojze_ly/article/details/49456255

jvm 中一次完整的 GC 流程是怎樣的,對象如何晉升到老年代,說說你知道的幾種主要的jvm 參數。

對象誕生即新生代->eden,在進行minor gc過程中,如果依舊存活,移動到from,變成Survivor,進行標記代數,如此檢查一定次數后,晉升為老年代,

http://www.cnblogs.com/redcreen/archive/2011/05/04/2037056.html

http://ifeve.com/useful-jvm-flags/

https://wangkang007.gitbooks.io/jvm/content/jvmcan_shu_xiang_jie.html

你知道哪幾種垃圾收集器,各自的優缺點,重點講下 cms,包括原理,流程,優缺點

Serial、parNew、ParallelScavenge、SerialOld、ParallelOld、CMS、G1

https://wangkang007.gitbooks.io/jvm/content/chapter1.html

垃圾回收算法的實現原理。

http://www.importnew.com/13493.html

當出現了內存溢出,你怎么排錯。

首先分析是什么類型的內存溢出,對應的調整參數或者優化代碼。

https://wangkang007.gitbooks.io/jvm/content/4jvmdiao_you.html

JVM 內存模型的相關知識了解多少,比如重排序,內存屏障,happen-before,主內存,工作內存等。

內存屏障:為了保障執行順序和可見性的一條cpu指令

重排序:為了提高性能,編譯器和處理器會對執行進行重拍

happen-before:操作間執行的順序關系。有些操作先發生。

主內存:共享變量存儲的區域即是主內存

工作內存:每個線程copy的本地內存,存儲了該線程以讀/寫共享變量的副本

http://ifeve.com/java-memory-model-1/

http://www.jianshu.com/p/d3fda02d4cae

http://blog.csdn.net/kenzyq/article/details/50918457

簡單說說你了解的類加載器。

類加載器的分類(bootstrap,ext,app,curstom),類加載的流程(load-link-init)

http://blog.csdn.net/gjanyanlig/article/details/6818655/

講講 JAVA 的反射機制。

Java程序在運行狀態可以動態的獲取類的所有屬性和方法,並實例化該類,調用方法的功能

http://baike.baidu.com/link?url=C7p1PeLa3ploAgkfAOK-4XHE8HzQuOAB7K5GPcK_zpbAa_Aw-nO3997K1oir8N–1_wxXZfOThFrEcA0LjVP6wNOwidVTkLBzKlQVK6JvXYvVNhDWV9yF-NIOebtg1hwsnagsjUhOE2wxmiup20RRa#7

你們線上應用的 JVM 參數有哪些。

-server
Xms6000M
-Xmx6000M
-Xmn500M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-XX:SurvivorRatio=65536
-XX:MaxTenuringThreshold=0
-Xnoclassgc
-XX:+DisableExplicitGC
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:-CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=90
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
 

g1 和 cms 區別,吞吐量優先和響應優先的垃圾收集器選擇。

Cms是以獲取最短回收停頓時間為目標的收集器。基於標記-清除算法實現。比較占用cpu資源,切易造成碎片。

G1是面向服務端的垃圾收集器,是jdk9默認的收集器,基於標記-整理算法實現。可利用多核、多cpu,保留分代,實現可預測停頓,可控。

http://blog.csdn.net/linhu007/article/details/48897597

請解釋如下 jvm 參數的含義:

-server -Xms512m -Xmx512m -Xss1024K

-XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxTenuringThreshold=20

XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly。

Server模式啟動

最小堆內存512m

最大512m

每個線程棧空間1m

永久代256

最大永久代256

最大轉為老年代檢查次數20

Cms回收開啟時機:內存占用80%

命令JVM不基於運行時收集的數據來啟動CMS垃圾收集周期

開源框架知識

簡單講講 tomcat 結構,以及其類加載器流程。

Server- –多個service

Container級別的:–>engine–》host–>context

Listenter

Connector

Logging、Naming、Session、JMX等等

這48個Java技術點,讓你的面試成功率提升5倍!

通過WebappClassLoader 加載class

http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/

http://blog.csdn.net/dc_726/article/details/11873343

http://www.cnblogs.com/xing901022/p/4574961.html

http://www.jianshu.com/p/62ec977996df

tomcat 如何調優,涉及哪些參數。

硬件上選擇,操作系統選擇,版本選擇,jdk選擇,配置jvm參數,配置connector的線程數量,開啟gzip壓縮,trimSpaces,集群等

http://blog.csdn.net/lifetragedy/article/details/7708724

講講 Spring 加載流程。

通過listener入口,核心是在AbstractApplicationContext的refresh方法,在此處進行裝載bean工廠,bean,創建bean實例,攔截器,后置處理器等。

https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/

講講 Spring 事務的傳播屬性。

七種傳播屬性。

事務傳播行為

所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在TransactionDefinition定義中包括了如下幾個表示傳播行為的常量:

TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。

TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。

TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。

TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。

TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。

TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。

TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。

https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/

Spring 如何管理事務的。

編程式和聲明式

同上

Spring 怎么配置事務(具體說出一些關鍵的 xml 元素)。

說說你對 Spring 的理解,非單例注入的原理?它的生命周期?循環注入的原理, aop 的實現原理,說說 aop 中的幾個術語,它們是怎么相互工作的。

核心組件:bean,context,core,單例注入是通過單例beanFactory進行創建,生命周期是在創建的時候通過接口實現開啟,循環注入是通過后置處理器,aop其實就是通過反射進行動態代理,pointcut,advice等。

Aop相關:http://blog.csdn.net/csh624366188/article/details/7651702/

Springmvc 中 DispatcherServlet 初始化過程。

入口是web.xml中配置的ds,ds繼承了HttpServletBean,FrameworkServlet,通過其中的init方法進行初始化裝載bean和實例,initServletBean是實際完成上下文工作和bean初始化的方法。

http://www.mamicode.com/info-detail-512105.html

Java運行時內存是如何划分的

Java虛擬機在執行Java程序的時候會把他所管理的內存划分為若干個不同的數據區域,各個區域有各自的用途,以及創建和銷毀的時間。有的區域隨着虛擬機進程的啟動而存在,有的區域則依賴用戶線程的啟動和結束而創建和銷毀。

Java虛擬機會把運行時的數據區域分為以下幾個區域:

Java運行時內存是如何划分的

程序計數器:

程序計數器是一塊很小的內存空間,代表着當前線程執行的字節碼的行號指示器,記錄着所執行的行號,java虛擬機執行的是由后綴名為.java的文件編譯而來的.class文件(字節碼文件),所以字節碼解釋器根據程序計數器來執行字節碼文件。每個線程都有自己的程序解釋器,這樣才能保證程序的正確執行,也就是說程序計數器是線程私有的。

Java虛擬機棧:

java虛擬機棧是用來描述java方法的內存模型,每個方法在執行的同時都會創建一個棧幀,而這個棧幀存儲的是方法中的局部變量,操作的數據,方法的入口返回值等信息,當一個方法被調用的時候,就代表着棧幀的入棧直至方法的結束代表着棧幀的出棧。因為虛擬機棧存儲的數據決定了他也是線程私有的,每個線程都擁有一個虛擬機棧記錄着方法的內容。我們平時所說的棧就是指的是虛擬機棧,其中存儲着基本數據類型和指向堆內存中對象的指針(對象的引用)。

本地方法棧:

這塊區域和虛擬機棧執行的操作其實是一致的,但是他們之間的服務對象不一樣,虛擬機棧為java方法服務,而本地方法棧為native方法服務,我們在看源碼的時候經常了一看到用native關鍵字修飾的方法,這種方法的實現是用c/c++實現的,我們在平時是看不到他的源碼實現的。

Java堆:

堆內存是這幾塊內存區域中最大的一塊,堆內存存在的目的是存放對象的實例(通過new創建的對象,對象的引用放在虛擬機棧中指向堆中的實例),在虛擬機啟動的時候堆內存也就被創建了,這塊內存被所有線程共享,在虛擬機運行期間的所有線程創建的對象的實例都被存儲在堆內存中。既然堆被線程所共享,那么線程創建的對象不能一直存放在這里,總會有裝不下的時候,在一定條件下,java虛擬機會觸發垃圾回收機制(GC),來回收這里被看作沒有用的對象,虛擬機所管理的垃圾回收器總是會對這塊區域進行管理操作。關於垃圾回收(GC)機制可以看另一篇文章:Java GC垃圾回收機制

方法區:

方法區和堆內存一樣,是各個線程共享的數據區域,看到這個方法區這個名字很快能想到這個區域存方法信息,事實上方法區存放的數據很多,包括被虛擬機加載的類信息,用final修飾的常量,String對象,用static修飾的靜態變量。

運行時常量池:

准確的說這塊區域屬於方法區,也就受到了方法區的空間限制,之前所說的String對象,就是字符串常量就是存放在這里,編譯期生成各種字面值和符號引用,將在類價在后放入方法區的運行時常量池的。運行時常量池的存儲具有動態性,並不是在類加載時才能放入數據,在程序運行期間也可以有新的常量放入。String類中的intern()方法就是這種特點,詳看之前轉載的一篇文章:String的intern()方法詳解

直接內存:

這塊區域和java中的新的io方式(NIO)有關,不屬於虛擬機的運行時數據區。NIO是一種基於通道,緩沖區的io方式。

XSS,CSRF,SQL注入

XSS是一種經常出現在web應用中的計算機安全漏洞,它允許惡意web用戶將代碼植入到提供給其它用戶使用的頁面中。比如這些代碼包括HTML代碼和客戶端腳本。攻擊者利用XSS漏洞旁路掉訪問控制——例如同源策略(same origin policy)。這種類型的漏洞由於被黑客用來編寫危害性更大的網絡釣魚(Phishing)攻擊而變得廣為人知。對於跨站腳本攻擊,黑客界共識是:跨站腳本攻擊是新型的“緩沖區溢出攻擊“,而JavaScript是新型的“ShellCode”。

CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用。盡管聽起來像跨站腳本(XSS),但它與XSS非常不同,XSS利用站點內的信任用戶,而CSRF則通過偽裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防范的資源也相當稀少)和難以防范,所以被認為比XSS更具危險性。

SQL注入,就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。具體來說,它是利用現有應用程序,將(惡意的)SQL命令注入到后台數據庫引擎執行的能力,它可以通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的網站上的數據庫,而不是按照設計者意圖去執行SQL語句。 [1] 比如先前的很多影視網站泄露VIP會員密碼大多就是通過WEB表單遞交查詢字符暴出的,這類表單特別容易受到SQL注入式攻擊

java中有幾種方法可以實現一個線程?用什么關鍵字修飾同步方法? stop()和suspend()方法為何不推薦?

有兩種實現方法,分別是繼承Thread類實現Runnable接口用synchronized關鍵字修飾同步方法反對使用stop(),是因為它不安全。它會解除由線程獲取的所有鎖定,而且如果對象處於一種不連貫狀態,那么其他線程能在那種狀態下檢查和修改它們。結果很難檢查出真正的問題所在。suspend()方法容易發生死鎖。調用suspend()的時候,目標線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被“掛起”的線程恢復運行。

對任何線程來說,如果它們想恢復目標線程,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。所以不應該使用suspend(),而應在自己的Thread類中置入一個標志,指出線程應該活動還是掛起。若標志指出線程應該掛起,便用wait()命其進入等待狀態。若標志指出線程應當恢復,則用一個notify()重新啟動線程。

請簡述在異常當中,throw和throws有什么區別

① throw代表動作,表示拋出一個異常的動作;throws代表一種狀態,代表方法可能有異常拋出
② throw用在方法實現中,而throws用在方法聲明中
③ throw只能用於拋出一種異常,而throws可以拋出多個異常

forward和redirect的區別

forward:    A -> B -> C
redirect:   A -> B A -> C
1.從地址欄顯示來說 
	forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然后把這些內容再發給瀏覽器.瀏覽器根本不知道服務器發送的內容從哪里來的,所以它的地址欄還是原來的地址.
	redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.
2.從數據共享來說 
	forward:轉發頁面和轉發到的頁面可以共享request里面的數據.
	redirect:不能共享數據.
3.從運用地方來說 
	forward:一般用於用戶登陸的時候,根據角色轉發到相應的模塊.
	redirect:一般用於用戶注銷登陸時返回主頁面和跳轉到其它的網站等.
4.從效率來說 
	forward:高.
	redirect:低. 

關於內存溢出的小結

內存溢出 out of memory,是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。
內存泄露 memory leak,是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存,遲早會被占光。
memory leak會最終會導致out of memory!內存泄漏是指你向系統申請分配內存進行使用(new),可是使用完了以后卻不歸還(delete),結果你申請到的那塊內存你自己也不能再訪問(也許你把它的地址給弄丟了),而系統也不能再次將它分配給需要的程序。

java為什么要重寫hashCode和equals方法?

如果不被重寫(原生)的hashCode和equals是什么樣的?

  1. 不被重寫(原生)的hashCode值是根據內存地址換算出來的一個值。
  2. 不被重寫(原生)的equals方法是嚴格判斷一個對象是否相等的方法(object1 == object2)。

為什么需要重寫equals和hashCode方法?

在我們的業務系統中判斷對象時有時候需要的不是一種嚴格意義上的相等,而是一種業務上的對象相等。在這種情況下,原生的equals方法就不能滿足我們的需求了

所以這個時候我們需要重寫equals方法,來滿足我們的業務系統上的需求。那么為什么在重寫equals方法的時候需要重寫hashCode方法呢?

我們先來看一下Object.hashCode的通用約定(摘自《Effective Java》第45頁)

1.在一個應用程序執行期間,如果一個對象的equals方法做比較所用到的信息沒有被修改的話,那么,對該對象調用hashCode方法多次,它必須始終如一地返回 同一個整數。在同一個應用程序的多次執行過程中,這個整數可以不同,即這個應用程序這次執行返回的整數與下一次執行返回的整數可以不一致。

2.如果兩個對象根據equals(Object)方法是相等的,那么調用這兩個對象中任一個對象的hashCode方法必須產生同樣的整數結果。

3.如果兩個對象根據equals(Object)方法是不相等的,那么調用這兩個對象中任一個對象的hashCode方法,不要求必須產生不同的整數結果。然而,程序員應該意識到這樣的事實,對於不相等的對象產生截然不同的整數結果,有可能提高散列表(hash table)的性能。

如果只重寫了equals方法而沒有重寫hashCode方法的話,則會違反約定的第二條:相等的對象必須具有相等的散列碼(hashCode)

同時對於HashSet和HashMap這些基於散列值(hash)實現的類。HashMap的底層處理機制是以數組的方法保存放入的數據的(Node<K,V>[] table),其中的關鍵是數組下標的處理。數組的下標是根據傳入的元素hashCode方法的返回值再和特定的值異或決定的。

如果該數組位置上已經有放入的值了,且傳入的鍵值相等則不處理,若不相等則覆蓋原來的值,如果數組位置沒有條目,則插入,並加入到相應的鏈表中。檢查鍵是否存在也是根據hashCode值來確定的。所以如果不重寫hashCode的話,可能導致HashSet、HashMap不能正常的運作、

如果我們將某個自定義對象存到HashMap或者HashSet及其類似實現類中的時候,如果該對象的屬性參與了hashCode的計算,那么就不能修改該對象參數hashCode計算的屬性了。有可能會移除不了元素,導致內存泄漏。

擴展:

在重寫equals方法的時候,需要遵守下面的通用約定:

1、自反性。

對於任意的引用值x,x.equals(x)一定為true。

2、對稱性。

對於任意的引用值x和y,當且僅當y.equals(x)返回true時,x.equals(y)也一定返回true。

3、傳遞性。

對於任意的引用值x、y和z,如果x.equals(y)返回true,並且y.equals(z)也返回true,那么x.equals(z)也一定返回true。

4、一致性。

對於任意的引用值x和y,如果用於equals比較的對象沒有被修改的話,那么,對此調用x.equals(y)要么一致地返回true,要么一致的返回false。

5、對於任意的非空引用值x,x.equals(null)一定返回false。

重寫hashCode方法的大致方式:

a、把某個非零常數值,比如說17(最好是素數),保存在一個叫result的int類型的變量中。

b、對於對象中每一個關鍵域f(值equals方法中考慮的每一個域),完成一些步驟:

1、為該域計算int類型的散列嗎c:

1)、如果該域是boolean類型,則計算(f?0:1)。

2)、如果該域是byte、char、short或者int類型,則計算(int)f。

3)、如果該域是float類型,則計算Float.floatToIntBits(f)。

4)、如果該域是long類型,則計算(int)(f ^ (f>>>32))。

5)、如果該域是double類型,則計算Double.doubleToLongBits(f)得到一個long類型的值,然后按照步驟4,對該long型值計算散列值。

6)、如果該域是一個對象引用,並且該類的equals方法通過遞歸調用equals的方式來比較這個域,則同樣對這個域遞歸調用hashCode。如果要求一個更為復雜的比較,則為這個域計算一個“規范表示”,然后針對這個范式表示調用hashCode。如果這個域的值為null,則返回0(或者其他某個常數)

7)、如果該域是一個數組,則把每一個元素當做單獨的域來處理。也就是說,遞歸地應用上述規則,對每個重要的元素計算一個散列碼,然后根據步驟下面的做法把這些散列值組合起來。

2、按照下面的公式,把步驟1中計算得到的散列碼C組合到result中:

result = 31*result+c。

c、返回result。

d、寫完hashCode方法之后,問自己“是否相等的實例具有相等的散列碼”。如果不是的話,找出原因,並修改。

可以通過org.apache.commons.lang.builder.HashCodeBuilder這個工具類來方便的重寫hashCode方法。

關於枚舉的小結

枚舉類型的那些事:https://www.cnblogs.com/hyl8218/p/5088287.html

枚舉類型符合通用模式 Class Enum<E extends Enum<E>>,而 E 表示枚舉類型的名稱。枚舉類型的每一個值都將映射到 protected Enum(String name, int ordinal) 構造函數中,在這里,每個值的名稱都被轉換成一個字符串,並且序數設置表示了此設置被創建的順序。

image

HTTP返回碼分析

301:- 永久移動。請求的資源已被永久的移動到新URI,返回信息會包括新的URI,瀏覽器會自動定向到新URI。今后任何新的請求都應使用新的URI代替
302:- 臨時移動。與301類似。但資源只是臨時被移動。客戶端應繼續使用原有URI

304:- 如果客戶端發送了一個帶條件的GET 請求且該請求已被允許,而文檔的內容(自上次訪問以來或者根據請求的條件)並沒有改變,則服務器應當返回這個304狀態碼..
403:- 代表客戶端錯誤,指的是服務器端有能力處理該請求,但是拒絕授權訪問。
404:- 服務器無法根據客戶端的請求找到資源(網頁)。通過此代碼,網站設計人員可設置"您所請求的資源無法找到"的個性頁面
500:- 服務器內部錯誤,無法完成請求

Java程序中啟動一個線程是用run()還是start()?

1.start()方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼:
通過調用Thread類的start()方法來啟動一個線程,這時此線程是處於就緒狀態,並沒有運行。
然后通過此Thread類調用方法run()來完成其運行操作的,這里方法run()稱為線程體,它包含了要執行的這個線程的內容,
Run方法運行結束,此線程終止,而CPU再運行其它線程。
2.run()方法當作普通方法的方式調用,程序還是要順序執行,還是要等待run方法體執行完畢后才可繼續執行下面的代碼:
而如果直接用Run方法,這只是調用一個方法而已,程序中依然只有主線程--這一個線程,其程序執行路徑還是只有一條,
這樣就沒有達到寫線程的目的。

Thread和Runnable的區別

如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable接口的話,則很容易的實現資源共享。
實現Runnable接口比繼承Thread類所具有的優勢:
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。
提醒一下大家:main方法其實也是一個線程。在java中所以的線程都是同時啟動的,至於什么時候,哪個先執行,完全看誰先得到CPU的資源。在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用java命令執行一個類的時候,實際上都會啟動一個JVM,每一個JVM實際就是在操作系統中啟動了一個進程。
在java程序中,只要前台有一個線程在運行,整個java程序進程不會小時,所以此時可以設置一個后台線程,這樣即使java進程小時了,此后台線程依然能夠繼續運行。

線程狀態說明

線程狀態從大的方面來說,可歸結為:初始狀態、可運行狀態、不可運行狀態和消亡狀態,具體可細分為上圖所示7個狀態,說明如下:
1)線程的實現有兩種方式,一是繼承Thread類,二是實現Runnable接口,但不管怎樣,當我們new了thread實例后,線程就進入了初始狀態;
2)當該對象調用了start()方法,就進入可運行狀態;
3)進入可運行狀態后,當該對象被操作系統選中,獲得CPU時間片就會進入運行狀態;
4)進入運行狀態后case就比較多,大致有如下情形: ﹒run()方法或main()方法結束后,線程就進入終止狀態; 當線程調用了自身的sleep()方法或其他線程的join()方法,就會進入阻塞狀態(該狀態既停 止當前線程,但並不釋放所占有的資源)。當
sleep()結束或join()結束后,該線程進入可運行狀態,繼續等待OS分配時間片; 當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被鎖牢(synchroniza,lock),將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池里也許已經有了其他線
程在等待獲取鎖標記,這時它們處於隊列狀態,既先到先得),一旦線程獲得鎖標記后,就轉入可運行狀態,等待OS分配 CPU時間片; 當線程調用wait()方法后會進入等待隊列(進入這個狀態會釋放所占有的所有資源,與阻塞狀態不同),進入這個狀態后,
是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒(由於notify()只是喚醒一個線程,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒
有所線程),線程被喚醒后會進入鎖池,等待獲取鎖標記。 當線程調用stop方法,即可使線程進入消亡狀態,但是由於stop方法是不安全的,不鼓勵使用,大家可以通過run方法里的條件變通實現線程的 stop。

Java中的原始數據類型都有哪些,它們的大小及對應的封裝類是什么?

  • byte——1 byte——Byte
  • short——2 bytes——Short
  • int——4 bytes——Integer
  • long——8 bytes——Long
  • float——4 bytes——Float
  • double——8 bytes——Double
  • char——2 bytes——Character
  • boolean——————Boolean

boolean數據類型非true即false。

這個數據類型表示1 bit,但是它的大小並沒有精確定義。

《Java虛擬機規范》中如是說:“雖然定義了boolean這種數據類型,但是只對它提供了非常有限的支持。在Java虛擬機中沒有任何供boolean值專用的字節碼指令,Java語言表達式所操作的boolean值,在編譯之后都使用Java虛擬機中的int數據類型來代替,而boolean數組將會被編碼成Java虛擬機的byte數組,每個元素boolean元素占8位”。這樣我們可以得出boolean類型單獨使用是4個字節,在數組中又是1個字節。

那虛擬機為什么要用int來代替boolean呢?為什么不用byte或short,這樣不是更節省內存空間嗎?

實際上,使用int的原因是,對於當下32位的CPU來說,一次進行32位的數據交換更加高效。

綜上,我們可以知道:官方文檔對boolean類型沒有給出精確的定義,《Java虛擬機規范》給出了“單獨時使用4個字節,boolean數組時1個字節”的定義,具體還要看虛擬機實現是否按照規范來,所以1個字節、4個字節都是有可能的。這其實是一種時空權衡。 boolean類型的封裝類是Boolean。

位運算符的基本用法

案例演示 >>,>>>,<<的用法:

<<:左移左邊最高位丟棄,右邊補齊0

這些java基礎,你不能忘

>>:右移最高位是0,左邊補齊0;最高為是1,左邊補齊1

這些java基礎,你不能忘

>>>:無符號右移 無論最高位是0還是1,左邊補齊0

最有效率的算出2 * 8的結果

//最有效率的算出2 * 8的結果

System.out.println(2 << 3);

談一談”==“與”equals()"的區別。

《Think in Java》中說:“關系操作符生成的是一個boolean結果,它們計算的是操作數的值之間的關系”。 "=="判斷的是兩個對象的內存地址是否一樣,適用於原始數據類型和枚舉類型(它們的變量存儲的是值本身,而引用類型變量存儲的是引用);equals是Object類的方法,Object對它的實現是比較內存地址,我們可以重寫這個方法來自定義“相等”這個概念。比如類庫中的String、Date等類就對這個方法進行了重寫。 綜上,對於枚舉類型和原始數據類型的相等性比較,應該使用"==";對於引用類型的相等性比較,應該使用equals方法。

Java中的四種引用及其應用場景是什么?

  • 強引用: 通常我們使用new操作符創建一個對象時所返回的引用即為強引用
  • 軟引用: 若一個對象只能通過軟引用到達,那么這個對象在內存不足時會被回收,可用於圖片緩存中,內存不足時系統會自動回收不再使用的Bitmap
  • 弱引用: 若一個對象只能通過弱引用到達,那么它就會被回收(即使內存充足),同樣可用於圖片緩存中,這時候只要Bitmap不再使用就會被回收
  • 虛引用: 虛引用是Java中最“弱”的引用,通過它甚至無法獲取被引用的對象,它存在的唯一作用就是當它指向的對象回收時,它本身會被加入到引用隊列中,這樣我們可以知道它指向的對象何時被銷毀。

object中定義了哪些方法?

  • clone()
  • equals()
  • hashCode()
  • toString()
  • notify()
  • notifyAll()
  • wait()
  • finalize()
  • getClass()

hashCode的作用是什么?

請參考散列表的基本原理與實現

ArrayList, LinkedList, Vector的區別是什么?

  • ArrayList:內部采用數組存儲元素,支持高效隨機訪問,支持動態調整大小
  • LinkedList:內部采用鏈表來存儲元素,支持快速插入/刪除元素,但不支持高效地隨機訪問
  • Vector: 可以看作線程安全版的ArrayList

String, StringBuilder, StringBuffer的區別是什么?

  • String: 不可變的字符序列,若要向其中添加新字符需要創建一個新的String對象
  • StringBuilder: 可變字符序列,支持向其中添加新字符(無需創建新對象)
  • StringBuffer: 可以看作線程安全版的StringBuilder

Map, Set, List, Queue、Stack的特點及用法。

  • Map<k, v="">:Java中存儲鍵值對的數據類型都實現了這個接口,表示“映射表”。支持的兩個核心操作是get(Object key)以及put(K key, V value),分別用來獲取鍵對應的值以及向映射表中插入鍵值對。</k,>
  • Set<e>:實現了這個接口的集合類型中不允許存在重復的元素,代表數學意義上的“集合”。它所支持的核心操作有add(E e), remove(Object o), contains(Object o),分別用於添加元素,刪除元素以及判斷給定元素是否存在於集中。
  • List<e>: Java中集合框架中的列表類型都實現了這個接口,表示一種有序序列。支持get(int index), add(E e)等操作。
  • Queue<e>:Java集合框架中的隊列接口,代表了“先進先出”隊列。支持add(E element),remove()等操作。
  • Stack<e>:Java集合框架中表示堆棧的數據類型,堆棧是一種“后進先出”的數據結構。支持push(E item), pop()等操作。

更詳細的說明請參考官方文檔,對相關數據結構不太熟悉的同學可以參考《算法導論》或其他相關書籍。

HashMap和HashTable的區別

  • HashTable是線程安全的,而HashMap不是
  • HashMap中允許存在null鍵和null值,而HashTable中不允許

HashMap的實現原理

簡單的說,HashMap的底層實現是“基於拉鏈法的散列表”。

詳細分析請參考 Map源碼解析之HashMap源碼分析

ConcurrentHashMap的實現原理

ConcurrentHashMap是支持並發讀寫的HashMap,它的特點是讀取數據時無需加鎖,寫數據時可以保證加鎖粒度盡可能的小。由於其內部采用“分段存儲”,只需對要進行寫操作的數據所在的“段”進行加鎖。關於ConcurrentHashMap底層實現的詳細分析請參考 Java並發編程:並發容器之ConcurrentHashMap

TreeMap, LinkedHashMap, HashMap的區別是什么?

  • HashMap的底層實現是散列表,因此它內部存儲的元素是無序的;
  • TreeMap的底層實現是紅黑樹,所以它內部的元素的有序的。排序的依據是自然序或者是創建TreeMap時所提供的比較器(Comparator)對象。
  • LinkedHashMap可以看作能夠記住插入元素的順序的HashMap。

Collection與Collections的區別是什么?

  • Collection<e>是Java集合框架中的基本接口;
  • Collections是Java集合框架提供的一個工具類,其中包含了大量用於操作或返回集合的靜態方法。

對於“try-catch-finally”,若try語句塊中包含“return”語句,finally語句塊會執行嗎?

會執行。只有兩種情況finally塊中的語句不會被執行:

  • 調用了System.exit()方法;
  • JVM“崩潰”了。

Java中的異常層次結構

Java中的異常層次結構如下圖所示:

JAVA面試核心教程|Java面試基礎知識點總結

我們可以看到Throwable類是異常層級中的基類。

Error類表示內部錯誤,這類錯誤使我們無法控制的;Exception表示異常,RuntimeException及其子類屬於未檢查異常,這類異常包括ArrayIndexOutOfBoundsException、NullPointerException等,我們應該通過條件判斷等方式語句避免未檢查異常的發生。IOException及其子類屬於已檢查異常,編譯器會檢查我們是否為所有可能拋出的已檢查異常提供了異常處理器,若沒有則會報錯。對於未檢查異常,我們無需捕獲(當然Java也允許我們捕獲,但我們應該做的事避免未檢查異常的發生)。

Java面向對象的三個特征與含義

三大特征:封裝、繼承、多態。

Override, Overload的含義與區別

  • Override表示“重寫”,是子類對父類中同一方法的重新定義
  • Overload表示“重載”,也就是定義一個與已定義方法名稱相同但簽名不同的新方法

接口與抽象類的區別

  • 接口是一種約定,實現接口的類要遵循這個約定;
  • 抽象類本質上是一個類,使用抽象類的代價要比接口大。
  • 接口與抽象類的對比如下:

抽象類中可以包含屬性,方法(包含抽象方法與有着具體實現的方法),常量;接口只能包含常量和方法聲明。

抽象類中的方法和成員變量可以定義可見性(比如 public、private等);而接口中的方法只能為public(缺省為public)。

一個子類只能有一個父類(具體類或抽象類);而一個接口可以繼承一個多個接口,一個類也可以實現多個接口。

子類中實現父類中的抽象方法時,可見性可以大於等於父類中的;而接口實現類中的接口 方法的可見性只能與接口中相同(public)。

靜態內部類與非靜態內部類的區別

靜態內部類不會持有外圍類的引用,而非靜態內部類會隱式持有外圍類的一個引用。

Java中多態的實現原理

所謂多態,指的就是父類引用指向子類對象,調用方法時會調用子類的實現而不是父類的實現。多態的實現的關鍵在於“動態綁定”。詳細介紹請戳 Java動態綁定的內部實現機制

簡述Java中創建新線程的兩種方法

  • 繼承Thread類(假設子類為MyThread),並重寫run()方法,然后new一個MyThread對象並對其調用start()即可啟動新線程。
  • 實現Runnable接口(假設實現類為MyRunnable),而后將MyRunnable對象作為參數傳入Thread構造器,在得到的Thread對象上調用start()方法即可。

簡述Java中進行線程同步的方法

  • volatile: Java Memory Model保證了對同一個volatile變量的寫happens before對它的讀;
  • synchronized:可以來對一個代碼塊或是對一個方法上鎖,被“鎖住”的地方稱為臨界區,進入臨界區的線程會獲取對象的monitor,這樣其他嘗試進入臨界區的線程會因無法獲取monitor而被阻塞。由於等待另一個線程釋放monitor而被阻塞的線程無法被中斷。
  • ReentrantLock: 嘗試獲取鎖的線程可以被中斷並可以設置超時參數。

簡述Java中具有哪幾種粒度的鎖

Java中可以對類、對象、方法或是代碼塊上鎖。

給出“生產者-消費者”問題的一種解決方案

使用阻塞隊列:

public class BlockingQueueTest { private int size = 20; private ArrayBlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(size); public static void main(String[] args) { BlockingQueueTest test = new BlockingQueueTest(); Producer producer = test.new Producer(); Consumer consumer = test.new Consumer(); producer.start(); consumer.start(); } class Consumer extends Thread{ @Override public void run() { while(true){ try { //從阻塞隊列中取出一個元素 queue.take(); System.out.println("隊列剩余" + queue.size() + "個元素"); } catch (InterruptedException e) { } } } } class Producer extends Thread{ @Override public void run() { while (true) { try { //向阻塞隊列中插入一個元素 queue.put(1); System.out.println("隊列剩余空間:" + (size - queue.size())); } catch (InterruptedException e) { } } } } }

ThreadLocal的設計理念與作用

ThreadLocal的作用是提供線程內的局部變量,在多線程環境下訪問時能保證各個線程內的ThreadLocal變量各自獨立。也就是說,每個線程的ThreadLocal變量是自己專用的,其他線程是訪問不到的。ThreadLocal最常用於以下這個場景:多線程環境下存在對非線程安全對象的並發訪問,而且該對象不需要在線程間共享,但是我們不想加鎖,這時候可以使用ThreadLocal來使得每個線程都持有一個該對象的副本。

concurrent包的整體架構

JAVA面試核心教程|Java面試基礎知識點總結

ArrayBlockingQueue, CountDownLatch類的作用

  • CountDownLatch:允許線程集等待直到計數器為0。適用場景: 當一個或多個線程需要等待指定數目的事件發生后再繼續執行。
  • ArrayBlockingQueue: 一個基於數組實現的阻塞隊列,它在構造時需要指定容量。當試圖向滿隊列中添加元素或者從空隊列中移除元素時,當前線程會被阻塞。通過阻塞隊列,我們可以按以下模式來工作:工作者線程可以周期性的將中間結果放入阻塞隊列中,其它線程可以取出中間結果並進行進一步操作。若工作者線程的執行比較慢(還沒來得及向隊列中插入元素),其他從隊列中取元素的線程會等待它(試圖從空隊列中取元素從而阻塞);若工作者線程執行較快(試圖向滿隊列中插入元素),則它會等待其它線程取出元素再繼續執行。

wait(),sleep() 的區別

  • wait():Object類中定義的實例方法。在指定對象上調用wait方法會讓當前線程進入等待狀態(前提是當前線程持有該對象的monitor),此時當前線程會釋放相應對象的monitor,這樣一來其它線程便有機會獲取這個對象的monitor了。當其它線程獲取了這個對象的monitor並進行了所需操作時,便可以調用notify方法喚醒之前進入等待狀態的線程。
  • sleep():Thread類中的靜態方法,作用是讓當前線程進入休眠狀態,以便讓其他線程有機會執行。進入休眠狀態的線程不會釋放它所持有的鎖。

線程池的用法與優勢

  • 優勢: 實現對線程的復用,避免了反復創建及銷毀線程的開銷;使用線程池統一管理線程可以減少並發線程的數目,而線程數過多往往會在線程上下文切換上以及線程同步上浪費過多時間。
  • 用法: 我們可以調用ThreadPoolExecutor的某個構造方法來自己創建一個線程池。但通常情況下我們可以使用Executors類提供給我們的靜態工廠方法來更方便的創建一個線程池對象。創建了線程池對象后,我們就可以調用submit方法提交任務到線程池中去執行了;線程池使用完畢后我們要記得調用shutdown方法來關閉它。

for-each與常規for循環的效率對比

關於這個問題我們直接看《Effective Java》給我們做的解答:

for-each能夠讓代碼更加清晰,並且減少了出錯的機會。 下面的慣用代碼適用於集合與數組類型:

for (Element e : elements) {

doSomething(e);

}

使用for-each循環與常規的for循環相比,並不存在性能損失,即使對數組進行迭代也是如此。實際上,在有些場合下它還能帶來微小的性能提升,因為它只計算一次數組索引的上限。

簡述Java IO與NIO的區別

Java IO是面向流的,這意味着我們需要每次從流中讀取一個或多個字節,直到讀取完所有字節;NIO是面向緩沖的,也就是說會把數據讀取到一個緩沖區中,然后對緩沖區中的數據進行相應處理。

Java IO是阻塞IO,而NIO是非阻塞IO。

Java NIO中存在一個稱為選擇器(selector)的東西,它允許你把多個通道(channel)注冊到一個選擇器上,然后使用一個線程來監視這些通道:若這些通道里有某個准備好可以開始進行讀或寫操作了,則開始對相應的通道進行讀寫。而在等待某通道變為可讀/寫期間,請求對通道進行讀寫操作的線程可以去干別的事情。

反射的作用與原理

反射的作用概括地說是運行時獲取類的各種定義信息,比如定義了哪些屬性與方法。原理是通過類的class對象來獲取它的各種信息。

Java中的泛型機制

關於泛型機制的詳細介紹請直接戳 Java核心技術點之泛型

常見設計模式

所謂“設計模式”,不過是面向對象編程中一些常用的軟件設計手法,並且經過實踐的檢驗,這些設計手法在各自的場景下能解決一些需求,因此它們就成為了如今廣為流傳的”設計模式“。也就是說,正式因為在某些場景下產生了一些棘手的問題,才催生了相應的設計模式。明確了這一點,我們在學習某種設計模式時要充分理解它產生的背景以及它所解決的主要矛盾是什么。

常用的設計模式可以分為以下三大類:

  • 創建型模式: 包括工廠模式(又可進一步分為簡單工廠模式、工廠方法模式、抽象工廠模式)、建造者模式、單例模式。
  • 結構型模式: 包括適配器模式、橋接模式、裝飾模式、外觀模式、享元模式、代理模式。
  • 行為型模式: 包括命令模式、中介者模式、觀察者模式、狀態模式、策略模式。

注解的基本概念與使用

注解可以看作是“增強版的注釋”,它可以向編譯器、虛擬機說明一些事情。 注解是描述Java代碼的代碼,它能夠被編譯器解析,注解處理工具在運行時也能夠解析注解。注解本身是“被動”的信息,只有主動解析它才有意義。 除了向編譯器/虛擬機傳遞信息,我們也可以使用注解來生成一些“模板化”的代碼。

HashMap的那些事

1.1、HashMap的實現原理

1.1.1、結構

HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體,HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。如下圖所示:

Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

image.png

當新建一個HashMap的時候,就會初始化一個數組。哈希表是由數組+鏈表組成的,一個長度為16的數組中,每個元素存儲的是一個鏈表的頭結點。這些元素一般情況是通過hash(key)%len的規則存儲到數組中,也就是元素的key的哈希值對數組長度取模得到。

1.1.2、核心變量

Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

image.png

1.1.3、put存儲邏輯

當我們往HashMap中put元素的時候,先根據key的hashCode重新計算hash值,根據hash值得到這個元素在數組中的位置(即下標), 如果數組該位置上已經存放有其他元素了,那么在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放在鏈尾。如果數組該位置上沒有元素,就直接將該元素放到此數組中的該位置上。

這里有一個特殊的地方。在JDK1.6中,HashMap采用位桶+鏈表實現,即使用鏈表處理沖突,同一hash值的鏈表都存儲在一個鏈表里。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。而JDK1.8中,HashMap采用位桶+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換為紅黑樹,這樣大大減少了查找時間。

紅黑樹

紅黑樹和平衡二叉樹(AVL樹)類似,都是在進行插入和刪除操作時通過特定操作保持二叉查找樹的平衡,從而獲得較高的查找性能。

紅黑樹和AVL樹的區別在於它使用顏色來標識結點的高度,它所追求的是局部平衡而不是AVL樹中的非常嚴格的平衡。

1.1.4、get讀取邏輯

從HashMap中get元素時,首先計算key的hashCode,找到數組中對應位置的某一元素,然后通過key的equals方法在對應位置的鏈表中找到需要的元素。

如果第一個節點是TreeNode,說明采用的是數組+紅黑樹結構處理沖突,遍歷紅黑樹,得到節點值。

1.1.5、歸納

簡單地說,HashMap 在底層將 key-value 當成一個整體進行處理,這個整體就是一個 Node 對象。HashMap 底層采用一個 Node<K,V>[] 數組來保存所有的 key-value 對,當需要存儲一個 Node 對象時,會根據hash算法來決定其在數組中的存儲位置,在根據equals方法決定其在該數組位置上的鏈表中的存儲位置;當需要取出一個Entry時,也會根據hash算法找到其在數組中的存儲位置,再根據equals方法從該位置上的鏈表中取出該Node。

1.1.6、HashMap的resize(rehash)

當HashMap中的元素越來越多的時候,hash沖突的幾率也就越來越高,因為數組的長度是固定的。所以為了提高查詢的效率,就要對HashMap的數組進行擴容,在對HashMap數組進行擴容時,就會出現性能問題:原數組中的數據必須重新計算其在新數組中的位置,並放進去,這就是resize。

那么HashMap什么時候進行擴容呢?當HashMap中的元素個數超過數組大小loadFactor時,就會進行數組擴容,loadFactor的默認值為0.75,這是一個折中的取值。也就是說,默認情況下,數組大小為16,那么當HashMap中元素個數超過160.75=12的時候,就把數組的大小擴展為 216=32,即擴大一倍,然后重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,所以如果我們已經預知HashMap中元素的個數,那么預設元素的個數能夠有效的提高HashMap的性能。

1.2、HashMap在並發場景下的問題和解決方案

1.2.1、多線程put后可能導致get死循環

問題原因就是HashMap是非線程安全的,多個線程put的時候造成了某個key值Entry key List的死循環,問題就這么產生了。

當另外一個線程get 這個Entry List 死循環的key的時候,這個get也會一直執行。最后結果是越來越多的線程死循環,最后導致服務器dang掉。我們一般認為HashMap重復插入某個值的時候,會覆蓋之前的值,這個沒錯。但是對於多線程訪問的時候,由於其內部實現機制(在多線程環境且未作同步的情況下,對同一個HashMap做put操作可能導致兩個或以上線程同時做rehash動作,就可能導致循環鍵表出現,一旦出現線程將無法終止,持續占用CPU,導致CPU使用率居高不下),就可能出現安全問題了。

為HashMap以鏈表組形式存在,初始數組16位(為何16位,又是一堆移位算法,下一篇文章再寫吧),如果長度超過75%,長度增加一倍,多線程操作的時候,恰巧兩個線程插入的時候都需要擴容,形成了兩個鏈表,這時候讀取,size不一樣,報錯了。其實這時候報錯都是好事,至少不會陷入死循環讓cpu死了,有種情況,假如兩個線程在讀,還有個線程在寫,恰巧擴容了,這時候你死都不知道咋死的,直接就是死循環,假如你是雙核cpu,cpu占用率就是50%,兩個線程恰巧都進入死循環了,得!中獎了。

1.2.2、多線程put的時候可能導致元素丟失

主要問題出在addEntry方法的new Entry (hash, key, value, e),如果兩個線程都同時取得了e,則他們下一個元素都是e,然后賦值給table元素的時候有一個成功有一個丟失。

1.2.3、解決方案

ConcurrentHashMap替換HashMap

Collections.synchronizedMap將HashMap包裝起來

1.3、ConcurrentHashMap PK HashTable

ConcurrentHashMap具體是怎么實現線程安全的呢,肯定不可能是每個方法加synchronized,那樣就變成了HashTable。

從ConcurrentHashMap代碼中可以看出,它引入了一個“分段鎖”的概念,具體可以理解為把一個大的Map拆分成N個小的HashTable,根據key.hashCode()來決定把key放到哪個HashTable中。

以空間換時間的結構,跟分布式緩存結構有點像,創建的時候,內存直接分為了16個segment,每個segment實際上還是存儲的哈希表(Segment其實就是一個HashMap ),寫入的時候,先找到對應的segment,然后鎖這個segment,寫完,解鎖,鎖segment的時候,其他segment還可以繼續工作。

ConcurrentHashMap如此的設計,優勢主要在於: 每個segment的讀寫是高度自治的,segment之間互不影響。這稱之為“鎖分段技術”;

二、線程,多線程,線程池的那些事

2.1、線程的各個狀態及切換

Java中的線程的生命周期大體可分為5種狀態:新建、可運行、運行、阻塞、死亡。

1、新建(NEW):新創建了一個線程對象。

2、可運行(RUNNABLE):線程對象創建后,其他線程(比如main線程)調用了該對象的start()方法。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取cpu 的使用權 。

3、運行(RUNNING):可運行狀態(runnable)的線程獲得了cpu 時間片(timeslice) ,執行程序代碼。

4、阻塞(BLOCKED):阻塞狀態是指線程因為某種原因放棄了cpu 使用權,也即讓出了cpu timeslice,暫時停止運行。直到線程進入可運行(runnable)狀態,才有機會再次獲得cpu timeslice 轉到運行(running)狀態。

阻塞的情況分三種:

1)等待阻塞:運行(running)的線程執行o.wait()方法,JVM會把該線程放入等待隊列(waitting queue)中。

2)同步阻塞:運行(running)的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池(lock pool)中。

3)其他阻塞:運行(running)的線程執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入可運行(runnable)狀態。

5、死亡(DEAD):線程run()、main() 方法執行結束,或者因異常退出了run()方法,則該線程結束生命周期。死亡的線程不可再次復生。

幾個方法的比較:

1)Thread.sleep(long millis),一定是當前線程調用此方法,當前線程進入阻塞,但不釋放對象鎖,millis后線程自動蘇醒進入可運行狀態。作用:給其它線程執行機會的最佳方式。

2)Thread.yield(),一定是當前線程調用此方法,當前線程放棄獲取的cpu時間片,由運行狀態變會可運行狀態,讓OS再次選擇線程。作用:讓相同優先級的線程輪流執行,但並不保證一定會輪流執行。實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程調度程序再次選中。Thread.yield()不會導致阻塞。

3)t.join()/t.join(long millis),當前線程里調用其它線程1的join方法,當前線程阻塞,但不釋放對象鎖,直到線程1執行完畢或者millis時間到,當前線程進入可運行狀態。

4)obj.wait(),當前線程調用對象的wait()方法,當前線程釋放對象鎖,進入等待隊列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時間到自動喚醒。

5)obj.notify(),喚醒在此對象監視器上等待的單個線程,選擇是任意性的。notifyAll()喚醒在此對象監視器上等待的所有線程。

2.2、多線程的實現方式Thread、Runnable、Callable

繼承Thread類,實現Runnable接口,實現Callable接口。

這三種方法的介紹和比較:

1、實現Runnable接口相比繼承Thread類有如下優勢:

1)可以避免由於Java的單繼承特性而帶來的局限

2)增強程序的健壯性,代碼能夠被多個線程共享,代碼與數據是獨立的

3)適合多個相同程序代碼的線程去處理同一資源的情況

2、實現Runnable接口和實現Callable接口的區別

1)Runnable是自從java1.1就有了,而Callable是1.5之后才加上去的

2)實現Callable接口的任務線程能返回執行結果,而實現Runnable接口的任務線程不能返回結果

3)Callable接口的call()方法允許拋出異常,而Runnable接口的run()方法的異常只能在內部消化,不能繼續上拋

4)加入線程池運行,Runnable使用ExecutorService的execute方法,Callable使用submit方法

注:Callable接口支持返回執行結果,此時需要調用FutureTask.get()方法實現,此方法會阻塞主線程直到獲取返回結果,當不調用此方法時,主線程不會阻塞

2.3、線程池原理和運行機制

java.uitl.concurrent.ThreadPoolExecutor類是線程池中最核心的一個類。

在ThreadPoolExecutor類中提供了四個構造方法,主要參數包括下面的參數:

1、int corePoolSize:核心池的大小。

線程池的基本大小,即在沒有任務需要執行的時候線程池的大小,並且只有在工作隊列滿了的情況下才會創建超出這個數量的線程。這里需要注意的是:在剛剛創建ThreadPoolExecutor的時候,線程並不會立即啟動,而是要等到有任務提交時才會啟動,除非調用了prestartCoreThread/prestartAllCoreThreads事先啟動核心線程。再考慮到keepAliveTime和allowCoreThreadTimeOut超時參數的影響,所以沒有任務需要執行的時候,線程池的大小不一定是corePoolSize。

2、int maximumPoolSize:線程池最大線程數,它表示在線程池中最多能創建多少個線程,注意與corePoolSize區分。

線程池中允許的最大線程數,線程池中的當前線程數目不會超過該值。如果隊列中任務已滿,並且當前線程個數小於maximumPoolSize,那么會創建新的線程來執行任務。

3、long keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。

4、TimeUnit unit:參數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性。

5、BlockingQueue<Runnable> workQueue:一個阻塞隊列,用來存儲等待執行的任務。

6、ThreadFactory threadFactory:線程工廠,主要用來創建線程。

7、RejectedExecutionHandler handler:表示當拒絕處理任務時的策略。

還有一個成員變量比較重要:poolSize

線程池中當前線程的數量,當該值為0的時候,意味着沒有任何線程,線程池會終止。同一時刻,poolSize不會超過maximumPoolSize。

2.4、線程池對任務的處理

1、如果當前線程池中的線程數目小於corePoolSize,則每來一個任務,就會創建一個線程去執行這個任務;

2、如果當前線程池中的線程數目>=corePoolSize,則每來一個任務,會嘗試將其添加到任務緩存隊列當中,若添加成功,則該任務會等待空閑線程將其取出去執行;若添加失敗(一般來說是任務緩存隊列已滿),則會嘗試創建新的線程去執行這個任務(maximumPoolSize);

3、如果當前線程池中的線程數目達到maximumPoolSize(此時線程池的任務緩存隊列已滿),則會采取任務拒絕策略進行處理;

任務拒絕策略,通常有以下四種策略:

1)ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。

2)ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。

3)ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)

4)ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務

4、如果線程池中的線程數量大於 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止,直至線程池中的線程數目不大於corePoolSize;如果允許為核心池中的線程設置存活時間,那么核心池中的線程空閑時間超過keepAliveTime,線程也會被終止。

2.5、線程池的狀態

1、線程池的狀態說明:

RUNNING(運行):接受新任務並處理排隊任務。

SHUTDOWN(關閉):不接受新任務,會處理隊列任務。

STOP(停止):不接受新任務,不處理隊列任務,並且中斷進程中的任務。

TIDYING(整理):所有任務都已終止,工作計數為零,線程將執行terminated()方法終止線程。

TERMINATED(已終止):terminated()方法已完成。

2、各個狀態之間的轉換

RUNNING -> SHUTDOWN:調用shutdown()方法。

RUNNING or SHUTDOWN-> STOP:調用shutdownNow()方法。

SHUTDOWN -> TIDYING:當隊列和池均都為空時。

STOP -> TIDYING:當池為空時。

TIDYING -> TERMINATED:當terminated()方法已完成。

線程和進程有什么區別?

進程和線程的區別:

對於進程來說,子進程是父進程的復制品,從父進程那里獲得父進程的數據空間,堆和棧的復制品。

而線程,相對於進程而言,是一個更加接近於執行體的概念,可以和同進程的其他線程之間直接共享數據,而且擁有自己的棧空間,擁有獨立序列。

共同點: 它們都能提高程序的並發度,提高程序運行效率和響應時間。線程和進程在使用上各有優缺點。 線程執行開銷比較小,但不利於資源的管理和保護,而進程相反。同時,線程適合在SMP機器上運行,而進程可以跨機器遷移。

他們之間根本區別在於 多進程中每個進程有自己的地址空間,線程則共享地址空間。所有其他區別都是因為這個區別產生的。比如說:

1. 速度。線程產生的速度快,通訊快,切換快,因為他們處於同一地址空間。

2. 線程的資源利用率好。

3. 線程使用公共變量或者內存的時候需要同步機制,但進程不用。

而他們通信方式的差異也仍然是由於這個根本原因造成的。

通信方式之間的差異

因為那個根本原因,實際上只有進程間需要通信,同一進程的線程共享地址空間,沒有通信的必要,但要做好同步/互斥,保護共享的全局變量。

而進程間通信無論是信號,管道pipe還是共享內存都是由操作系統保證的,是系統調用.

進程間的通信方式


  • 管道( pipe ):
  • 管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。
  • 有名管道 (namedpipe) :
  • 有名管道也是半雙工的通信方式,但是它允許無親緣關系進程間的通信。
  • 信號量(semophore ) :
  • 信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。
  • 消息隊列( messagequeue ) :
  • 消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。
  • 信號 (sinal ) :
  • 信號是一種比較復雜的通信方式,用於通知接收進程某個事件已經發生。
  • 共享內存(shared memory ) :
  • 共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。
  • 套接字(socket ) :
  • 套接口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同設備及其間的進程通信。

    線程間的通信方式

    1. 鎖機制:包括互斥鎖、條件變量、讀寫鎖
    • 互斥鎖提供了以排他方式防止數據結構被並發修改的方法。
    • 讀寫鎖允許多個線程同時讀共享數據,而對寫操作是互斥的。
    • 條件變量可以以原子的方式阻塞進程,直到某個特定條件為真為止。對條件的測試是在互斥鎖的保護下進行的。條件變量始終與互斥鎖一起使用。
    1. 信號量機制(Semaphore):包括無名線程信號量和命名線程信號量
    2. 信號機制(Signal):類似進程間的信號處理

    線程間的通信目的主要是用於線程同步,所以線程沒有像進程通信中的用於數據交換的通信機制。

    三、JVM的那些事

    3.1、JVM的結構

    每個JVM都包含:方法區、Java堆、Java棧、本地方法棧、程序計數器等。

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    1、方法區:共享

    各個線程共享的區域,存放類信息、常量、靜態變量。

    2、Java堆:共享

    也是線程共享的區域,我們的類的實例就放在這個區域,可以想象你的一個系統會產生很多實例,因此Java堆的空間也是最大的。如果Java堆空間不足了,程序會拋出OutOfMemoryError異常。

    3、Java棧:私有

    每個線程私有的區域,它的生命周期與線程相同,一個線程對應一個Java棧,每執行一個方法就會往棧中壓入一個元素,這個元素叫“棧幀”,而棧幀中包括了方法中的局部變量、用於存放中間狀態值的操作棧。如果Java棧空間不足了,程序會拋出StackOverflowError異常,想一想什么情況下會容易產生這個錯誤,對,遞歸,遞歸如果深度很深,就會執行大量的方法,方法越多Java棧的占用空間越大。

    4、本地方法棧:私有

    角色和Java棧類似只不過它是用來表示執行本地方法的,本地方法棧存放的方法調用本地方法接口,最終調用本地方法庫,實現與操作系統、硬件交互的目的。

    5、程序計數器:私有

    說到這里我們的類已經加載了,實例對象、方法、靜態變量都去了自己該去的地方,那么問題來了,程序該怎么執行,哪個方法先執行,哪個方法后執行,這些指令執行的順序就是程序計數器在管,它的作用就是控制程序指令的執行順序。

    6、執行引擎當然就是根據PC寄存器調配的指令順序,依次執行程序指令。

    3.2、Java堆的介紹及典型的垃圾回收算法介紹

    3.2.1、Java堆的介紹

    Java堆是虛擬機管理的最大的一塊內存,堆上的所有線程共享一塊內存區域,在啟動虛擬機時創建。此內存唯一目的就是存放對象實例,幾乎所有對象實例都在這里分配,這一點Java虛擬機規范中的描述是:所有對象實例及數組都要在堆上分配。

    Java堆是垃圾收集器管理的主要區域,也被稱為“GC堆”,由於現在收集器基本都采用分代收集算法,所以Java堆中還可以分為:新生代和老年代。

    堆的內存模型大致為:

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    默認的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值為 1:2 ( 該值可以通過參數 –XX:NewRatio 來指定 ),即:新生代 ( Young ) = 1/3 的堆空間大小,老年代 ( Old ) = 2/3 的堆空間大小。

    其中,新生代 ( Young ) 被細分為 Eden 和 兩個 Survivor 區域,這兩個 Survivor 區域分別被命名為 from 和 to以示區分。 默認的,Edem : from : to = 8 : 1 : 1 ( 可以通過參數 –XX:SurvivorRatio 來設定 ),即: Eden = 8/10 的新生代空間大小,from = to = 1/10 的新生代空間大小。

    JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來為對象服務,所以無論什么時候,總是有一塊 Survivor 區域是空閑着的。 因此,新生代實際可用的內存空間為 9/10 ( 即90% )的新生代空間。

    新生代是 GC 收集垃圾的頻繁區域。

    當對象在 Eden ( 包括一個 Survivor 區域,這里假設是 from 區域 ) 出生后,在經過一次 Minor GC 后,如果對象還存活,並且能夠被另外一塊 Survivor 區域所容納 ( 上面已經假設為 from 區域,這里應為 to 區域,即 to 區域有足夠的內存空間來存儲 Eden 和 from 區域中存活的對象 ),則使用復制算法將這些仍然還存活的對象復制到另外一塊 Survivor 區域 ( 即 to 區域 ) 中,然后清理所使用過的 Eden 以及 Survivor 區域 ( 即 from 區域 ),並且將這些對象的年齡設置為1,以后對象在 Survivor 區每熬過一次 Minor GC,就將對象的年齡 + 1,當對象的年齡達到某個值時 ( 默認是 15 歲,可以通過參數 -XX:MaxTenuringThreshold 來設定 ),這些對象就會成為老年代。

    但這也不是一定的,對於一些較大的對象 ( 即需要分配一塊較大的連續內存空間 ) 則是直接進入到老年代。

    From Survivor區域與To Survivor區域是交替切換空間,在同一時間內兩者中只有一個不為空。

    3.2.2、如何確定某個對象是可回收的(垃圾)

    1、引用計數法

    給對象中添加一個引用計數器,每當有一個地方引用它時,計數器就加1;當引用失效時,計數器值就減1;任何時刻計數器都為0的對象就是不可能再被使用的。

    這種方式的問題是無法解決循環引用的問題,當兩個對象循環引用時,就算把兩個對象都設置為null,因為他們的引用計數都不為0,這就會使他們永遠不會被清除。

    2、根搜索算法(可達性分析)

    為了解決引用計數法的循環引用問題,Java使用了可達性分析的方法。通過一系列的“GC roots”對象作為起點搜索。如果在“GC roots”和一個對象之間沒有可達路徑,則稱該對象是不可達的。要注意的是,不可達對象不等價於可回收對象,不可達對象變為可回收對象至少要經過兩次標記過程。兩次標記后仍然是可回收對象,則將面臨回收。

    比較常見的將對象視為可回收對象的原因:

    顯式地將對象的唯一強引用指向新的對象。

    顯式地將對象的唯一強引用賦值為Null。

    局部引用所指向的對象(如,方法內對象)。

    只有弱引用與其關聯的對象。

    1)強引用(StrongReference)

    強引用是使用最普遍的引用。如果一個對象具有強引用,那垃圾回收器絕不會回收它。當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題。 ps:強引用其實也就是我們平時A a = new A()這個意思。

    2)軟引用(SoftReference)

    如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存(下文給出示例)。

    軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

    3)弱引用(WeakReference)

    弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。

    弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

    4)虛引用(PhantomReference)

    “虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。

    虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之 關聯的引用隊列中。

    3.2.3、典型的垃圾回收算法介紹

    1、標記-清除算法(Mark-Sweep)

    最基礎的垃圾回收算法,分為“標注”和“清除”兩個階段:首先標記出所有需要回收的對象,在標記完成后統一回收掉所有被標記的對象。

    標記過程:為了能夠區分對象是live的,可以為每個對象添加一個marked字段,該字段在對象創建的時候,默認值是false。

    清除過程:去遍歷堆中所有對象,並找出未被mark的對象,進行回收。與此同時,那些被mark過的對象的marked字段的值會被重新設置為false,以便下次的垃圾回收。

    缺點:效率低,空間問題(產生大量不連續的內存碎片),后續可能發生大對象不能找到可利用空間的問題。

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    2、復制算法(Copying)——新生代的收集算法就是這種,但是比例不是1:1,而是(8+1):1

    為了解決Mark-Sweep算法內存碎片化的缺陷而被提出的算法。按內存容量將內存划分為大小相等的兩塊,每次只使用其中一塊。當這一塊內存滿后將尚存活的對象復制到另一塊上去,把已使用的內存空間一次清理掉。這種算法雖然實現簡單,內存效率高,不易產生碎片,但是最大的問題是可用內存被壓縮到了原本的一半。且存活對象增多的話,Copying算法的效率會大大降低。

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    3、標記-整理算法(Mark-Compact)——老年代的收集算法

    結合了以上兩個算法,標記階段和Mark-Sweep算法相同,標記后不是清理對象,而是將所有存活對象移向內存的一端,然后清除端邊界外的對象。如圖:

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    4、分代收集算法(Generational Collection)

    分代收集法是目前大部分JVM所采用的方法,其核心思想是根據對象存活的不同生命周期將內存划分為不同的域,一般情況下將GC堆划分為老生代(Tenured/Old Generation)和新生代(Young Generation)。

    老生代的特點是每次垃圾回收時只有少量對象需要被回收,新生代的特點是每次垃圾回收時都有大量垃圾需要被回收,因此可以根據不同區域選擇不同的算法。

    目前大部分JVM的GC對於新生代都采取復制算法(Copying),因為新生代中每次垃圾回收都要回收大部分對象,即要復制的操作比較少,但通常並不是按照1:1來划分新生代。一般將新生代划分為一塊較大的Eden空間和兩個較小的Survivor空間(From Space, To Space),每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將該兩塊空間中還存活的對象復制到另一塊Survivor空間中。

    老年代中的對象存活率高,沒有額外空間對它進行分配,使用“標記-清理”或“標記-整理”算法來進行回收。

    3.3、JVM處理FULLGC經驗

    3.3.1、內存泄漏

    1、產生原因

    1)JVM內存過小。

    2)程序不嚴密,產生了過多的垃圾。

    2、一般情況下,在程序上的體現為:

    1)內存中加載的數據量過於龐大,如一次從數據庫取出過多數據。

    2)集合類中有對對象的引用,使用完后未清空,使得JVM不能回收。

    3)代碼中存在死循環或循環產生過多重復的對象實體。

    4)使用的第三方軟件中的BUG。

    5)啟動參數內存值設定的過小。

    3.3.2、Java內存泄漏的排查案例

    1、確定頻繁Full GC現象,找出進程唯一ID

    使用jps(jps -l)或ps(ps aux | grep tomat)找出這個進程在本地虛擬機的唯一ID(LVMID,Local Virtual Machine Identifier)

    2、再使用“虛擬機統計信息監視工具:jstat”(jstat -gcutil 20954 1000)查看已使用空間站總空間的百分比,可以看到FGC的頻次。

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    3、找出導致頻繁Full GC的原因,找出出現問題的對象

    分析方法通常有兩種:

    1)把堆dump下來再用MAT等工具進行分析,但dump堆要花較長的時間,並且文件巨大,再從服務器上拖回本地導入工具,這個過程有些折騰,不到萬不得已最好別這么干。

    2)更輕量級的在線分析,使用“Java內存影像工具:jmap”生成堆轉儲快照(一般稱為headdump或dump文件)。

    jmap命令格式:jmap -histo:live 20954

    4、一個工具:BTrace,沒有使用過

    HTTP、HTTPS、協議相關

    5.1、HTTP請求報文和響應報文

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    5.2、HTTPS為什么是安全的?HTTPS的加密方式有哪些?

    5.2.1、HTTPS的工作原理說明HTTPS是安全的

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    客戶端在使用HTTPS方式與Web服務器通信時有以下幾個步驟,如圖所示。

    1、客戶使用https的URL訪問Web服務器,要求與Web服務器建立SSL連接。

    2、Web服務器收到客戶端請求后,會將網站的證書信息(證書中包含公鑰)傳送一份給客戶端。

    3、客戶端的瀏覽器與Web服務器開始協商SSL連接的安全等級,也就是信息加密的等級。

    4、客戶端的瀏覽器根據雙方同意的安全等級,建立會話密鑰,然后利用網站的公鑰將會話密鑰加密,並傳送給網站。

    5、Web服務器利用自己的私鑰解密出會話密鑰。

    6、Web服務器利用會話密鑰加密與客戶端之間的通信。

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    5.2.2、HTTPS的加密方式有哪些?

    1、對稱加密

    對稱加密是指加密和解密使用相同密鑰的加密算法。它要求發送方和接收方在安全通信之前,商定一個密鑰。對稱算法的安全性依賴於密鑰,泄漏密鑰就意味着任何人都可以對他們發送或接收的消息解密,所以密鑰的保密性對通信至關重要。

    2、更多的加密方式的了解

    5.3、TCP三次握手協議,四次揮手

    第一次握手:主機A發送位碼為syn=1,隨機產生seq number=1234567的數據包到服務器,主機B由SYN=1知道,A要求建立聯機;

    第二次握手:主機B收到請求后要確認聯機信息,向A發送ack number=(主機A的seq+1),syn=1,ack=1,隨機產生seq=7654321的包;

    第三次握手:主機A收到后檢查ack number是否正確,即第一次發送的seq number+1,以及位碼ack是否為1,若正確,主機A會再發送ack number=(主機B的seq+1),ack=1,主機B收到后確認seq值與ack=1則連接建立成功。

    完成三次握手,主機A與主機B開始傳送數據。

    5.4、OAuth協議介紹

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    5.5、防盜鏈Referer

    Referer請求頭: 代表當前訪問時從哪個網頁連接過來的。

    當Referer未存在或者是從其他站點訪問我們資源的時候就直接重定向到我們的主頁,這樣既可以防止我們的資源被竊取。

    六、Spring

    6.1、AOP的實現原理

    spring框架對於這種編程思想的實現基於兩種動態代理模式,分別是JDK動態代理 及 CGLIB的動態代理,這兩種動態代理的區別是 JDK動態代理需要目標對象實現接口,而 CGLIB的動態代理則不需要。下面我們通過一個實例來實現動態代理,進而幫助我們理解面向切面編程。

    JDK的動態代理要使用到一個類 Proxy 用於創建動態代理的對象,一個接口 InvocationHandler用於監聽代理對象的行為,其實動態代理的本質就是對代理對象行為的監聽。

    6.2、Spring MVC工作原理

    Spring的MVC框架主要由DispatcherServlet、處理器映射、處理器(控制器)、視圖解析器、視圖組成。

    6.2.1、SpringMVC原理圖

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    6.2.2、SpringMVC運行原理

    1、客戶端請求提交到DispatcherServlet

    2、由DispatcherServlet控制器查詢一個或多個HandlerMapping,找到處理請求的Controller

    3、DispatcherServlet將請求提交到Controller

    4、Controller調用業務邏輯處理后,返回ModelAndView

    5、DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖

    6、視圖負責將結果顯示到客戶端

    6.2.3、SpringMVC核心組件

    1、DispatcherServlet:中央控制器,把請求給轉發到具體的控制類

    2、Controller:具體處理請求的控制器

    3、HandlerMapping:映射處理器,負責映射中央處理器轉發給controller時的映射策略

    4、ModelAndView:服務層返回的數據和視圖層的封裝類

    5、ViewResolver:視圖解析器,解析具體的視圖

    6、Interceptors :攔截器,負責攔截我們定義的請求然后做處理工作

    6.2.4、Servlet 生命周期

    Servlet 生命周期可被定義為從創建直到毀滅的整個過程。以下是 Servlet 遵循的過程:

    1、Servlet 通過調用 init () 方法進行初始化。

    2、Servlet 調用 service() 方法來處理客戶端的請求。

    3、Servlet 通過調用 destroy() 方法終止(結束)。

    4、最后,Servlet 是由 JVM 的垃圾回收器進行垃圾回收的。

    6.2.5、Spring容器初始化過程

    Spring 啟動時讀取應用程序提供的Bean配置信息,並在Spring容器中生成一份相應的Bean配置注冊表,然后根據這張注冊表實例化Bean,裝配號Bean之間的依賴關系,為上層應用提供准備就緒的運行環境。

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點

    image.png

    七、分布式

    7.1、分布式下如何保證事務一致性

    分布式事務,常見的兩個處理辦法就是兩段式提交和補償。

    7.1.1、兩段式提交

    分布式事務將提交分成兩個階段:

    prepare;

    commit/rollback

    在分布式系統中,每個節點雖然可以知曉自己的操作是成功或者失敗,卻無法知道其他節點的操作的成功或失敗。當一個事務跨越多個節點時,為了保持事務的ACID特性,需要引入一個作為協調者的組件來統一掌控所有節點(參與者)的操作結果並最終指示這些節點是否需要把操作結果進行真正的提交。算法步驟如下:

    第一階段:

    1、協調者會問所有的參與者,是否可以執行提交操作。

    2、各個參與者開始事務執行的准備工作,如:為資源上鎖,預留資源。

    3、參與者響應協調者,如果事務的准備工作成功,則回應“可以提交”,否則回應“拒絕提交”。

    第二階段:

    1、如果所有的參與者都回應“可以提交”。那么協調者向所有的參與者發送“正式提交”的命令。參與者完成正式提交並釋放所有資源,然后回應“完成”,協調者收集各節點的“完成”回應后結束這個Global Transaction

    2、如果有一個參與者回應“拒絕提交”,那么協調者向所有的參與者發送“回滾操作”,並釋放所有資源,然后回應“回滾完成”,協調者收集各節點的“回滾”回應后,取消這個Global Transaction。

    7.1.2、三段式提交

    三段提交的核心理念是:在詢問的時候並不鎖定資源,除非所有人都同意了,才開始鎖資源。他把二段提交的第一個段break成了兩段:詢問,然后再鎖資源。最后真正提交。

    7.1.2、事務補償,最終一致性

    補償比較好理解,先處理業務,然后定時或者回調里,檢查狀態是不是一致的,如果不一致采用某個策略,強制狀態到某個結束狀態(一般是失敗狀態)。

    九、中間件和架構

    9.1、kafka消息隊列

    1、避免數據丟失

    producer:

    加大重試次數

    同步發送

    對於單條數據過大,要設置可接收的單條數據的大小

    對於異步發送,通過回調函數來感知丟消息

    block.on.buffer.full = true

    consumer:

    enable.auto.commit=false 關閉自動提交位移

    2、避免消息亂序

    假設a,b兩條消息,a先發送后由於發送失敗重試,這時順序就會在b的消息后面,可以設置max.in.flight.requests.per.connection=1來避免。

    max.in.flight.requests.per.connection:限制客戶端在單個連接上能夠發送的未響應請求的個數,設置此值是1表示kafka broker在響應請求之前client不能再向同一個broker發送請求,但吞吐量會下降。

    3、避免消息重復

    使用第三方redis的set

    9.2、ZooKeeper的原理

    9.3、SOA相關,RPC兩種實現方式:基於HTTP和基於TCP

    9.4、Netty

    Java高級工程師面試阿里,阿里雲,天貓,菜鳥,涉及到的知識點 

    java虛擬機

    什么時候會觸發full gc

    1. System.gc()方法的調用
    2. 老年代空間不足
    3. 永生區空間不足(JVM規范中運行時數據區域中的方法區,在HotSpot虛擬機中又被習慣稱為永生代或者永生區,Permanet Generation中存放的為一些class的信息、常量、靜態變量等數據)
    4. GC時出現promotion failed和concurrent mode failure
    5. 統計得到的Minor GC晉升到舊生代平均大小大於老年代剩余空間
    6. 堆中分配很大的對象

    JAVA 線程狀態轉換

    JAVA 線程狀態轉換圖示

    解析一些java復雜面試題的簡單操作

    synchronized 的底層怎么實現

    1. 同步代碼塊(Synchronization)基於進入和退出管程(Monitor)對象實現。每個對象有一個監視器鎖(monitor)。當monitor被占用時就會處於鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:
    • 如果monitor的進入數為0,則該線程進入monitor,然后將進入數設置為1,該線程即為monitor的所有者。
    • 如果線程已經占有該monitor,只是重新進入,則進入monitor的進入數加1.
    • 如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試獲取monitor的所有權。
    1. 被 synchronized 修飾的同步方法並沒有通過指令monitorenter和monitorexit來完成(理論上其實也可以通過這兩條指令來實現),不過相對於普通方法,其常量池中多了ACC_SYNCHRONIZED標示符。JVM就是根據該標示符來實現方法的同步的:當方法調用時,調用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標志是否被設置,如果設置了,執行線程將先獲取monitor,獲取成功之后才能執行方法體,方法執行完后再釋放monitor。在方法執行期間,其他任何線程都無法再獲得同一個monitor對象。 其實本質上沒有區別,只是方法的同步是一種隱式的方式來實現,無需通過字節碼來完成

    B樹和B+樹的區別

    1. B樹,每個節點都存儲key和data,所有節點組成這棵樹,並且葉子節點指針為nul,葉子結點不包含任何關鍵字信息。

    解析一些java復雜面試題的簡單操作

    1. B+樹,所有的葉子結點中包含了全部關鍵字的信息,及指向含有這些關鍵字記錄的指針,且葉子結點本身依關鍵字的大小自小而大的順序鏈接,所有的非終端結點可以看成是索引部分,結點中僅含有其子樹根結點中最大(或最小)關鍵字。 (而B 樹的非終節點也包含需要查找的有效信息)

    解析一些java復雜面試題的簡單操作

    為什么說B+比B樹更適合實際應用中操作系統的文件索引和數據庫索引?

    1. B+的磁盤讀寫代價更低 B+的內部結點並沒有指向關鍵字具體信息的指針。因此其內部結點相對B樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那么盤塊所能容納的關鍵字數量也越多。一次性讀入內存中的需要查找的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
    2. B+-tree的查詢效率更加穩定 由於非終結點並不是最終指向文件內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查找必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。

    JVM,JRE,JDK的區別

    JVM :英文名稱(Java Virtual Machine),就是我們耳熟能詳的 Java 虛擬機。它只認識 xxx.class 這種類型的文件,它能夠將 class 文件中的字節碼指令進行識別並調用操作系統向上的 API 完成動作。所以說,jvm 是 Java 能夠跨平台的核心,具體的下文會詳細說明。

    JRE :英文名稱(Java Runtime Environment),我們叫它:Java 運行時環境。它主要包含兩個部分,jvm 的標准實現和 Java 的一些基本類庫。它相對於 jvm 來說,多出來的是一部分的 Java 類庫。

    JDK :英文名稱(Java Development Kit),Java 開發工具包。jdk 是整個 Java 開發的核心,它集成了 jre 和一些好用的小工具。例如:javac.exe,java.exe,jar.exe 等。

    顯然,這三者的關系是:一層層的嵌套關系。JDK>JRE>JVM

    借一張圖簡單說明一下

    Java 中JRE、JDK、JVM,以及java、javascript、js、jsp的區別

    然后是前端技術一些概念,雖然現在基本是前后端分離的模式開發,但也需要理解一些基礎吧!

    javascript==js

    js是一種腳本語言,在html中,css管理位置,html主管內容,而js主管動作,減輕后台的操作,可以很簡單的就實現對輸入的數據的驗證。比如說注冊的時候,用js中的ajax到后台實時驗證本用戶名是否已經被注冊,驗證碼是否正確或者用來實現異步更新,為用戶帶來更好的體驗。用jquery來驗證密碼的合法性,輸入密碼與確認密碼是否一樣,從而反饋到html頁面上,可以通過操控css或者html頁面內容來確認輸入內容是否有錯。但是ajax和jquery都是js的一個庫。

    js!=jsp

    js(javascript) jsp(java server pages)

    以前在知乎里面看到了一句相當經典的回答,js與jsp的關系就是雷鋒和雷峰塔的關系。從這句話可以看出它們倆沒有任何聯系,而實際上也是這樣。jsp其實可以看做一種腳本語言,需要用servlet來編譯實現,然而作為一種腳本語言它有相當強大,在其中可以嵌入java代碼,jsp中幾乎可以使用全部的java類 。其實就是可以把jsp當做html來作為網頁顯示出來,而且其上還可以嵌套java語言,也可以嵌套其他的語言類似,當然都序言用servlet來編譯實現。jsp作為字節碼文件執行后可以直接運行,不必每次都要編譯,速度快。可能我表述還是有點問題,但是jsp和js大多都應用於web網頁的編寫上,jsp可以看做html和java的結合體,當然js就可以在jsp上實現一些動作,特效,驗證功能,與在html中所實現的效果一樣。因為jsp是在服務器端解釋執行的,服務器執行轉化后的.class程序,客戶端接收到的只是服務器發來的html代碼,看不到jsp代碼。而js可以在客戶端通過查看源代碼顯示出來。

    java、jsp

    java是一種編程語言,jsp只是相當於java里面的servlet部分

    后言

    記得剛開始開發網站的時候,我的一個學長叫我去看jsp,然后我就用了一個星期看js去了,我還以為js就是jsp,然后就jj了,javascript和jsp也沒差多少,所以做了很多的無用功,多走了不該走的彎路,不過后來兩個東西都用上了,而且用處都還非常大。

    重要的事情說三遍,

    js!=jsp,js!=jsp,js!=jsp。

    js==javascript

    jsp==java server pages

    待補充答案的部分

    基礎題目

    1. Java線程的狀態

      問了對Java的Map了解嗎,請說出其中的幾個接口,怎么獲取key,怎么判斷是否包含key,哪些實現了Map接口,map的hash以及數據結構,1.7和1.8的區別等。

      2、寫一個棧的實現,用數組,確保最大隊列長度為k(我當時問了滿了要不要什么策略),第一次我用front和end兩個指針,然后他問我一個變量可以不(我說的不可以),然后我說front + size(隊列中的元素)可以,然后手寫。

      3、問了一些juc並發庫有哪些類(futrue,futruetask,excutors,executorthreadpool,countdownlatch,cyclicbarrier,symphone等)

      4、怎么確保當所有線程執行到某個點等待,直到所有線程都執行到時一起往下執行(cyclicbarrier)。

      5、cyclicbarrier和countdownlatch有什么區別,以及應用場景。

    1. 怎么查看是哪一條SQL執行慢(這個之前在面拼多多的時候也被問到過,但樓主沒去看,被自己不善於總結坑了),slow_query_log,long_query_time,slow_query_log_file,log_queries_not_using_indexes這個命令大家可以去看下

      4、ACID的意義(原子性,一致性,隔離性,持久性,當時腦子懵逼了,只說出了兩個)

      5、數據庫的四種隔離級別,怎么避免臟讀

      6、hashmap和currenthashmap的數據結構,volatile了解嗎,寫個volatile的應用場景(我就說了單列的雙重檢驗)

      7、jdk1.8的特性。

      9、還有什么我沒有問到的嗎(我說我什么方向的都有一點研究),然后面試官看了下學歷,渣渣本科,好吧不問了。

    1. 進程和線程的區別,進程間如何通訊,線程間如何通訊
    2. HashMap的數據結構是什么?如何實現的。和HashTable,ConcurrentHashMap的區別
    3. Cookie和Session的區別
    4. 索引有什么用?如何建索引?
    5. ArrayList是如何實現的,ArrayList和LinkedList的區別?ArrayList如何實現擴容。
    6. equals方法實現
    7. 面向對象
    8. 線程狀態,BLOCKED和WAITING有什么區別
    9. JVM如何加載字節碼文件
    10. JVM GC,GC算法。
    11. 什么情況會出現Full GC,什么情況會出現yong GC。
    12. JVM內存模型
    13. Java運行時數據區
    14. 事務的實現原理
    15. Java讀取一個文件, 有哪些方法, 考慮性能, 用哪一個類
    16. BIO, NIO, AIO區別
    17. Java 類加載機制
    18. 介紹線程安全的list(copyonwritelist)
    19. 線程安全的map,具體是怎么實現的,與Hashtable什么區別。
    20. 為什么使用雙親委派模型
    21. NIO的組件, Selector
    22. 什么是序列化, IO的序列化方式, 為什么需要序列化(包括在網絡傳輸的情況下)
    23. Error和Exception區別
    24. RuntimeException和非RuntimeException區別
    25. 什么叫線程安全, 保證線程安全的方法
    26. 加鎖的方式, synchronized作用在方法上和代碼塊區別
    27. synchronized(this)和synchronized(Xx.class)區別
    28. 知道的線程池(ThreadPoolExecutor屬於一類,forkjoin知道嗎)
    29. 線程池怎么自己去實現?給你一個Runnable、一個容器怎么實現。
    30. AQS中線程等待怎么做的(線程掛起狀態怎么做的)?
    31. 阻塞非阻塞的區別?
    32. 異步和同步的區別?異步是使用的內核級線程還是用戶態線程。
    33. AIO在Java中應用到了嗎?
    34. 1. junit用法,before,beforeClass,after, afterClass的執行順序

      2. 分布式鎖

      3. nginx的請求轉發算法,如何配置根據權重轉發

      4. 用hashmap實現redis有什么問題(死鎖,死循環,可用ConcurrentHashmap)

      5. 線程的狀態

      5. 線程的阻塞的方式

      6. sleep和wait的區別

      7. hashmap的底層實現

      8. 一萬個人搶100個紅包,如何實現(不用隊列),如何保證2個人不能搶到同一個紅包,可用分布式鎖

      9. java內存模型,垃圾回收機制,不可達算法

      10. 兩個Integer的引用對象傳給一個swap方法在方法內部交換引用,返回后,兩個引用的值是否會發現變化

      11. aop的底層實現,動態代理是如何動態,假如有100個對象,如何動態的為這100個對象代理

      12. 是否用過maven install。 maven test。git(make install是安裝本地jar包)

      13. tomcat的各種配置,如何配置docBase

      14. spring的bean配置的幾種方式

      15. web.xml的配置

      16. spring的監聽器。

      17. zookeeper的實現機制,有緩存,如何存儲注冊服務的

      18. IO會阻塞嗎?readLine是不是阻塞的

      19. 用過spring的線程池還是java的線程池?

      20. 字符串的格式化方法 (20,21這兩個問題問的太低級了)

      21. 時間的格式化方法

      22. 定時器用什么做的

      23. 線程如何退出結束

      24. java有哪些鎖?樂觀鎖 悲觀鎖 synchronized 可重入鎖 讀寫鎖,用過reentrantlock嗎?reentrantlock與synmchronized的區別

      25. ThreadLocal的使用場景

      26. java的內存模型,垃圾回收機制

      27. 為什么線程執行要調用start而不是直接run(直接run,跟普通方法沒什么區別,先調start,run才會作為一個線程方法運行)

      28. qmq消息的實現機制(qmq是去哪兒網自己封裝的消息隊列)

      29. 遍歷hashmap的三種方式

      30. jvm的一些命令

      31. memcache和redis的區別

      32. mysql的行級鎖加在哪個位置

      33. ConcurrentHashmap的鎖是如何加的?是不是分段越多越好

      34. myisam和innodb的區別(innodb是行級鎖,myisam是表級鎖)

      35. mysql其他的性能優化方式

      36. linux系統日志在哪里看

      37. 如何查看網絡進程

      38. 統計一個整數的二進制表示中bit為1的個數

      39. jvm內存模型,java內存模型

      40. 如何把java內存的數據全部dump出來

      41. 如何手動觸發全量回收垃圾,如何立即觸發垃圾回收

      42. hashmap如果只有一個寫其他全讀會出什么問題

      43. git rebase

      44. mongodb和hbase的區別

      45. 如何解決並發問題

      46. volatile的用途

      47. java線程池(好像之前我的理解有問題)

      48. mysql的binlog

      49. 代理模式

      50. mysql是如何實現事務的

      51. 讀寫分離何時強制要讀主庫,讀哪個從庫是通過什么方式決定的,從庫的同步mysql用的什么方式

      52. mysql的存儲引擎

      53. mysql的默認隔離級別,其他隔離級別

      54. 將一個鏈表反轉(用三個指針,但是每次只發轉一個)

      55. spring Aop的實現原理,具體說說

      56. 何時會內存泄漏,內存泄漏會拋哪些異常

      57. 是否用過Autowire注解

      58. spring的注入bean的方式

      59. sql語句各種條件的執行順序,如select, where, order by, group by

      60. select xx from xx where xx and xx order by xx limit xx; 如何優化這個(看explain)

      61. 四則元算寫代碼

      62. 統計100G的ip文件中出現ip次數最多的100個ip

      63. zookeeper的事物,結點,服務提供方掛了如何告知消費方

      64. 5台服務器如何選出leader(選舉算法)

      65. 適配器和代理模式的區別

      66. 讀寫鎖

      67. static加鎖

      68. 事務隔離級別

      69. 門面模式,類圖(外觀模式)

      70. mybatis如何映射表結構

      71. 二叉樹遍歷

      72. 主從復制

      73. mysql引擎區別

      74. 靜態內部類加載到了哪個區?方法區

      75. class文件編譯后加載到了哪

      76. web的http請求如何整體響應時間變長導致處理的請求數變少,該如何處理?用隊列,當處理不了那么多http請求時將請求放到隊列

      中慢慢處理,web如何實現隊列

      77. 線程安全的單例模式

      78. 快速排序性能考慮

      79. volatile關鍵字用法

      80. 求表的size,或做數據統計可用什么存儲引擎

      81. 讀多寫少可用什么引擎

      82. 假如要統計多個表應該用什么引擎

      83. concurrenhashmap求size是如何加鎖的,如果剛求完一段后這段發生了變化該如何處理

      84. 1000個蘋果放10個籃子,怎么放,能讓我拿到所有可能的個數

      85. 可重入的讀寫鎖,可重入是如何實現的?

      86. 是否用過NIO

      87. java的concurrent包用過沒

      88. sting s=new string("abc")分別在堆棧上新建了哪些對象

      89. java虛擬機的區域分配,各區分別存什么

      90. 分布式事務(JTA)

      91. threadlocal使用時注意的問題(ThreadLocal和Synchonized都用於解決多線程並發訪問。但是ThreadLocal與synchronized有本質的區別。synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal為每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的並不是同一個對象,這樣就隔離了多個線程對數據的數據共享。而Synchronized卻正好相反,它用於在多個線程間通信時能夠獲得數據共享)

      92. java有哪些容器(集合,tomcat也是一種容器)

      93. 二分查找算法

      94. myisam的優點,和innodb的區別

      95. redis能存哪些類型

      96. http協議格式,get和post的區別

      97. 可重入鎖中對應的wait和notify

      98. redis能把內存空間交換進磁盤中嗎(這個應該是可以的,但是那個面試官非跟我說不可以)

      99. java線程池中基於緩存和基於定長的兩種線程池,當請求太多時分別是如何處理的?定長的事用的隊列,如果隊列也滿了呢?交換進磁盤?基於緩存的線程池解決方法呢?

      100. synchronized加在方法上用的什么鎖

      101. 可重入鎖中的lock和trylock的區別

      102. innodb對一行數據的讀會枷鎖嗎?不枷鎖,讀實際讀的是副本

      103. redis做緩存是分布式存的?不同的服務器上存的數據是否重復?guava cache呢?是否重復?不同的機器存的數據不同

      104. 用awk統計一個ip文件中top10

      105. 對表做統計時可直接看schema info信息,即查看表的系統信息

      106. mysql目前用的版本

      107. 公司經驗豐富的人給了什么幫助?(一般boss面會問這些)

      108. 自己相對於一樣的應屆生有什么優勢

      109. 自己的好的總結習慣給自己今后的工作帶了什么幫助,舉例為證

      110. 原子類,線程安全的對象,異常的處理方式

      111. 4億個int數,如何找出重復的數(用hash方法,建一個2的32次方個bit的hash數組,每取一個int數,可hash下2的32次方找到它在hash數組中的位置,然后將bit置1表示已存在)

      112. 4億個url,找出其中重復的(考慮內存不夠,通過hash算法,將url分配到1000個文件中,不同的文件間肯定就不會重復了,再分別找出重復的)

      有1萬個數組,每個數組有1000個整數,每個數組都是降序的,從中找出最大的N個數,N<1000

      113. LinkedHashmap的底層實現

      114. 類序列化時類的版本號的用途,如果沒有指定一個版本號,系統是怎么處理的?如果加了字段會怎么樣?

      115. Override和Overload的區別,分別用在什么場景

      116. java的反射是如何實現的

  • 技術深度

    1. 有沒有看過JDK源碼,看過的類實現原理是什么。
    2. HTTP協議
    3. TCP協議
    4. 一致性Hash算法
    5. JVM如何加載字節碼文件
    6. 類加載器如何卸載字節碼
    7. IO和NIO的區別,NIO優點
    8. Java線程池的實現原理,keepAliveTime等參數的作用。
    9. HTTP連接池實現原理
    10. HTTP1.0與HTTP1.1區別
    11. TCP與UDP區別
    12. 數據庫連接池實現原理
    13. 數據庫的實現原理

    技術框架

    1. 看過哪些開源框架的源碼
    2. 為什么要用Redis,Redis有哪些優缺點?Redis如何實現擴容?
    3. Netty是如何使用線程池的,為什么這么使用
    4. 為什么要使用Spring,Spring的優缺點有哪些
    5. Spring的IOC容器初始化流程
    6. Spring的IOC容器實現原理,為什么可以通過byName和ByType找到Bean
    7. Spring AOP實現原理
    8. 消息中間件是如何實現的,技術難點有哪些
    9. Spring AOP實現原理
    10. 一個頁面, 一個提交按鈕, 如何防止重復提交, 我說驗證碼, 還有其它方式嗎?
    11. ajax實現跨域請求(前端或者后台實現方法)
    12. cookie和session區別
    13. forward和redirect區別
    14. redis
    15. rabbitMq
    16. memcached等的使用場景和設計原理
    17. redis部署方式。
    18. redis怎么加入節點
    19. redis持久化

      手撕字符串轉int

      2.數據庫事務隔離級別

      3.spring 事務

      4.數據庫索引失效的場景

      5.組合索引(A,B)若查詢B列是否用到了索引

      6.如果A是string類型,而查詢的時候是1314151617 用到了索引嗎?能查到這條數據嗎?

      7.數據庫怎么實現樂觀鎖?

      8.redis pipeline了解嗎?

      9.秒殺場景?怎么實現。redis怎么限流,限流算法。

      10.redis實現隊列、實現優先級隊列。

      11.分布式鎖。

    系統架構

    1. 如何搭建一個高可用系統
    2. 哪些設計模式可以增加系統的可擴展性
    3. 介紹設計模式,如模板模式,命令模式,策略模式,適配器模式、橋接模式、裝飾模式,觀察者模式,狀態模式,訪問者模式。
    4. 抽象能力,怎么提高研發效率。
    5. 什么是高內聚低耦合,請舉例子如何實現
    6. 什么情況用接口,什么情況用消息
    7. 如果AB兩個系統互相依賴,如何解除依賴
    8. 如何寫一篇設計文檔,目錄是什么
    9. 什么場景應該拆分系統,什么場景應該合並系統
    10. 系統和模塊的區別,分別在什么場景下使用

    分布式系統

    1. 分布式事務,兩階段提交。
    2. 如何實現分布式鎖
    3. 如何實現分布式Session
    4. 如何保證消息的一致性
    5. 負載均衡
    6. 正向代理(客戶端代理)和反向代理(服務器端代理)
    7. CDN實現原理
    8. 怎么提升系統的QPS和吞吐量
    9. 你用過的JVM命令有哪些
    10. 如果一個程序發生OOM, 該怎么處理
    11. JVM內存模型
    12. JDK7與JDK8的JVM內存模型區別
    13. 回收算法
    14. 回收器
    15. 虛擬機client和server的區別
    16. 對象和引用之間一般用什么連接?句柄池的作用是什么。

    實戰能力

    1. 有沒有處理過線上問題?出現內存泄露,CPU利用率標高,應用無響應時如何處理的。
    2. 開發中有沒有遇到什么技術問題?如何解決的
    3. 如果有幾十億的白名單,每天白天需要高並發查詢,晚上需要更新一次,如何設計這個功能。
    4. 新浪微博是如何實現把微博推給訂閱者
    5. Google是如何在一秒內把搜索結果返回給用戶的。
    6. 12306網站的訂票系統如何實現,如何保證不會票不被超賣。
    7. 如何實現一個秒殺系統,保證只有幾位用戶能買到某件商品。

    軟能力

    1. 如何學習一項新技術,比如如何學習Java的,重點學習什么
    2. 有關注哪些新的技術
    3. 工作任務非常多非常雜時如何處理
    4. 項目出現延遲如何處理
    5. 和同事的設計思路不一樣怎么處理
    6. 如何保證開發質量
    7. 職業規划是什么?短期,長期目標是什么
    8. 團隊的規划是什么
    9. 能介紹下從工作到現在自己的成長在那里?
  • 0.基礎部分

    無論是哪一種編程語言,基礎永遠是你不能忽視的部分。以下是比較常出現的十個點,當然最好是全都能熟悉。

    1. 使用length屬性獲取數組長度,public、private、protected、friendly區別
    2. 最有效率的方法算2*8等於幾
    3. 兩個對象值相同,x.equal(y)==true,但是卻可有不同的hashcode,這句話對不對。
    4. Collection和Collections區別
    5. Set里面的元素不能重復,用什么方法區分重復與否。
    6. 給出一個常見的runtime exception。
    7. try{}里有一個return語句,緊跟在try后的finally里的code會不會被執行,什么時候執行,return前執行還是return后執行。4、short s1;
    8. s1=s1+1;是否有錯?
    9. 7.運行時異常和一般異常的區別
    10. Java中的異常處理機制的簡單原理和應用

    1.Java高級部分

    1. 寫出單例模式。
    2. 寫出一種11位手機號的正則表達式
    3. 寫出知道的設計模式。
    4. Webservice介紹。
    5. tcp/ip協議三次握手。
    6. Ajax請求是否可以實現同步。
    7. 隱藏URL方式。
    8. 簡單概括取到一個網頁內容的實現步驟,(簡單來說就是爬蟲),考察邏輯思維能力。
    9. 簡述form表單提交post方法與get方法在字符編碼、http協議方面的區別。
    10. 一個http請求從開始到結束都經歷了哪些過程,簡寫流程圖。
    11. Spring框架以及數據庫和JVM三個方面,也會交流到分布式、線程池的實現

      1、Java內存結構,spring的aop的實現方法,java數據庫問題定位和性能調優;

      2、關於Java異常的續承層次結構,講述異常的續承關系;

      3、java中重載和重寫有什么區別,分別用什么關鍵字;

      4、關於分布式消息隊列,分布式緩存;

      5、關於hashmap源碼實現, jdk

      6、關於設計模式,uml,jvm 內存回收機制問題

      7、java線程如何啟動?java中加鎖的方式有哪些,怎么個寫法?

      8、對樂觀鎖和悲觀鎖的理解;

      9、ORACLE中的SQL如何進行優化,都有哪些方式?事務有哪些特性,在ORACLE中隔離有哪些級別?

      10、介紹一下自己最近做的一個典型的項目;

      11、在項目中遇到了哪些問題,自己是如何解決的 ;

      12、目前系統支撐的用戶量是多少,假如用戶量提升10倍,系統會出現什么樣的問題,如何重新設計系統【這里主要是想了解您的問題預見能力以及問題解決能力,考查思路】

      13、使用memcached是一個什么樣的原理

      14、如何存放數據到memcached集群中,介紹一下這個過程。跟進的問題,講一下一致性哈希算法的實現原理。

      15、JVM中堆是如何管理的,JVM的內存回收機制,介紹一下

      16、分布式事務實現方式

      17、熱點賬戶問題(項目中有就會問)

      阿里技術面試(電面)涉及Java基礎點(可參考):

    12. session
    13. java鎖
    14. gc原理
    15. hashmap
    16. listlink arraylist 區別
    17. aop 原理
    18. 多線程
    19. kafka 原理和容錯
    20. spark hadoop 原理
    21. redis 同步機制
    22. classLoader 機制
    23. Http 協議
    24. cookie的限制
    25. HashMap key的要求 , hashcode一致兩個對象是否相等
    26. JVM的原理
    27. 涉及面較廣,包括談到項目上遇到的問題,以此深入探討。

        Java面試題分享:

      • JMS的兩種模式是那些;
      • 富客戶端怎么更新;
      • 自己設計類似ESB這樣的企業數據總線應該有哪些功能;
      • 系統架構設計;
      • 集群中怎么控制session;
      • 怎么樣知道java存中是哪一些模塊消耗內存比較多;
      • 應用服務器的參數調整。
      • 人選介紹目前目前技術管理側重;
      • 對阿里推薦對應崗位的理解度;
      • 系統設計是怎么樣的;
      • 做的一些架構,數據源來自於哪里並深入問;
      • 模塊邊界,緩存機制;
      • 選用技術選型時,A和B的區別;
      • 多線程如何用,有什么好處,和進程的區別;
      • 多線程的過程;
      • 多線程同步的方法,X項目中如何去實現;
      • 分布式架構在你目前項目中的體現;
      • 跨主機通信用過什么,接口等;
      • 大數據存儲;
      • 介紹自己的工作職責、技術or管理怎么分配的
      • 介紹項目,涉及的技術把整個流程說下。然后他感興趣就會深入問
      • 然后就是聊一些jvm、nosql之類的
      • 假如服務器反應很慢,你應該怎么排查問題
      • 怎么跟蹤一個方法的用時,並且最小限度干涉業務程序

    2.框架部分

    關於這部分,主要考的也是一些框架部門中較為基礎的內容。

    1. Mybatis與Hibernate區別。
    2. 關於hibernate的相關問題。
    3. 關於Spring的相關問題。
    4. 關於struts1/2的工作流程。
    5. 介紹IOC和AOP。

    3.數據庫

    1. 學生成績表的常用查詢。(基礎到不能再基礎拉。)
    2. 如何防止SQL注入。
    3. 簡述悲觀鎖和樂觀鎖。
    4. 了解redis,memcache,mongodb等(如果有項目經驗最佳)。
    5. 數據庫性能優化常用基礎知識,百萬級數據優化。(這也是目前比較常被用到的)

    5.前端基礎

    1. 列舉3種數據類型。
    2. jquery取值賦值基本方法。
    3. CSS盒子模型的4個順序。
    4. 獲取單選按鈕的值,獲取復選框的值,獲取下拉列表的值,后去復選框的值,獲取單選按鈕組的值,文本框、文本域賦值。
    5. javascript變量范圍有什么不同,全局變量和局部變量。​

    HashSet 與TreeSet和LinkedHashSet的區別

    Set接口

    Set不允許包含相同的元素,如果試圖把兩個相同元素加入同一個集合中,add方法返回false。

    Set判斷兩個對象相同不是使用==運算符,而是根據equals方法。也就是說,只要兩個對象用equals方法比較返回true,Set就不會接受這兩個對象。

    HashSet與TreeSet都是基於Set接口的實現類。其中TreeSet是Set的子接口SortedSet的實現類。Set接口及其子接口、實現類的結構如下所示:

    |——SortedSet接口——TreeSet實現類

    Set接口——|——HashSet實現類

    |——LinkedHashSet實現類

    HashSet

    HashSet有以下特點

     不能保證元素的排列順序,順序有可能發生變化

     不是同步的

     集合元素可以是null,但只能放入一個null

    當向HashSet結合中存入一個元素時,HashSet會調用該對象的hashCode()方法來得到該對象的hashCode值,然后根據 hashCode值來決定該對象在HashSet中存儲位置。

    簡單的說,HashSet集合判斷兩個元素相等的標准是兩個對象通過equals方法比較相等,並且兩個對象的hashCode()方法返回值相等

    注意,如果要把一個對象放入HashSet中,重寫該對象對應類的equals方法,也應該重寫其hashCode()方法。其規則是如果兩個對象通過equals方法比較返回true時,其 hashCode也應該相同。另外,對象中用作equals比較標准的屬性,都應該用來計算 hashCode的值。

    TreeSet

    TreeSet類型是J2SE中唯一可實現自動排序的類型

    TreeSet是SortedSet接口的唯一實現類,TreeSet可以確保集合元素處於排序狀態。TreeSet支持兩種排序方式,自然排序 和定制排序,其中自然排序為默認的排序方式。向 TreeSet中加入的應該是同一個類的對象。

    TreeSet判斷兩個對象不相等的方式是兩個對象通過equals方法返回false,或者通過CompareTo方法比較沒有返回0

    自然排序

    自然排序使用要排序元素的CompareTo(Object obj)方法來比較元素之間大小關系,然后將元素按照升序排列。

    Java提供了一個Comparable接口,該接口里定義了一個compareTo(Object obj)方法,該方法返回一個整數值,實現了該接口的對象就可以比較大小。

    obj1.compareTo(obj2)方法如果返回0,則說明被比較的兩個對象相等,如果返回一個正數,則表明obj1大於obj2,如果是 負數,則表明obj1小於obj2。

    如果我們將兩個對象的equals方法總是返回true,則這兩個對象的compareTo方法返回應該返回0

    定制排序

    自然排序是根據集合元素的大小,以升序排列,如果要定制排序,應該使用Comparator接口,實現 int compare(To1,To2)方法

    LinkedHashSet

    LinkedHashSet集合同樣是根據元素的hashCode值來決定元素的存儲位置,但是它同時使用鏈表維護元素的次序。這樣使得元素看起 來像是以插入順 序保存的,也就是說,當遍歷該集合時候,LinkedHashSet將會以元素的添加順序訪問集合的元素。

    LinkedHashSet在迭代訪問Set中的全部元素時,性能比HashSet好,但是插入時性能稍微遜色於HashSet。

    有許多人學了很長時間的Java,但一直不明白hashCode方法的作用,

    我來解釋一下吧。首先,想要明白hashCode的作用,你必須要先知道Java中的集合。

    java的HashCode方法

    總的來說,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。

    你知道它們的區別嗎?前者集合內的元素是有序的,元素可以重復;后者元素無序,但元素不可重復。

    那么這里就有一個比較嚴重的問題了:要想保證元素不重復,可兩個元素是否重復應該依據什么來判斷呢?

    這就是Object.equals方法了。但是,如果每增加一個元素就檢查一次,那么當元素很多時,后添加到集合中的元素比較的次數就非常多了。 也就是說,如果集合中現在已經有1000個元素,那么第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大降低效率。

    於是,Java采用了哈希表的原理。哈希(Hash)實際上是個人名,由於他提出一哈希算法的概念,所以就以他的名字命名了。 哈希算法也稱為散列算法,是將數據依特定算法直接指定到一個地址上。如果詳細講解哈希算法,那需要更多的文章篇幅,我在這里就不介紹了。

    初學者可以這樣理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能並不是)。 這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一下子能定位到它應該放置的物理位置上。 如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經有元素了, 就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。 所以這里存在一個沖突解決的問題。這樣一來實際調用equals方法的次數就大大降低了,幾乎只需要一兩次。 所以,Java對於eqauls方法和hashCode方法是這樣規定的:

    1、如果兩個對象相同,那么它們的hashCode值一定要相同;

    2、如果兩個對象的hashCode相同,它們並不一定相同

    上面說的對象相同指的是用eqauls方法比較。你當然可以不按要求去做了,但你會發現,相同的對象可以出現在Set集合中。同時,增加新元素的效率會大大下降。

    hashcode這個方法是用來鑒定2個對象是否相等的。 那你會說,不是還有equals這個方法嗎? 不錯,這2個方法都是用來判斷2個對象是否相等的。但是他們是有區別的。 一般來講,equals這個方法是給用戶調用的,如果你想判斷2個對象是否相等,你可以重寫equals方法,然后在代碼中調用,就可以判斷他們是否相等 了。簡單來講,equals方法主要是用來判斷從表面上看或者從內容上看,2個對象是不是相等。

    舉個例子,有個學生類,屬性只有姓名和性別,那么我們可以 認為只要姓名和性別相等,那么就說這2個對象是相等的。

    hashcode方法一般用戶不會去調用,比如在hashmap中,由於key是不可以重復的,他在判斷key是不是重復的時候就判斷了hashcode 這個方法,而且也用到了equals方法。這里不可以重復是說equals和hashcode只要有一個不等就可以了!所以簡單來講,hashcode相 當於是一個對象的編碼,就好像文件中的md5,他和equals不同就在於他返回的是int型的,比較起來不直觀。我們一般在覆蓋equals的同時也要 覆蓋hashcode,讓他們的邏輯一致。

    舉個例子,還是剛剛的例子,如果姓名和性別相等就算2個對象相等的話,那么hashcode的方法也要返回姓名 的hashcode值加上性別的hashcode值,這樣從邏輯上,他們就一致了。 要從物理上判斷2個對象是否相等,用==就可以了。

    其他

    10.1、系統做了哪些安全防護

    1、XSS(跨站腳本攻擊)

    全稱是跨站腳本攻擊(Cross Site Scripting),指攻擊者在網頁中嵌入惡意腳本程序。

    XSS防范:

    XSS之所以會發生,是因為用戶輸入的數據變成了代碼。因此,我們需要對用戶輸入的數據進行HTML轉義處理,將其中的“尖括號”、“單引號”、“引號”之類的特殊字符進行轉義編碼。

    2、CSRF(跨站請求偽造)

    攻擊者盜用了你的身份,以你的名義向第三方網站發送惡意請求。

    CSRF的防御:

    1)盡量使用POST,限制GET

    2)將cookie設置為HttpOnly

    3)增加token

    4)通過Referer識別

    3、SQL注入

    使用預編譯語句(PreparedStatement),這樣的話即使我們使用sql語句偽造成參數,到了服務端的時候,這個偽造sql語句的參數也只是簡單的字符,並不能起到攻擊的作用。

    做最壞的打算,即使被’拖庫‘('脫褲,數據庫泄露')。數據庫中密碼不應明文存儲的,可以對密碼使用md5進行加密,為了加大破解成本,所以可以采用加鹽的(數據庫存儲用戶名,鹽(隨機字符長),md5后的密文)方式。

    4、DDOS

    最直接的方法增加帶寬。但是攻擊者用各地的電腦進行攻擊,他的帶寬不會耗費很多錢,但對於服務器來說,帶寬非常昂貴。

    雲服務提供商有自己的一套完整DDoS解決方案,並且能提供豐富的帶寬資源

    Spring框架面試問答

    1. 什么是spring?

    Spring 是個java企業級應用的開源開發框架。Spring主要用來開發Java應用,但是有些擴展是針對構建J2EE平台的web應用。Spring 框架目標是簡化Java企業級應用開發,並通過POJO為基礎的編程模型促進良好的編程習慣。

    2. 使用Spring框架的好處是什么?

    • 輕量:Spring 是輕量的,基本的版本大約2MB
    • 控制反轉:Spring通過控制反轉實現了松散耦合,對象們給出它們的依賴,而不是創建或查找依賴的對象們
    • 面向切面的編程(AOP):Spring支持面向切面的編程,並且把應用業務邏輯和系統服務分開
    • 容器:Spring 包含並管理應用中對象的生命周期和配置
    • MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品
    • 事務管理:Spring 提供一個持續的事務管理接口,可以擴展到上至本地事務下至全局事務(JTA)
    • 異常處理:Spring 提供方便的API把具體技術相關的異常(比如由JDBC,Hibernate or JDO拋出的)轉化為一致的unchecked 異常

    3. Spring由哪些模塊組成?

    以下是Spring 框架的基本模塊:

    • Core module
    • Bean module
    • Context module
    • Expression Language module
    • JDBC module
    • ORM module
    • OXM module
    • Java Messaging Service(JMS) module
    • Transaction module
    • Web module
    • Web-Servlet module
    • Web-Struts module
    • Web-Portlet module

    4. 核心容器(應用上下文) 模塊

    這是基本的Spring模塊,提供spring 框架的基礎功能,BeanFactory 是 任何以spring為基礎的應用的核心。Spring 框架建立在此模塊之上,它使Spring成為一個容器。

    5. BeanFactory – BeanFactory 實現舉例

    Bean 工廠是工廠模式的一個實現,提供了控制反轉功能,用來把應用的配置和依賴從正真的應用代碼中分離。最常用的BeanFactory 實現是XmlBeanFactory 類。

    6. XMLBeanFactory

    最常用的就是org.springframework.beans.factory.xml.XmlBeanFactory ,它根據XML文件中的定義加載beans。該容器從XML 文件讀取配置元數據並用它去創建一個完全配置的系統或應用。

    7. 解釋AOP模塊

    AOP模塊用於發給我們的Spring應用做面向切面的開發, 很多支持由AOP聯盟提供,這樣就確保了Spring和其他AOP框架的共通性。這個模塊將元數據編程引入Spring。

    8. 解釋JDBC抽象和DAO模塊

    通過使用JDBC抽象和DAO模塊,保證數據庫代碼的簡潔,並能避免數據庫資源錯誤關閉導致的問題,它在各種不同的數據庫的錯誤信息之上,提供了一個統一的異常訪問層。它還利用Spring的AOP 模塊給Spring應用中的對象提供事務管理服務。

    9. 解釋對象/關系映射集成模塊

    Spring 通過提供ORM模塊,支持我們在直接JDBC之上使用一個對象/關系映射映射(ORM)工具,Spring 支持集成主流的ORM框架,如Hiberate,JDO和 iBATIS SQL Maps。Spring的事務管理同樣支持以上所有ORM框架及JDBC。

    10. 解釋WEB 模塊

    Spring的WEB模塊是構建在application context 模塊基礎之上,提供一個適合web應用的上下文。這個模塊也包括支持多種面向web的任務,如透明地處理多個文件上傳請求和程序級請求參數的綁定到你的業務對象。它也有對Jakarta Struts的支持。

    12. Spring配置文件

    Spring配置文件是個XML 文件,這個文件包含了類信息,描述了如何配置它們,以及如何相互調用。

    13. 什么是Spring IOC 容器?

    Spring IOC 負責創建對象,管理對象(通過依賴注入(DI),裝配對象,配置對象,並且管理這些對象的整個生命周期。

    14. IOC的優點是什么?

    IOC 或 依賴注入把應用的代碼量降到最低。它使應用容易測試,單元測試不再需要單例和JNDI查找機制。最小的代價和最小的侵入性使松散耦合得以實現。IOC容器支持加載服務時的餓漢式初始化和懶加載。

    15. ApplicationContext通常的實現是什么?

    • FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
    • ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這里,你需要正確設置classpath因為這個容器將在classpath里找bean配置。
    • WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的所有bean。

    16. Bean 工廠和 Application contexts 有什么區別?

    Application contexts提供一種方法處理文本消息,一個通常的做法是加載文件資源(比如鏡像),它們可以向注冊為監聽器的bean發布事件。另外,在容器或容器內的對象上執行的那些不得不由bean工廠以程序化方式處理的操作,可以在Application contexts中以聲明的方式處理。Application contexts實現了MessageSource接口,該接口的實現以可插拔的方式提供獲取本地化消息的方法。

    17. 一個Spring的應用看起來象什么?

    • 一個定義了一些功能的接口
    • 這實現包括屬性,它的Setter , getter 方法和函數等
    • Spring AOP
    • Spring 的XML 配置文件
    • 使用以上功能的客戶端程序

    依賴注入

    18. 什么是Spring的依賴注入?

    依賴注入,是IOC的一個方面,是個通常的概念,它有多種解釋。這概念是說你不用創建對象,而只需要描述它如何被創建。你不在代碼里直接組裝你的組件和服務,但是要在配置文件里描述哪些組件需要哪些服務,之后一個容器(IOC容器)負責把他們組裝起來。

    19. 有哪些不同類型的IOC(依賴注入)方式?

    • 構造器依賴注入:構造器依賴注入通過容器觸發一個類的構造器來實現的,該類有一系列參數,每個參數代表一個對其他類的依賴。
    • Setter方法注入:Setter方法注入是容器通過調用無參構造器或無參static工廠 方法實例化bean之后,調用該bean的setter方法,即實現了基於setter的依賴注入。

    20. 哪種依賴注入方式你建議使用,構造器注入,還是 Setter方法注入?

    你兩種依賴方式都可以使用,構造器注入和Setter方法注入。最好的解決方案是用構造器參數實現強制依賴,setter方法實現可選依賴。

    Spring Beans

    21.什么是Spring beans?

    Spring beans 是那些形成Spring應用的主干的java對象。它們被Spring IOC容器初始化,裝配,和管理。這些beans通過容器中配置的元數據創建。比如,以XML文件中<bean/> 的形式定義。

    Spring 框架定義的beans都是單件beans。在bean tag中有個屬性”singleton”,如果它被賦為TRUE,bean 就是單件,否則就是一個 prototype bean。默認是TRUE,所以所有在Spring框架中的beans 缺省都是單件。點擊這里一圖Spring Bean的生命周期。

    22. 一個 Spring Bean 定義 包含什么?

    一個Spring Bean 的定義包含容器必知的所有配置元數據,包括如何創建一個bean,它的生命周期詳情及它的依賴。

    23. 如何給Spring 容器提供配置元數據?

    這里有三種重要的方法給Spring 容器提供配置元數據。

    XML配置文件。

    基於注解的配置。

    基於java的配置。

    24. 你怎樣定義類的作用域?

    當定義一個<bean> 在Spring里,我們還能給這個bean聲明一個作用域。它可以通過bean 定義中的scope屬性來定義。如,當Spring要在需要的時候每次生產一個新的bean實例,bean的scope屬性被指定為prototype。另一方面,一個bean每次使用的時候必須返回同一個實例,這個bean的scope 屬性 必須設為 singleton。

    25. 解釋Spring支持的幾種bean的作用域

    Spring框架支持以下五種bean的作用域:

    • singleton : bean在每個Spring ioc 容器中只有一個實例。
    • prototype:一個bean的定義可以有多個實例。
    • request:每次http請求都會創建一個bean,該作用域僅在基於web的Spring ApplicationContext情形下有效。
    • session:在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。
    • global-session:在一個全局的HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。

    缺省的Spring bean 的作用域是Singleton。

    26. Spring框架中的單例bean是線程安全的嗎?

    不,Spring框架中的單例bean不是線程安全的。

    27. 解釋Spring框架中bean的生命周期

    • Spring容器 從XML 文件中讀取bean的定義,並實例化bean。
    • Spring根據bean的定義填充所有的屬性。
    • 如果bean實現了BeanNameAware 接口,Spring 傳遞bean 的ID 到 setBeanName方法。
    • 如果Bean 實現了 BeanFactoryAware 接口, Spring傳遞beanfactory 給setBeanFactory 方法。
    • 如果有任何與bean相關聯的BeanPostProcessors,Spring會在postProcesserBeforeInitialization()方法內調用它們。
    • 如果bean實現IntializingBean了,調用它的afterPropertySet方法,如果bean聲明了初始化方法,調用此初始化方法。
    • 如果有BeanPostProcessors 和bean 關聯,這些bean的postProcessAfterInitialization() 方法將被調用。
    • 如果bean實現了 DisposableBean,它將調用destroy()方法。

    點擊這里一圖Spring Bean的生命周期。

    28. 哪些是重要的bean生命周期方法? 你能重載它們嗎?

    有兩個重要的bean 生命周期方法,第一個是setup , 它是在容器加載bean的時候被調用。第二個方法是 teardown 它是在容器卸載類的時候被調用。

    The bean 標簽有兩個重要的屬性(init-method和destroy-method)。用它們你可以自己定制初始化和注銷方法。它們也有相應的注解(@PostConstruct和@PreDestroy)。

    29. 什么是Spring的內部bean?

    當一個bean僅被用作另一個bean的屬性時,它能被聲明為一個內部bean,為了定義inner bean,在Spring 的 基於XML的 配置元數據中,可以在 <property/>或 <constructor-arg/> 元素內使用<bean/> 元素,內部bean通常是匿名的,它們的Scope一般是prototype。

    30. 在 Spring中如何注入一個java集合?

    Spring提供以下幾種集合的配置元素:

    • <list>類型用於注入一列值,允許有相同的值。
    • <set> 類型用於注入一組值,不允許有相同的值。
    • <map> 類型用於注入一組鍵值對,鍵和值都可以為任意類型。
    • <props>類型用於注入一組鍵值對,鍵和值都只能為String類型。

    31. 什么是bean裝配?

    裝配,或bean 裝配是指在Spring 容器中把bean組裝到一起,前提是容器需要知道bean的依賴關系,如何通過依賴注入來把它們裝配到一起。

    32. 什么是bean的自動裝配?

    Spring 容器能夠自動裝配相互合作的bean,這意味着容器不需要<constructor-arg>和<property>配置,能通過Bean工廠自動處理bean之間的協作。

    33. 解釋不同方式的自動裝配

    有五種自動裝配的方式,可以用來指導Spring容器用自動裝配方式來進行依賴注入

    • no:默認的方式是不進行自動裝配,通過顯式設置ref 屬性來進行裝配。
    • byName:通過參數名 自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byname,之后容器試圖匹配、裝配和該bean的屬性具有相同名字的bean。
    • byType:通過參數類型自動裝配,Spring容器在配置文件中發現bean的autowire屬性被設置成byType,之后容器試圖匹配、裝配和該bean的屬性具有相同類型的bean。如果有多個bean符合條件,則拋出錯誤。
    • constructor:這個方式類似於byType, 但是要提供給構造器參數,如果沒有確定的帶參數的構造器參數類型,將會拋出異常。
    • autodetect:首先嘗試使用constructor來自動裝配,如果無法工作,則使用byType方式。

    34.自動裝配有哪些局限性?

    自動裝配的局限性是:

    • 重寫:你仍需用 <constructor-arg>和 <property> 配置來定義依賴,意味着總要重寫自動裝配。
    • 基本數據類型:你不能自動裝配簡單的屬性,如基本數據類型,String字符串,和類。
    • 模糊特性:自動裝配不如顯式裝配精確,如果有可能,建議使用顯式裝配。

    35. 你可以在Spring中注入一個null 和一個空字符串嗎?

    可以。

    Spring注解

    36. 什么是基於Java的Spring注解配置? 給一些注解的例子

    基於Java的配置,允許你在少量的Java注解的幫助下,進行你的大部分Spring配置而非通過XML文件。

    以@Configuration 注解為例,它用來標記類可以當做一個bean的定義,被Spring IOC容器使用。另一個例子是@Bean注解,它表示此方法將要返回一個對象,作為一個bean注冊進Spring應用上下文。點擊這里學習JAVA幾大元注解。

    37. 什么是基於注解的容器配置?

    相對於XML文件,注解型的配置依賴於通過字節碼元數據裝配組件,而非尖括號的聲明。

    開發者通過在相應的類,方法或屬性上使用注解的方式,直接組件類中進行配置,而不是使用xml表述bean的裝配關系。

    38. 怎樣開啟注解裝配?

    注解裝配在默認情況下是不開啟的,為了使用注解裝配,我們必須在Spring配置文件中配置 <context:annotation-config/>元素。

    39. @Required 注解

    這個注解表明bean的屬性必須在配置的時候設置,通過一個bean定義的顯式的屬性值或通過自動裝配,若@Required注解的bean屬性未被設置,容器將拋出BeanInitializationException。

    40. @Autowired 注解

    @Autowired 注解提供了更細粒度的控制,包括在何處以及如何完成自動裝配。它的用法和@Required一樣,修飾setter方法、構造器、屬性或者具有任意名稱和/或多個參數的PN方法。

    41. @Qualifier 注解

    當有多個相同類型的bean卻只有一個需要自動裝配時,將@Qualifier 注解和@Autowire 注解結合使用以消除這種混淆,指定需要裝配的確切的bean。點擊這里學習更多常用注解。

    Spring數據訪問

    42.在Spring框架中如何更有效地使用JDBC?

    使用SpringJDBC 框架,資源管理和錯誤處理的代價都會被減輕。所以開發者只需寫statements 和 queries從數據存取數據,JDBC也可以在Spring框架提供的模板類的幫助下更有效地被使用,這個模板叫JdbcTemplate (例子見這里here)

    43. JdbcTemplate

    JdbcTemplate 類提供了很多便利的方法解決諸如把數據庫數據轉變成基本數據類型或對象,執行寫好的或可調用的數據庫操作語句,提供自定義的數據錯誤處理。

    44. Spring對DAO的支持

    Spring對數據訪問對象(DAO)的支持旨在簡化它和數據訪問技術如JDBC,Hibernate or JDO 結合使用。這使我們可以方便切換持久層。編碼時也不用擔心會捕獲每種技術特有的異常。

    45. 使用Spring通過什么方式訪問Hibernate?

    在Spring中有兩種方式訪問Hibernate:

    • 控制反轉 Hibernate Template和 Callback
    • 繼承 HibernateDAOSupport提供一個AOP 攔截器

    46. Spring支持的ORM

    Spring支持以下ORM:

    • Hibernate
    • iBatis
    • JPA (Java Persistence API)
    • TopLink
    • JDO (Java Data Objects)
    • OJB

    47.如何通過HibernateDaoSupport將Spring和Hibernate結合起來?

    用Spring的 SessionFactory 調用 LocalSessionFactory。集成過程分三步:

    • 配置the Hibernate SessionFactory
    • 繼承HibernateDaoSupport實現一個DAO
    • 在AOP支持的事務中裝配

    48. Spring支持的事務管理類型

    Spring支持兩種類型的事務管理:

    • 編程式事務管理:這意味你通過編程的方式管理事務,給你帶來極大的靈活性,但是難維護。
    • 聲明式事務管理:這意味着你可以將業務代碼和事務管理分離,你只需用注解和XML配置來管理事務。

    49. Spring框架的事務管理有哪些優點?

    • 它為不同的事務API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一個不變的編程模式。
    • 它為編程式事務管理提供了一套簡單的API而不是一些復雜的事務API如
    • 它支持聲明式事務管理。
    • 它和Spring各種數據訪問抽象層很好得集成。

    50. 你更傾向用那種事務管理類型?

    大多數Spring框架的用戶選擇聲明式事務管理,因為它對應用代碼的影響最小,因此更符合一個無侵入的輕量級容器的思想。聲明式事務管理要優於編程式事務管理,雖然比編程式事務管理(這種方式允許你通過代碼控制事務)少了一點靈活性。

    Spring面向切面編程(AOP)

    51. 解釋AOP

    面向切面的編程,或AOP, 是一種編程技術,允許程序模塊化橫向切割關注點,或橫切典型的責任划分,如日志和事務管理。

    52. Aspect 切面

    AOP核心就是切面,它將多個類的通用行為封裝成可重用的模塊,該模塊含有一組API提供橫切功能。比如,一個日志模塊可以被稱作日志的AOP切面。根據需求的不同,一個應用程序可以有若干切面。在Spring AOP中,切面通過帶有@Aspect注解的類實現。

    52. 在Spring AOP 中,關注點和橫切關注的區別是什么?

    關注點是應用中一個模塊的行為,一個關注點可能會被定義成一個我們想實現的一個功能。

    橫切關注點是一個關注點,此關注點是整個應用都會使用的功能,並影響整個應用,比如日志,安全和數據傳輸,幾乎應用的每個模塊都需要的功能。因此這些都屬於橫切關注點。

    54. 連接點

    連接點代表一個應用程序的某個位置,在這個位置我們可以插入一個AOP切面,它實際上是個應用程序執行Spring AOP的位置。

    55. 通知

    通知是個在方法執行前或執行后要做的動作,實際上是程序執行時要通過SpringAOP框架觸發的代碼段。

    Spring切面可以應用五種類型的通知:

    • before:前置通知,在一個方法執行前被調用
    • after:在方法執行之后調用的通知,無論方法執行是否成功
    • after-returning:僅當方法成功完成后執行的通知
    • after-throwing:在方法拋出異常退出時執行的通知
    • around:在方法執行之前和之后調用的通知

    56. 切點

    切入點是一個或一組連接點,通知將在這些位置執行。可以通過表達式或匹配的方式指明切入點。

    57. 什么是引入?

    引入允許我們在已存在的類中增加新的方法和屬性。

    58. 什么是目標對象?

    被一個或者多個切面所通知的對象。它通常是一個代理對象。也指被通知(advised)對象。

    59. 什么是代理?

    代理是通知目標對象后創建的對象。從客戶端的角度看,代理對象和目標對象是一樣的。

    60. 有幾種不同類型的自動代理?

    BeanNameAutoProxyCreator

    DefaultAdvisorAutoProxyCreator

    Metadata autoproxying

    61. 什么是織入。什么是織入應用的不同點?

    織入是將切面和到其他應用類型或對象連接或創建一個被通知對象的過程。

    織入可以在編譯時,加載時,或運行時完成。

    62. 解釋基於XML Schema方式的切面實現

    在這種情況下,切面由常規類以及基於XML的配置實現。

    63. 解釋基於注解的切面實現

    在這種情況下(基於@AspectJ的實現),涉及到的切面聲明的風格與帶有java5標注的普通java類一致。

    Spring 的MVC

    64. 什么是Spring的MVC框架?

    Spring 配備構建Web 應用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成,如Struts,Spring 的MVC框架用控制反轉把業務對象和控制邏輯清晰地隔離。它也允許以聲明的方式把請求參數和業務對象綁定。

    65. DispatcherServlet

    Spring的MVC框架是圍繞DispatcherServlet來設計的,它用來處理所有的HTTP請求和響應。

    66. WebApplicationContext

    WebApplicationContext 繼承了ApplicationContext 並增加了一些WEB應用必備的特有功能,它不同於一般的ApplicationContext ,因為它能處理主題,並找到被關聯的servlet。

    67. 什么是Spring MVC框架的控制器?

    控制器提供一個訪問應用程序的行為,此行為通常通過服務接口實現。控制器解析用戶輸入並將其轉換為一個由視圖呈現給用戶的模型。Spring用一個非常抽象的方式實現了一個控制層,允許用戶創建多種用途的控制器。

    68. @Controller 注解

    該注解表明該類扮演控制器的角色,Spring不需要你繼承任何其他控制器基類或引用Servlet API。

    69. @RequestMapping 注解

    該注解是用來映射一個URL到一個類或一個特定的方處理法上。

    【學習參考】

    [薦]https://www.toutiao.com/c/user/84982888621/#mid=1589035076683780

    [薦]https://www.toutiao.com/i6592700941210747405/

    https://www.toutiao.com/a6590673631498469901/

    https://www.toutiao.com/i6566145388829475336/

    https://www.toutiao.com/i6594406859459789319/


  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM