一嗅绰、Java 基礎(chǔ)
JDK 和 JRE 有什么區(qū)別?
- JDK:Java Development Kit 的簡(jiǎn)稱向族,java 開發(fā)工具包呵燕,提供了 java 的開發(fā)環(huán)境和運(yùn)行環(huán)境。
- JRE:Java Runtime Environment 的簡(jiǎn)稱件相,java 運(yùn)行環(huán)境再扭,為 java 的運(yùn)行提供了所需環(huán)境。
具體來說 JDK 其實(shí)包含了 JRE夜矗,同時(shí)還包含了編譯 java 源碼的編譯器 javac泛范,還包含了很多 java 程序調(diào)試和分析的工具。簡(jiǎn)單來說:如果你需要運(yùn)行 java 程序紊撕,只需安裝 JRE 就可以了罢荡,如果你需要編寫 java 程序,需要安裝 JDK对扶。
== 和 equals 的區(qū)別是什么区赵?
== 解讀
對(duì)于基本類型和引用類型 == 的作用效果是不同的,如下所示:
- 基本類型:比較的是值是否相同浪南;
- 引用類型:比較的是引用是否相同笼才;
代碼示例:
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
代碼解讀:因?yàn)?x 和 y 指向的是同一個(gè)引用,所以 == 也是 true逞泄,而 new String()方法則重寫開辟了內(nèi)存空間患整,所以 == 結(jié)果為 false,而 equals 比較的一直是值喷众,所以結(jié)果都為 true各谚。
equals 解讀
equals 本質(zhì)上就是 ==,只不過 String 和 Integer 等重寫了 equals 方法到千,把它變成了值比較昌渤。看下面的代碼就明白了憔四。
首先來看默認(rèn)情況下 equals 比較一個(gè)有相同值的對(duì)象膀息,代碼如下:
class Cat {
public Cat(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false
輸出結(jié)果出乎我們的意料,竟然是 false了赵?這是怎么回事潜支,看了 equals 源碼就知道了,源碼如下:
public boolean equals(Object obj) {
return (this == obj);
}
原來 equals 本質(zhì)上就是 ==柿汛。
那問題來了冗酿,兩個(gè)相同值的 String 對(duì)象,為什么返回的是 true?代碼如下:
String s1 = new String("老王");
String s2 = new String("老王");
System.out.println(s1.equals(s2)); // true
同樣的裁替,當(dāng)我們進(jìn)入 String 的 equals 方法项玛,找到了答案,代碼如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
原來是 String 重寫了 Object 的 equals 方法弱判,把引用比較改成了值比較襟沮。
總結(jié) :== 對(duì)于基本類型來說是值比較,對(duì)于引用類型來說是比較的是引用昌腰;而 equals 默認(rèn)情況下是引用比較开伏,只是很多類重新了 equals 方法,比如 String遭商、Integer 等把它變成了值比較硅则,所以一般情況下 equals 比較的是值是否相等。
兩個(gè)對(duì)象的 hashCode()相同株婴,則 equals()也一定為 true,對(duì)嗎暑认?
不對(duì)困介,兩個(gè)對(duì)象的 hashCode()相同,equals()不一定 true蘸际。
代碼示例:
1 String str1 = "通話";
2 String str2 = "重地";
3 System.out.println(String.format("str1:%d | str2:%d", str1.hashCode(),str2.hashCode()));
4 System.out.println(str1.equals(str2));
執(zhí)行的結(jié)果:
> str1:1179395 | str2:1179395
>
> false
代碼解讀:很顯然“通話”和“重地”的 hashCode() 相同座哩,然而 equals() 則為 false,因?yàn)樵谏⒘斜碇辛竿琱ashCode()相等即兩個(gè)鍵值對(duì)的哈希值相等根穷,然而哈希值相等,并不一定能得出鍵值對(duì)相等导坟。
final 在 java 中有什么作用屿良?
- final 修飾的類叫最終類,該類不能被繼承惫周。
- final 修飾的方法不能被重寫尘惧。
- final 修飾的變量叫常量,常量必須初始化递递,初始化之后值就不能被修改喷橙。
** java 中的 Math.round(-1.5) 等于多少?**
等于 -1登舞,因?yàn)樵跀?shù)軸上取值時(shí)贰逾,中間值(0.5)向右取整,所以正 0.5 是往上取整菠秒,負(fù) 0.5 是直接舍棄疙剑。
String 屬于基礎(chǔ)的數(shù)據(jù)類型嗎?
String 不屬于基礎(chǔ)類型,基礎(chǔ)類型有 8 種:byte核芽、boolean囚戚、char、short轧简、int驰坊、float、long哮独、double拳芙,而 String 屬于對(duì)象。
java 中操作字符串都有哪些類皮璧?它們之間有什么區(qū)別舟扎?
操作字符串的類有:String、StringBuffer悴务、StringBuilder睹限。
String 和 StringBuffer、StringBuilder 的區(qū)別在于 String 聲明的是不可變的對(duì)象讯檐,每次操作都會(huì)生成新的 String 對(duì)象羡疗,然后將指針指向新的 String 對(duì)象,而 StringBuffer别洪、StringBuilder 可以在原有對(duì)象的基礎(chǔ)上進(jìn)行操作叨恨,所以在經(jīng)常改變字符串內(nèi)容的情況下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的區(qū)別在于挖垛,StringBuffer 是線程安全的痒钝,而 StringBuilder 是非線程安全的,但 StringBuilder 的性能卻高于 StringBuffer痢毒,所以在單線程環(huán)境下推薦使用 StringBuilder送矩,多線程環(huán)境下推薦使用 StringBuffer。
String str="i"與 String str=new String("i")一樣嗎闸准?
不一樣益愈,因?yàn)閮?nèi)存的分配方式不一樣。String str="i"的方式夷家,java 虛擬機(jī)會(huì)將其分配到常量池中蒸其;而 String str=new String("i") 則會(huì)被分到堆內(nèi)存中。
如何將字符串反轉(zhuǎn)库快?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法摸袁。
示例代碼:
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abcdefg");
System.out.println(stringBuffer.reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abcdefg");
System.out.println(stringBuilder.reverse()); // gfedcba
String 類的常用方法都有那些?
- indexOf():返回指定字符的索引义屏。
- charAt():返回指定索引處的字符靠汁。
- replace():字符串替換蜂大。
- trim():去除字符串兩端空白。
- split():分割字符串蝶怔,返回一個(gè)分割后的字符串?dāng)?shù)組奶浦。
- getBytes():返回字符串的 byte 類型數(shù)組。
- length():返回字符串長(zhǎng)度踢星。
- toLowerCase():將字符串轉(zhuǎn)成小寫字母澳叉。
- toUpperCase():將字符串轉(zhuǎn)成大寫字符。
- substring():截取字符串沐悦。
- equals():字符串比較成洗。
抽象類必須要有抽象方法嗎?
不需要藏否,抽象類不一定非要有抽象方法瓶殃。
示例代碼:
1 abstract class Cat {
2 public static void sayHi() {
3 System.out.println("hi~");
4 }
5 }
上面代碼,抽象類并沒有抽象方法但完全可以正常運(yùn)行副签。
普通類和抽象類有哪些區(qū)別遥椿?
- 普通類不能包含抽象方法,抽象類可以包含抽象方法淆储。
- 抽象類不能直接實(shí)例化修壕,普通類可以直接實(shí)例化。
抽象類能使用 final 修飾嗎遏考?
不能,定義抽象類就是讓其他類繼承的蓝谨,如果定義為 final 該類就不能被繼承灌具,這樣彼此就會(huì)產(chǎn)生矛盾,所以 final 不能修飾抽象類譬巫,如下圖所示咖楣,編輯器也會(huì)提示錯(cuò)誤信息:
?
接口和抽象類有什么區(qū)別?
- 實(shí)現(xiàn):抽象類的子類使用 extends 來繼承芦昔;接口必須使用 implements 來實(shí)現(xiàn)接口诱贿。
- 構(gòu)造函數(shù):抽象類可以有構(gòu)造函數(shù);接口不能有咕缎。
- main 方法:抽象類可以有 main 方法珠十,并且我們能運(yùn)行它;接口不能有 main 方法凭豪。
- 實(shí)現(xiàn)數(shù)量:類可以實(shí)現(xiàn)很多個(gè)接口焙蹭;但是只能繼承一個(gè)抽象類。
- 訪問修飾符:接口中的方法默認(rèn)使用 public 修飾嫂伞;抽象類中的方法可以是任意訪問修飾符孔厉。
java 中 IO 流分為幾種拯钻?
按功能來分:輸入流(input)、輸出流(output)撰豺。
按類型來分:字節(jié)流和字符流粪般。
字節(jié)流和字符流的區(qū)別是:字節(jié)流按 8 位傳輸以字節(jié)為單位輸入輸出數(shù)據(jù),字符流按 16 位傳輸以字符為單位輸入輸出數(shù)據(jù)污桦。
BIO亩歹、NIO、AIO 有什么區(qū)別寡润?
- BIO:Block IO 同步阻塞式 IO捆憎,就是我們平常使用的傳統(tǒng) IO,它的特點(diǎn)是模式簡(jiǎn)單使用方便梭纹,并發(fā)處理能力低躲惰。
- NIO:New IO 同步非阻塞 IO,是傳統(tǒng) IO 的升級(jí)变抽,客戶端和服務(wù)器端通過 Channel(通道)通訊础拨,實(shí)現(xiàn)了多路復(fù)用。
- AIO:Asynchronous IO 是 NIO 的升級(jí)绍载,也叫 NIO2诡宗,實(shí)現(xiàn)了異步非堵塞 IO ,異步 IO 的操作基于事件和回調(diào)機(jī)制击儡。
Files的常用方法都有哪些塔沃?
- Files.exists():檢測(cè)文件路徑是否存在。
- Files.createFile():創(chuàng)建文件阳谍。
- Files.createDirectory():創(chuàng)建文件夾蛀柴。
- Files.delete():刪除一個(gè)文件或目錄。
- Files.copy():復(fù)制文件矫夯。
- Files.move():移動(dòng)文件鸽疾。
- Files.size():查看文件個(gè)數(shù)。
- Files.read():讀取文件训貌。
- Files.write():寫入文件制肮。
二、容器
java 容器都有哪些递沪?
常用容器的圖錄:
?
Collection 和 Collections 有什么區(qū)別豺鼻?
- java.util.Collection 是一個(gè)集合接口(集合類的一個(gè)頂級(jí)接口)。它提供了對(duì)集合對(duì)象進(jìn)行基本操作的通用接口方法款慨。Collection接口在Java 類庫中有很多具體的實(shí)現(xiàn)拘领。Collection接口的意義是為各種具體的集合提供了最大化的統(tǒng)一操作方式,其直接繼承接口有List與Set樱调。
- Collections則是集合類的一個(gè)工具類/幫助類约素,其中提供了一系列靜態(tài)方法届良,用于對(duì)集合中元素進(jìn)行排序、搜索以及線程安全等各種操作圣猎。
List士葫、Set、Map 之間的區(qū)別是什么送悔?
HashMap 和 Hashtable 有什么區(qū)別慢显?
hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法欠啤。
hashTable同步的荚藻,而HashMap是非同步的,效率上逼hashTable要高洁段。
hashMap允許空鍵值应狱,而hashTable不允許。如何決定使用 HashMap 還是 TreeMap祠丝?
對(duì)于在Map中插入疾呻、刪除和定位元素這類操作,HashMap是最好的選擇写半。然而岸蜗,假如你需要對(duì)一個(gè)有序的key集合進(jìn)行遍歷,TreeMap是更好的選擇叠蝇×г溃基于你的collection的大小,也許向HashMap中添加元素會(huì)更快悔捶,將map換為TreeMap進(jìn)行有序key的遍歷矾睦。說一下 HashMap 的實(shí)現(xiàn)原理?
HashMap概述: HashMap是基于哈希表的Map接口的非同步實(shí)現(xiàn)炎功。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵缓溅。此類不保證映射的順序蛇损,特別是它不保證該順序恒久不變。
HashMap的數(shù)據(jù)結(jié)構(gòu): 在java編程語言中坛怪,最基本的結(jié)構(gòu)就是兩種淤齐,一個(gè)是數(shù)組,另外一個(gè)是模擬指針(引用)袜匿,所有的數(shù)據(jù)結(jié)構(gòu)都可以用這兩個(gè)基本結(jié)構(gòu)來構(gòu)造的更啄,HashMap也不例外。HashMap實(shí)際上是一個(gè)“鏈表散列”的數(shù)據(jù)結(jié)構(gòu)居灯,即數(shù)組和鏈表的結(jié)合體祭务。
當(dāng)我們往Hashmap中put元素時(shí),首先根據(jù)key的hashcode重新計(jì)算hash值,根絕hash值得到這個(gè)元素在數(shù)組中的位置(下標(biāo)),如果該數(shù)組在該位置上已經(jīng)存放了其他元素,那么在這個(gè)位置上的元素將以鏈表的形式存放,新加入的放在鏈頭,最先加入的放入鏈尾.如果數(shù)組中該位置沒有元素,就直接將該元素放到數(shù)組的該位置上内狗。
需要注意Jdk 1.8中對(duì)HashMap的實(shí)現(xiàn)做了優(yōu)化,當(dāng)鏈表中的節(jié)點(diǎn)數(shù)據(jù)超過八個(gè)之后,該鏈表會(huì)轉(zhuǎn)為紅黑樹來提高查詢效率,從原來的O(n)到O(logn)
說一下 HashSet 的實(shí)現(xiàn)原理闷串?
HashSet底層由HashMap實(shí)現(xiàn)
HashSet的值存放于HashMap的key上
HashMap的value統(tǒng)一為PRESENTArrayList 和 LinkedList 的區(qū)別是什么晤斩?
最明顯的區(qū)別是 ArrrayList底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,支持隨機(jī)訪問妓柜,而 LinkedList 的底層數(shù)據(jù)結(jié)構(gòu)是雙向循環(huán)鏈表拌倍,不支持隨機(jī)訪問赂鲤。使用下標(biāo)訪問一個(gè)元素,ArrayList 的時(shí)間復(fù)雜度是 O(1)柱恤,而 LinkedList 是 O(n)数初。如何實(shí)現(xiàn)數(shù)組和 List 之間的轉(zhuǎn)換?
List轉(zhuǎn)換成為數(shù)組:調(diào)用ArrayList的toArray方法梗顺。
數(shù)組轉(zhuǎn)換成為L(zhǎng)ist:調(diào)用Arrays的asList方法泡孩。ArrayList 和 Vector 的區(qū)別是什么?
Vector是同步的荚守,而ArrayList不是珍德。然而,如果你尋求在迭代的時(shí)候?qū)α斜磉M(jìn)行改變矗漾,你應(yīng)該使用CopyOnWriteArrayList锈候。
ArrayList比Vector快,它因?yàn)橛型匠ü保粫?huì)過載泵琳。
ArrayList更加通用,因?yàn)槲覀兛梢允褂肅ollections工具類輕易地獲取同步列表和只讀列表誊役。Array 和 ArrayList 有何區(qū)別获列?
Array可以容納基本類型和對(duì)象,而ArrayList只能容納對(duì)象蛔垢。
Array是指定大小的击孩,而ArrayList大小是固定的。
Array沒有提供ArrayList那么多功能鹏漆,比如addAll巩梢、removeAll和iterator等。在 Queue 中 poll()和 remove()有什么區(qū)別艺玲?
poll() 和 remove() 都是從隊(duì)列中取出一個(gè)元素括蝠,但是 poll() 在獲取元素失敗的時(shí)候會(huì)返回空,但是 remove() 失敗的時(shí)候會(huì)拋出異常饭聚。哪些集合類是線程安全的忌警?
vector:就比arraylist多了個(gè)同步化機(jī)制(線程安全),因?yàn)樾瘦^低秒梳,現(xiàn)在已經(jīng)不太建議使用法绵。在web應(yīng)用中箕速,特別是前臺(tái)頁面,往往效率(頁面響應(yīng)速度)是優(yōu)先考慮的礼烈。
statck:堆棧類弧满,先進(jìn)后出。
hashtable:就比hashmap多了個(gè)線程安全此熬。
enumeration:枚舉庭呜,相當(dāng)于迭代器。迭代器 Iterator 是什么犀忱?
迭代器是一種設(shè)計(jì)模式募谎,它是一個(gè)對(duì)象,它可以遍歷并選擇序列中的對(duì)象阴汇,而開發(fā)人員不需要了解該序列的底層結(jié)構(gòu)数冬。迭代器通常被稱為“輕量級(jí)”對(duì)象,因?yàn)閯?chuàng)建它的代價(jià)小搀庶。Iterator 怎么使用拐纱?有什么特點(diǎn)?
Java中的Iterator功能比較簡(jiǎn)單哥倔,并且只能單向移動(dòng):
(1) 使用方法iterator()要求容器返回一個(gè)Iterator秸架。第一次調(diào)用Iterator的next()方法時(shí),它返回序列的第一個(gè)元素咆蒿。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承东抹。
(2) 使用next()獲得序列中的下一個(gè)元素。
(3) 使用hasNext()檢查序列中是否還有元素沃测。
(4) 使用remove()將迭代器新返回的元素刪除缭黔。
Iterator是Java迭代器最簡(jiǎn)單的實(shí)現(xiàn),為L(zhǎng)ist設(shè)計(jì)的ListIterator具有更多的功能蒂破,它可以從兩個(gè)方向遍歷List馏谨,也可以從List中插入和刪除元素。
Iterator 和 ListIterator 有什么區(qū)別附迷?
Iterator可用來遍歷Set和List集合惧互,但是ListIterator只能用來遍歷List。
Iterator對(duì)集合只能是前向遍歷挟秤,ListIterator既可以前向也可以后向。
ListIterator實(shí)現(xiàn)了Iterator接口抄伍,并包含其他的功能艘刚,比如:增加元素,替換元素截珍,獲取前一個(gè)和后一個(gè)元素的索引攀甚,等等箩朴。
三、多線程并行和并發(fā)有什么區(qū)別秋度?
并行是指兩個(gè)或者多個(gè)事件在同一時(shí)刻發(fā)生炸庞;而并發(fā)是指兩個(gè)或多個(gè)事件在同一時(shí)間間隔發(fā)生。
并行是在不同實(shí)體上的多個(gè)事件荚斯,并發(fā)是在同一實(shí)體上的多個(gè)事件埠居。
在一臺(tái)處理器上“同時(shí)”處理多個(gè)任務(wù),在多臺(tái)處理器上同時(shí)處理多個(gè)任務(wù)事期。如hadoop分布式集群滥壕。
所以并發(fā)編程的目標(biāo)是充分的利用處理器的每一個(gè)核,以達(dá)到最高的處理性能兽泣。線程和進(jìn)程的區(qū)別绎橘?
簡(jiǎn)而言之,進(jìn)程是程序運(yùn)行和資源分配的基本單位唠倦,一個(gè)程序至少有一個(gè)進(jìn)程称鳞,一個(gè)進(jìn)程至少有一個(gè)線程。進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元稠鼻,而多個(gè)線程共享內(nèi)存資源冈止,減少切換次數(shù),從而效率更高枷餐。線程是進(jìn)程的一個(gè)實(shí)體靶瘸,是cpu調(diào)度和分派的基本單位,是比程序更小的能獨(dú)立運(yùn)行的基本單位毛肋。同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行怨咪。守護(hù)線程是什么?
守護(hù)線程(即daemon thread)润匙,是個(gè)服務(wù)線程诗眨,準(zhǔn)確地來說就是服務(wù)其他的線程。創(chuàng)建線程有哪幾種方式孕讳?
①. 繼承Thread類創(chuàng)建線程類
定義Thread類的子類匠楚,并重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務(wù)厂财。因此把run()方法稱為執(zhí)行體芋簿。
創(chuàng)建Thread子類的實(shí)例,即創(chuàng)建了線程對(duì)象璃饱。
調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程与斤。
②. 通過Runnable接口創(chuàng)建線程類
定義runnable接口的實(shí)現(xiàn)類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體撩穿。
創(chuàng)建 Runnable實(shí)現(xiàn)類的實(shí)例磷支,并依此實(shí)例作為Thread的target來創(chuàng)建Thread對(duì)象,該Thread對(duì)象才是真正的線程對(duì)象食寡。
調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程雾狈。
③. 通過Callable和Future創(chuàng)建線程
創(chuàng)建Callable接口的實(shí)現(xiàn)類,并實(shí)現(xiàn)call()方法抵皱,該call()方法將作為線程執(zhí)行體善榛,并且有返回值。
創(chuàng)建Callable實(shí)現(xiàn)類的實(shí)例叨叙,使用FutureTask類來包裝Callable對(duì)象锭弊,該FutureTask對(duì)象封裝了該Callable對(duì)象的call()方法的返回值。
使用FutureTask對(duì)象作為Thread對(duì)象的target創(chuàng)建并啟動(dòng)新線程擂错。
調(diào)用FutureTask對(duì)象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值味滞。
- 說一下 runnable 和 callable 有什么區(qū)別?
有點(diǎn)深的問題了钮呀,也看出一個(gè)Java程序員學(xué)習(xí)知識(shí)的廣度剑鞍。
Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已爽醋;
Callable接口中的call()方法是有返回值的蚁署,是一個(gè)泛型,和Future蚂四、FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果光戈。
- 線程有哪些狀態(tài)?
線程通常都有五種狀態(tài)遂赠,創(chuàng)建久妆、就緒、運(yùn)行跷睦、阻塞和死亡筷弦。
創(chuàng)建狀態(tài)。在生成線程對(duì)象抑诸,并沒有調(diào)用該對(duì)象的start方法烂琴,這是線程處于創(chuàng)建狀態(tài)。
就緒狀態(tài)蜕乡。當(dāng)調(diào)用了線程對(duì)象的start方法之后奸绷,該線程就進(jìn)入了就緒狀態(tài),但是此時(shí)線程調(diào)度程序還沒有把該線程設(shè)置為當(dāng)前線程层玲,此時(shí)處于就緒狀態(tài)号醉。在線程運(yùn)行之后绒瘦,從等待或者睡眠中回來之后,也會(huì)處于就緒狀態(tài)扣癣。
運(yùn)行狀態(tài)。線程調(diào)度程序?qū)⑻幱诰途w狀態(tài)的線程設(shè)置為當(dāng)前線程憨降,此時(shí)線程就進(jìn)入了運(yùn)行狀態(tài)父虑,開始運(yùn)行run函數(shù)當(dāng)中的代碼。
阻塞狀態(tài)授药。線程正在運(yùn)行的時(shí)候士嚎,被暫停,通常是為了等待某個(gè)時(shí)間的發(fā)生(比如說某項(xiàng)資源就緒)之后再繼續(xù)運(yùn)行悔叽。sleep,suspend莱衩,wait等方法都可以導(dǎo)致線程阻塞。
死亡狀態(tài)娇澎。如果一個(gè)線程的run方法執(zhí)行結(jié)束或者調(diào)用stop方法后笨蚁,該線程就會(huì)死亡。對(duì)于已經(jīng)死亡的線程趟庄,無法再使用start方法令其進(jìn)入就緒
41. sleep() 和 wait() 有什么區(qū)別括细?
sleep():方法是線程類(Thread)的靜態(tài)方法,讓調(diào)用線程進(jìn)入睡眠狀態(tài)戚啥,讓出執(zhí)行機(jī)會(huì)給其他線程奋单,等到休眠時(shí)間結(jié)束后,線程進(jìn)入就緒狀態(tài)和其他線程一起競(jìng)爭(zhēng)cpu的執(zhí)行時(shí)間猫十。因?yàn)閟leep() 是static靜態(tài)的方法览濒,他不能改變對(duì)象的機(jī)鎖,當(dāng)一個(gè)synchronized塊中調(diào)用了sleep() 方法拖云,線程雖然進(jìn)入休眠贷笛,但是對(duì)象的機(jī)鎖沒有被釋放,其他線程依然無法訪問這個(gè)對(duì)象江兢。
wait():wait()是Object類的方法昨忆,當(dāng)一個(gè)線程執(zhí)行到wait方法時(shí),它就進(jìn)入到一個(gè)和該對(duì)象相關(guān)的等待池杉允,同時(shí)釋放對(duì)象的機(jī)鎖邑贴,使得其他線程能夠訪問,可以通過notify叔磷,notifyAll方法來喚醒等待的線程拢驾。
42. notify()和 notifyAll()有什么區(qū)別?
- 如果線程調(diào)用了對(duì)象的 wait()方法改基,那么線程便會(huì)處于該對(duì)象的等待池中繁疤,等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。
- 當(dāng)有線程調(diào)用了對(duì)象的 notifyAll()方法(喚醒所有 wait 線程)或 notify()方法(只隨機(jī)喚醒一個(gè) wait 線程),被喚醒的的線程便會(huì)進(jìn)入該對(duì)象的鎖池中稠腊,鎖池中的線程會(huì)去競(jìng)爭(zhēng)該對(duì)象鎖躁染。也就是說,調(diào)用了notify后只要一個(gè)線程會(huì)由等待池進(jìn)入鎖池架忌,而notifyAll會(huì)將該對(duì)象等待池內(nèi)的所有線程移動(dòng)到鎖池中吞彤,等待鎖競(jìng)爭(zhēng)。
- 優(yōu)先級(jí)高的線程競(jìng)爭(zhēng)到對(duì)象鎖的概率大叹放,假若某線程沒有競(jìng)爭(zhēng)到該對(duì)象鎖饰恕,它還會(huì)留在鎖池中,唯有線程再次調(diào)用 wait()方法井仰,它才會(huì)重新回到等待池中埋嵌。而競(jìng)爭(zhēng)到對(duì)象鎖的線程則繼續(xù)往下執(zhí)行,直到執(zhí)行完了 synchronized 代碼塊俱恶,它會(huì)釋放掉該對(duì)象鎖雹嗦,這時(shí)鎖池中的線程會(huì)繼續(xù)競(jìng)爭(zhēng)該對(duì)象鎖。
43. 線程的 run()和 start()有什么區(qū)別合是?
每個(gè)線程都是通過某個(gè)特定Thread對(duì)象所對(duì)應(yīng)的方法run()來完成其操作的俐银,方法run()稱為線程體。通過調(diào)用Thread類的start()方法來啟動(dòng)一個(gè)線程端仰。
start()方法來啟動(dòng)一個(gè)線程捶惜,真正實(shí)現(xiàn)了多線程運(yùn)行。這時(shí)無需等待run方法體代碼執(zhí)行完畢荔烧,可以直接繼續(xù)執(zhí)行下面的代碼吱七; 這時(shí)此線程是處于就緒狀態(tài), 并沒有運(yùn)行鹤竭。 然后通過此Thread類調(diào)用方法run()來完成其運(yùn)行狀態(tài)踊餐, 這里方法run()稱為線程體,它包含了要執(zhí)行的這個(gè)線程的內(nèi)容臀稚, Run方法運(yùn)行結(jié)束吝岭, 此線程終止。然后CPU再調(diào)度其它線程吧寺。
run()方法是在本線程里的窜管,只是線程里的一個(gè)函數(shù),而不是多線程的。 如果直接調(diào)用run(),其實(shí)就相當(dāng)于是調(diào)用了一個(gè)普通函數(shù)而已稚机,直接待用run()方法必須等待run()方法執(zhí)行完畢才能執(zhí)行下面的代碼幕帆,所以執(zhí)行路徑還是只有一條,根本就沒有線程的特征赖条,所以在多線程執(zhí)行時(shí)要使用start()方法而不是run()方法失乾。
44. 創(chuàng)建線程池有哪幾種方式常熙?
①. newFixedThreadPool(int nThreads)
創(chuàng)建一個(gè)固定長(zhǎng)度的線程池,每當(dāng)提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程碱茁,直到達(dá)到線程池的最大數(shù)量裸卫,這時(shí)線程規(guī)模將不再變化,當(dāng)線程發(fā)生未預(yù)期的錯(cuò)誤而結(jié)束時(shí)纽竣,線程池會(huì)補(bǔ)充一個(gè)新的線程彼城。
②. newCachedThreadPool()
創(chuàng)建一個(gè)可緩存的線程池,如果線程池的規(guī)模超過了處理需求退个,將自動(dòng)回收空閑線程,而當(dāng)需求增加時(shí)调炬,則可以自動(dòng)添加新線程语盈,線程池的規(guī)模不存在任何限制。
③. newSingleThreadExecutor()
這是一個(gè)單線程的Executor缰泡,它創(chuàng)建單個(gè)工作線程來執(zhí)行任務(wù)刀荒,如果這個(gè)線程異常結(jié)束,會(huì)創(chuàng)建一個(gè)新的來替代它棘钞;它的特點(diǎn)是能確保依照任務(wù)在隊(duì)列中的順序來串行執(zhí)行缠借。
④. newScheduledThreadPool(int corePoolSize)
創(chuàng)建了一個(gè)固定長(zhǎng)度的線程池,而且以延遲或定時(shí)的方式來執(zhí)行任務(wù)宜猜,類似于Timer泼返。
45. 線程池都有哪些狀態(tài)?
線程池有5種狀態(tài):Running姨拥、ShutDown绅喉、Stop、Tidying叫乌、Terminated柴罐。
線程池各個(gè)狀態(tài)切換框架圖:
?
46. 線程池中 submit()和 execute()方法有什么區(qū)別?
- 接收的參數(shù)不一樣
- submit有返回值憨奸,而execute沒有
- submit方便Exception處理
47. 在 java 程序中怎么保證多線程的運(yùn)行安全革屠?
線程安全在三個(gè)方面體現(xiàn):
- 原子性:提供互斥訪問,同一時(shí)刻只能有一個(gè)線程對(duì)數(shù)據(jù)進(jìn)行操作排宰,(atomic,synchronized)似芝;
- 可見性:一個(gè)線程對(duì)主內(nèi)存的修改可以及時(shí)地被其他線程看到,(synchronized,volatile)板甘;
- 有序性:一個(gè)線程觀察其他線程中的指令執(zhí)行順序国觉,由于指令重排序,該觀察結(jié)果一般雜亂無序虾啦,(happens-before原則)麻诀。
48. 多線程鎖的升級(jí)原理是什么痕寓?
在Java中,鎖共有4種狀態(tài)蝇闭,級(jí)別從低到高依次為:無狀態(tài)鎖呻率,偏向鎖,輕量級(jí)鎖和重量級(jí)鎖狀態(tài)呻引,這幾個(gè)狀態(tài)會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)礼仗。鎖可以升級(jí)但不能降級(jí)。
鎖升級(jí)的圖示過程:
?
49. 什么是死鎖逻悠?
死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過程中元践,由于競(jìng)爭(zhēng)資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用童谒,它們都將無法推進(jìn)下去单旁。此時(shí)稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程饥伊。是操作系統(tǒng)層面的一個(gè)錯(cuò)誤象浑,是進(jìn)程死鎖的簡(jiǎn)稱,最早在 1965 年由 Dijkstra 在研究銀行家算法時(shí)提出的琅豆,它是計(jì)算機(jī)操作系統(tǒng)乃至整個(gè)并發(fā)程序設(shè)計(jì)領(lǐng)域最難處理的問題之一辽俗。
50. 怎么防止死鎖辨泳?
死鎖的四個(gè)必要條件:
- 互斥條件:進(jìn)程對(duì)所分配到的資源不允許其他進(jìn)程進(jìn)行訪問,若其他進(jìn)程訪問該資源,只能等待项乒,直至占有該資源的進(jìn)程使用完成后釋放該資源
- 請(qǐng)求和保持條件:進(jìn)程獲得一定的資源之后聋呢,又對(duì)其他資源發(fā)出請(qǐng)求猜揪,但是該資源可能被其他進(jìn)程占有麸澜,此事請(qǐng)求阻塞,但又對(duì)自己獲得的資源保持不放
- 不可剝奪條件:是指進(jìn)程已獲得的資源翼雀,在未完成使用之前饱苟,不可被剝奪,只能在使用完后自己釋放
- 環(huán)路等待條件:是指進(jìn)程發(fā)生死鎖后狼渊,若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
這四個(gè)條件是死鎖的必要條件箱熬,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立狈邑,而只要上述條件之 一不滿足城须,就不會(huì)發(fā)生死鎖。
理解了死鎖的原因米苹,尤其是產(chǎn)生死鎖的四個(gè)必要條件糕伐,就可以最大可能地避免、預(yù)防和 解除死鎖蘸嘶。
所以良瞧,在系統(tǒng)設(shè)計(jì)陪汽、進(jìn)程調(diào)度等方面注意如何不讓這四個(gè)必要條件成立,如何確 定資源的合理分配算法褥蚯,避免進(jìn)程永久占據(jù)系統(tǒng)資源挚冤。
此外,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源赞庶。因此训挡,對(duì)資源的分配要給予合理的規(guī)劃。
- ThreadLocal 是什么歧强?有哪些使用場(chǎng)景澜薄?
線程局部變量是局限于線程內(nèi)部的變量,屬于線程自身所有摊册,不在多個(gè)線程間共享肤京。Java提供ThreadLocal類來支持線程局部變量,是一種實(shí)現(xiàn)線程安全的方式丧靡。但是在管理環(huán)境下(如 web 服務(wù)器)使用線程局部變量的時(shí)候要特別小心,在這種情況下籽暇,工作線程的生命周期比任何應(yīng)用變量的生命周期都要長(zhǎng)温治。任何線程局部變量一旦在工作完成后沒有釋放,Java 應(yīng)用就存在內(nèi)存泄露的風(fēng)險(xiǎn)戒悠。
52.說一下 synchronized 底層實(shí)現(xiàn)原理熬荆?
synchronized可以保證方法或者代碼塊在運(yùn)行時(shí),同一時(shí)刻只有一個(gè)方法可以進(jìn)入到臨界區(qū)绸狐,同時(shí)它還可以保證共享變量的內(nèi)存可見性卤恳。
Java中每一個(gè)對(duì)象都可以作為鎖,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ):
普通同步方法寒矿,鎖是當(dāng)前實(shí)例對(duì)象
靜態(tài)同步方法突琳,鎖是當(dāng)前類的class對(duì)象
同步方法塊,鎖是括號(hào)里面的對(duì)象
synchronized 和 volatile 的區(qū)別是什么符相?
volatile本質(zhì)是在告訴jvm當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的拆融,需要從主存中讀取啊终; synchronized則是鎖定當(dāng)前變量镜豹,只有當(dāng)前線程可以訪問該變量,其他線程被阻塞住蓝牲。
volatile僅能使用在變量級(jí)別趟脂;synchronized則可以使用在變量、方法例衍、和類級(jí)別的昔期。
volatile僅能實(shí)現(xiàn)變量的修改可見性已卸,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性镇眷。
volatile不會(huì)造成線程的阻塞咬最;synchronized可能會(huì)造成線程的阻塞。
volatile標(biāo)記的變量不會(huì)被編譯器優(yōu)化欠动;synchronized標(biāo)記的變量可以被編譯器優(yōu)化永乌。synchronized 和 Lock 有什么區(qū)別?
首先synchronized是java內(nèi)置關(guān)鍵字具伍,在jvm層面翅雏,Lock是個(gè)java類;
synchronized無法判斷是否獲取鎖的狀態(tài)人芽,Lock可以判斷是否獲取到鎖望几;
synchronized會(huì)自動(dòng)釋放鎖(a 線程執(zhí)行完同步代碼會(huì)釋放鎖 ;b 線程執(zhí)行過程中發(fā)生異常會(huì)釋放鎖)萤厅,Lock需在finally中手工釋放鎖(unlock()方法釋放鎖)橄抹,否則容易造成線程死鎖;
用synchronized關(guān)鍵字的兩個(gè)線程1和線程2惕味,如果當(dāng)前線程1獲得鎖楼誓,線程2線程等待。如果線程1阻塞名挥,線程2則會(huì)一直等待下去疟羹,而Lock鎖就不一定會(huì)等待下去,如果嘗試獲取不到鎖禀倔,線程可以不用一直等待就結(jié)束了榄融;
synchronized的鎖可重入、不可中斷救湖、非公平愧杯,而Lock鎖可重入、可判斷鞋既、可公平(兩者皆可)民效;
Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題涛救。synchronized 和 ReentrantLock 區(qū)別是什么畏邢?
synchronized是和if、else检吆、for舒萎、while一樣的關(guān)鍵字,ReentrantLock是類蹭沛,這是二者的本質(zhì)區(qū)別臂寝。既然ReentrantLock是類章鲤,那么它就提供了比synchronized更多更靈活的特性,可以被繼承咆贬、可以有方法败徊、可以有各種各樣的類變量,ReentrantLock比synchronized的擴(kuò)展性體現(xiàn)在幾點(diǎn)上:
ReentrantLock可以對(duì)獲取鎖的等待時(shí)間進(jìn)行設(shè)置掏缎,這樣就避免了死鎖
ReentrantLock可以獲取各種鎖的信息
ReentrantLock可以靈活地實(shí)現(xiàn)多路通知
另外皱蹦,二者的鎖機(jī)制其實(shí)也是不一樣的:ReentrantLock底層調(diào)用的是Unsafe的park方法加鎖,synchronized操作的應(yīng)該是對(duì)象頭中mark word眷蜈。
- 說一下 atomic 的原理沪哺?
Atomic包中的類基本的特性就是在多線程環(huán)境下,當(dāng)有多個(gè)線程同時(shí)對(duì)單個(gè)(包括基本類型及引用類型)變量進(jìn)行操作時(shí)酌儒,具有排他性辜妓,即當(dāng)多個(gè)線程同時(shí)對(duì)該變量的值進(jìn)行更新時(shí),僅有一個(gè)線程能成功忌怎,而未成功的線程可以向自旋鎖一樣籍滴,繼續(xù)嘗試,一直等到執(zhí)行成功榴啸。
Atomic系列的類中的核心方法都會(huì)調(diào)用unsafe類中的幾個(gè)本地方法孽惰。我們需要先知道一個(gè)東西就是Unsafe類,全名為:sun.misc.Unsafe插掂,這個(gè)類包含了大量的對(duì)C代碼的操作灰瞻,包括很多直接內(nèi)存分配以及原子操作的調(diào)用腥例,而它之所以標(biāo)記為非安全的辅甥,是告訴你這個(gè)里面大量的方法調(diào)用都會(huì)存在安全隱患,需要小心使用燎竖,否則會(huì)導(dǎo)致嚴(yán)重的后果璃弄,例如在通過unsafe分配內(nèi)存的時(shí)候,如果自己指定某些區(qū)域可能會(huì)導(dǎo)致一些類似C++一樣的指針越界到其他進(jìn)程的問題构回。
四夏块、反射
- 什么是反射?
反射主要是指程序可以訪問纤掸、檢測(cè)和修改它本身狀態(tài)或行為的一種能力
Java反射:
在Java運(yùn)行時(shí)環(huán)境中脐供,對(duì)于任意一個(gè)類,能否知道這個(gè)類有哪些屬性和方法借跪?對(duì)于任意一個(gè)對(duì)象政己,能否調(diào)用它的任意一個(gè)方法
Java反射機(jī)制主要提供了以下功能:
在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類。
在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象掏愁。
在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法歇由。
在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法卵牍。
- 什么是 java 序列化?什么情況下需要序列化沦泌?
簡(jiǎn)單說就是為了保存在內(nèi)存中的各種對(duì)象的狀態(tài)(也就是實(shí)例變量糊昙,不是方法),并且可以把保存的對(duì)象狀態(tài)再讀出來谢谦。雖然你可以用你自己的各種各樣的方法來保存object states释牺,但是Java給你提供一種應(yīng)該比你自己好的保存對(duì)象狀態(tài)的機(jī)制,那就是序列化他宛。
什么情況下需要序列化:
a)當(dāng)你想把的內(nèi)存中的對(duì)象狀態(tài)保存到一個(gè)文件中或者數(shù)據(jù)庫中時(shí)候船侧;
b)當(dāng)你想用套接字在網(wǎng)絡(luò)上傳送對(duì)象的時(shí)候;
c)當(dāng)你想通過RMI傳輸對(duì)象的時(shí)候厅各;
- 動(dòng)態(tài)代理是什么镜撩?有哪些應(yīng)用?
動(dòng)態(tài)代理:
當(dāng)想要給實(shí)現(xiàn)了某個(gè)接口的類中的方法队塘,加一些額外的處理袁梗。比如說加日志,加事務(wù)等憔古≌诹可以給這個(gè)類創(chuàng)建一個(gè)代理,故名思議就是創(chuàng)建一個(gè)新的類鸿市,這個(gè)類不僅包含原來類方法的功能锯梁,而且還在原來的基礎(chǔ)上添加了額外處理的新類。這個(gè)代理類并不是定義好的焰情,是動(dòng)態(tài)生成的陌凳。具有解耦意義,靈活内舟,擴(kuò)展性強(qiáng)合敦。
動(dòng)態(tài)代理的應(yīng)用:
Spring的AOP
加事務(wù)
加權(quán)限
加日志
- 怎么實(shí)現(xiàn)動(dòng)態(tài)代理?
首先必須定義一個(gè)接口验游,還要有一個(gè)InvocationHandler(將實(shí)現(xiàn)接口的類的對(duì)象傳遞給它)處理類充岛。再有一個(gè)工具類Proxy(習(xí)慣性將其稱為代理類,因?yàn)檎{(diào)用他的newInstance()可以產(chǎn)生代理對(duì)象,其實(shí)他只是一個(gè)產(chǎn)生代理對(duì)象的工具類)耕蝉。利用到InvocationHandler崔梗,拼接代理類源碼,將其編譯生成代理類的二進(jìn)制碼垒在,利用加載器加載蒜魄,并將其實(shí)例化產(chǎn)生代理對(duì)象,最后返回。
五权悟、對(duì)象拷貝
61. 為什么要使用克略彝酢?
想對(duì)一個(gè)對(duì)象進(jìn)行處理峦阁,又想保留原有的數(shù)據(jù)進(jìn)行接下來的操作谦铃,就需要克隆了,Java語言中克隆針對(duì)的是類的實(shí)例榔昔。
62. 如何實(shí)現(xiàn)對(duì)象克戮匀颉?
有兩種方式:
1). 實(shí)現(xiàn)Cloneable接口并重寫Object類中的clone()方法撒会;
2). 實(shí)現(xiàn)Serializable接口嘹朗,通過對(duì)象的序列化和反序列化實(shí)現(xiàn)克隆,可以實(shí)現(xiàn)真正的深度克隆诵肛,代碼如下:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class MyUtil {
private MyUtil() {
throw new AssertionError();
}
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
return (T) ois.readObject();
// 說明:調(diào)用ByteArrayInputStream或ByteArrayOutputStream對(duì)象的close方法沒有任何意義
// 這兩個(gè)基于內(nèi)存的流只要垃圾回收器清理對(duì)象就能夠釋放資源屹培,這一點(diǎn)不同于對(duì)外部資源(如文件流)的釋放
}
}
下面是測(cè)試代碼:
import java.io.Serializable;
/**
* 人類
* @author nnngu
*
*/
class Person implements Serializable {
private static final long serialVersionUID = -9102017020286042305L;
private String name; // 姓名
private int age; // 年齡
private Car car; // 座駕
public Person(String name, int age, Car car) {
this.name = name;
this.age = age;
this.car = car;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
}
/**
* 小汽車類
* @author nnngu
*
*/
class Car implements Serializable {
private static final long serialVersionUID = -5713945027627603702L;
private String brand; // 品牌
private int maxSpeed; // 最高時(shí)速
public Car(String brand, int maxSpeed) {
this.brand = brand;
this.maxSpeed = maxSpeed;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getMaxSpeed() {
return maxSpeed;
}
public void setMaxSpeed(int maxSpeed) {
this.maxSpeed = maxSpeed;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
}
}
class CloneTest {
public static void main(String[] args) {
try {
Person p1 = new Person("郭靖", 33, new Car("Benz", 300));
Person p2 = MyUtil.clone(p1); // 深度克隆
p2.getCar().setBrand("BYD");
// 修改克隆的Person對(duì)象p2關(guān)聯(lián)的汽車對(duì)象的品牌屬性
// 原來的Person對(duì)象p1關(guān)聯(lián)的汽車不會(huì)受到任何影響
// 因?yàn)樵诳寺erson對(duì)象時(shí)其關(guān)聯(lián)的汽車對(duì)象也被克隆了
System.out.println(p1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意:基于序列化和反序列化實(shí)現(xiàn)的克隆不僅僅是深度克隆,更重要的是通過泛型限定怔檩,可以檢查出要克隆的對(duì)象是否支持序列化褪秀,這項(xiàng)檢查是編譯器完成的,不是在運(yùn)行時(shí)拋出異常薛训,這種是方案明顯優(yōu)于使用Object類的clone方法克隆對(duì)象媒吗。讓問題在編譯的時(shí)候暴露出來總是好過把問題留到運(yùn)行時(shí)。
63. 深拷貝和淺拷貝區(qū)別是什么乙埃?
- 淺拷貝只是復(fù)制了對(duì)象的引用地址闸英,兩個(gè)對(duì)象指向同一個(gè)內(nèi)存地址,所以修改其中任意的值介袜,另一個(gè)值都會(huì)隨之變化甫何,這就是淺拷貝(例:assign())
- 深拷貝是將對(duì)象及值復(fù)制過來,兩個(gè)對(duì)象修改其中任意的值另一個(gè)值不會(huì)改變米酬,這就是深拷貝(例:JSON.parse()和JSON.stringify()沛豌,但是此方法無法復(fù)制函數(shù)類型)
session 和 cookie 有什么區(qū)別趋箩?
由于HTTP協(xié)議是無狀態(tài)的協(xié)議赃额,所以服務(wù)端需要記錄用戶的狀態(tài)時(shí),就需要用某種機(jī)制來識(shí)具體的用戶叫确,這個(gè)機(jī)制就是Session.典型的場(chǎng)景比如購物車跳芳,當(dāng)你點(diǎn)擊下單按鈕時(shí),由于HTTP協(xié)議無狀態(tài)竹勉,所以并不知道是哪個(gè)用戶操作的飞盆,所以服務(wù)端要為特定的用戶創(chuàng)建了特定的Session,用用于標(biāo)識(shí)這個(gè)用戶,并且跟蹤用戶吓歇,這樣才知道購物車?yán)锩嬗袔妆緯跛_@個(gè)Session是保存在服務(wù)端的,有一個(gè)唯一標(biāo)識(shí)城看。在服務(wù)端保存Session的方法很多女气,內(nèi)存、數(shù)據(jù)庫测柠、文件都有炼鞠。集群的時(shí)候也要考慮Session的轉(zhuǎn)移,在大型的網(wǎng)站轰胁,一般會(huì)有專門的Session服務(wù)器集群谒主,用來保存用戶會(huì)話,這個(gè)時(shí)候 Session 信息都是放在內(nèi)存的赃阀,使用一些緩存服務(wù)比如Memcached之類的來放 Session霎肯。
思考一下服務(wù)端如何識(shí)別特定的客戶?這個(gè)時(shí)候Cookie就登場(chǎng)了榛斯。每次HTTP請(qǐng)求的時(shí)候姿现,客戶端都會(huì)發(fā)送相應(yīng)的Cookie信息到服務(wù)端。實(shí)際上大多數(shù)的應(yīng)用都是用 Cookie 來實(shí)現(xiàn)Session跟蹤的肖抱,第一次創(chuàng)建Session的時(shí)候备典,服務(wù)端會(huì)在HTTP協(xié)議中告訴客戶端,需要在 Cookie 里面記錄一個(gè)Session ID意述,以后每次請(qǐng)求把這個(gè)會(huì)話ID發(fā)送到服務(wù)器提佣,我就知道你是誰了。有人問荤崇,如果客戶端的瀏覽器禁用了 Cookie 怎么辦拌屏?一般這種情況下,會(huì)使用一種叫做URL重寫的技術(shù)來進(jìn)行會(huì)話跟蹤术荤,即每次HTTP交互倚喂,URL后面都會(huì)被附加上一個(gè)諸如 sid=xxxxx 這樣的參數(shù),服務(wù)端據(jù)此來識(shí)別用戶瓣戚。
Cookie其實(shí)還可以用在一些方便用戶的場(chǎng)景下端圈,設(shè)想你某次登陸過一個(gè)網(wǎng)站,下次登錄的時(shí)候不想再次輸入賬號(hào)了子库,怎么辦舱权?這個(gè)信息可以寫到Cookie里面,訪問網(wǎng)站的時(shí)候仑嗅,網(wǎng)站頁面的腳本可以讀取這個(gè)信息宴倍,就自動(dòng)幫你把用戶名給填了张症,能夠方便一下用戶。這也是Cookie名稱的由來鸵贬,給用戶的一點(diǎn)甜頭俗他。所以,總結(jié)一下:Session是在服務(wù)端保存的一個(gè)數(shù)據(jù)結(jié)構(gòu)阔逼,用來跟蹤用戶的狀態(tài)拯辙,這個(gè)數(shù)據(jù)可以保存在集群、數(shù)據(jù)庫颜价、文件中涯保;Cookie是客戶端保存用戶信息的一種機(jī)制,用來記錄用戶的一些信息周伦,也是實(shí)現(xiàn)Session的一種方式夕春。
說一下 session 的工作原理?
其實(shí)session是一個(gè)存在服務(wù)器上的類似于一個(gè)散列表格的文件专挪。里面存有我們需要的信息及志,在我們需要用的時(shí)候可以從里面取出來。類似于一個(gè)大號(hào)的map吧寨腔,里面的鍵存儲(chǔ)的是用戶的sessionid速侈,用戶向服務(wù)器發(fā)送請(qǐng)求的時(shí)候會(huì)帶上這個(gè)sessionid。這時(shí)就可以從中取出對(duì)應(yīng)的值了迫卢。如果客戶端禁止 cookie 能實(shí)現(xiàn) session 還能用嗎倚搬?
Cookie與 Session,一般認(rèn)為是兩個(gè)獨(dú)立的東西乾蛤,Session采用的是在服務(wù)器端保持狀態(tài)的方案每界,而Cookie采用的是在客戶端保持狀態(tài)的方案。但為什么禁用Cookie就不能得到Session呢家卖?因?yàn)镾ession是用Session ID來確定當(dāng)前對(duì)話所對(duì)應(yīng)的服務(wù)器Session眨层,而Session ID是通過Cookie來傳遞的,禁用Cookie相當(dāng)于失去了Session ID上荡,也就得不到Session了趴樱。
假定用戶關(guān)閉Cookie的情況下使用Session,其實(shí)現(xiàn)途徑有以下幾種:
設(shè)置php.ini配置文件中的“session.use_trans_sid = 1”酪捡,或者編譯時(shí)打開打開了“--enable-trans-sid”選項(xiàng)叁征,讓PHP自動(dòng)跨頁傳遞Session ID。
手動(dòng)通過URL傳值沛善、隱藏表單傳遞Session ID航揉。
用文件塞祈、數(shù)據(jù)庫等形式保存Session ID金刁,在跨頁過程中手動(dòng)調(diào)用帅涂。
如何避免 sql 注入?
PreparedStatement(簡(jiǎn)單又有效的方法)
使用正則表達(dá)式過濾傳入的參數(shù)
字符串過濾
JSP中調(diào)用該函數(shù)檢查是否包函非法字符
JSP頁面判斷代碼
- 什么是 XSS 攻擊尤蛮,如何避免媳友?
XSS攻擊又稱CSS,全稱Cross Site Script (跨站腳本攻擊),其原理是攻擊者向有XSS漏洞的網(wǎng)站中輸入惡意的 HTML 代碼产捞,當(dāng)用戶瀏覽該網(wǎng)站時(shí)醇锚,這段 HTML 代碼會(huì)自動(dòng)執(zhí)行,從而達(dá)到攻擊的目的坯临。XSS 攻擊類似于 SQL 注入攻擊焊唬,SQL注入攻擊中以SQL語句作為用戶輸入,從而達(dá)到查詢/修改/刪除數(shù)據(jù)的目的看靠,而在xss攻擊中赶促,通過插入惡意腳本,實(shí)現(xiàn)對(duì)用戶游覽器的控制挟炬,獲取用戶的一些信息鸥滨。 XSS是 Web 程序中常見的漏洞,XSS 屬于被動(dòng)式且用于客戶端的攻擊方式谤祖。
XSS防范的總體思路是:對(duì)輸入(和URL參數(shù))進(jìn)行過濾婿滓,對(duì)輸出進(jìn)行編碼际跪。
- 什么是 CSRF 攻擊棒掠,如何避免?
CSRF(Cross-site request forgery)也被稱為 one-click attack或者 session riding茉稠,中文全稱是叫跨站請(qǐng)求偽造额湘。一般來說秕铛,攻擊者通過偽造用戶的瀏覽器的請(qǐng)求,向訪問一個(gè)用戶自己曾經(jīng)認(rèn)證訪問過的網(wǎng)站發(fā)送出去缩挑,使目標(biāo)網(wǎng)站接收并誤以為是用戶的真實(shí)操作而去執(zhí)行命令但两。常用于盜取賬號(hào)、轉(zhuǎn)賬供置、發(fā)送虛假消息等谨湘。攻擊者利用網(wǎng)站對(duì)請(qǐng)求的驗(yàn)證漏洞而實(shí)現(xiàn)這樣的攻擊行為,網(wǎng)站能夠確認(rèn)請(qǐng)求來源于用戶的瀏覽器芥丧,卻不能驗(yàn)證請(qǐng)求是否源于用戶的真實(shí)意愿下的操作行為紧阔。
如何避免:
- 驗(yàn)證 HTTP Referer 字段
HTTP頭中的Referer字段記錄了該 HTTP 請(qǐng)求的來源地址。在通常情況下续担,訪問一個(gè)安全受限頁面的請(qǐng)求來自于同一個(gè)網(wǎng)站擅耽,而如果黑客要對(duì)其實(shí)施 CSRF
攻擊,他一般只能在他自己的網(wǎng)站構(gòu)造請(qǐng)求物遇。因此乖仇,可以通過驗(yàn)證Referer值來防御CSRF 攻擊憾儒。
- 使用驗(yàn)證碼
關(guān)鍵操作頁面加上驗(yàn)證碼,后臺(tái)收到請(qǐng)求后通過判斷驗(yàn)證碼可以防御CSRF乃沙。但這種方法對(duì)用戶不太友好起趾。
- 在請(qǐng)求地址中添加token并驗(yàn)證
CSRF 攻擊之所以能夠成功,是因?yàn)楹诳涂梢酝耆珎卧煊脩舻恼?qǐng)求警儒,該請(qǐng)求中所有的用戶驗(yàn)證信息都是存在于cookie中训裆,因此黑客可以在不知道這些驗(yàn)證信息的情況下直接利用用戶自己的cookie 來通過安全驗(yàn)證。要抵御 CSRF蜀铲,關(guān)鍵在于在請(qǐng)求中放入黑客所不能偽造的信息边琉,并且該信息不存在于 cookie 之中〖侨埃可以在 HTTP 請(qǐng)求中以參數(shù)的形式加入一個(gè)隨機(jī)產(chǎn)生的 token艺骂,并在服務(wù)器端建立一個(gè)攔截器來驗(yàn)證這個(gè) token,如果請(qǐng)求中沒有token或者 token 內(nèi)容不正確隆夯,則認(rèn)為可能是 CSRF 攻擊而拒絕該請(qǐng)求钳恕。這種方法要比檢查 Referer 要安全一些,token 可以在用戶登陸后產(chǎn)生并放于session之中蹄衷,然后在每次請(qǐng)求時(shí)把token 從 session 中拿出忧额,與請(qǐng)求中的 token 進(jìn)行比對(duì),但這種方法的難點(diǎn)在于如何把 token 以參數(shù)的形式加入請(qǐng)求愧口。
對(duì)于 GET 請(qǐng)求睦番,token 將附在請(qǐng)求地址之后,這樣 URL 就變成 http://url?csrftoken=tokenvalue耍属。
而對(duì)于 POST 請(qǐng)求來說托嚣,要在 form 的最后加上 <input type="hidden" name="csrftoken" value="tokenvalue"/>,這樣就把token以參數(shù)的形式加入請(qǐng)求了厚骗。
- 在HTTP 頭中自定義屬性并驗(yàn)證
這種方法也是使用 token 并進(jìn)行驗(yàn)證示启,和上一種方法不同的是,這里并不是把 token 以參數(shù)的形式置于 HTTP 請(qǐng)求之中领舰,而是把它放到 HTTP 頭中自定義的屬性里夫嗓。通過 XMLHttpRequest 這個(gè)類,可以一次性給所有該類請(qǐng)求加上 csrftoken 這個(gè) HTTP 頭屬性冲秽,并把 token 值放入其中舍咖。這樣解決了上種方法在請(qǐng)求中加入 token 的不便,同時(shí)锉桑,通過 XMLHttpRequest 請(qǐng)求的地址不會(huì)被記錄到瀏覽器的地址欄排霉,也不用擔(dān)心 token 會(huì)透過 Referer 泄露到其他網(wǎng)站中去。
七民轴、異常
throw 和 throws 的區(qū)別攻柠?
throws是用來聲明一個(gè)方法可能拋出的所有異常信息球订,throws是將異常聲明但是不處理,而是將異常往上傳辙诞,誰調(diào)用我就交給誰處理辙售。而throw則是指拋出的一個(gè)具體的異常類型轻抱。final飞涂、finally、finalize 有什么區(qū)別祈搜?
final可以修飾類较店、變量、方法容燕,修飾類表示該類不能被繼承梁呈、修飾方法表示該方法不能被重寫、修飾變量表示該變量是一個(gè)常量不能被重新賦值蘸秘。
finally一般作用在try-catch代碼塊中官卡,在處理異常的時(shí)候,通常我們將一定要執(zhí)行的代碼方法finally代碼塊中醋虏,表示不管是否出現(xiàn)異常寻咒,該代碼塊都會(huì)執(zhí)行,一般用來存放一些關(guān)閉資源的代碼颈嚼。
finalize是一個(gè)方法毛秘,屬于Object類的一個(gè)方法,而Object類是所有類的父類阻课,該方法一般由垃圾回收器來調(diào)用叫挟,當(dāng)我們調(diào)用System的gc()方法的時(shí)候,由垃圾回收器調(diào)用finalize(),回收垃圾限煞。try-catch-finally 中哪個(gè)部分可以省略抹恳?
答:catch 可以省略
原因:
更為嚴(yán)格的說法其實(shí)是:try只適合處理運(yùn)行時(shí)異常,try+catch適合處理運(yùn)行時(shí)異常+普通異常署驻。也就是說适秩,如果你只用try去處理普通異常卻不加以catch處理,編譯是通不過的硕舆,因?yàn)榫幾g器硬性規(guī)定秽荞,普通異常如果選擇捕獲,則必須用catch顯示聲明以便進(jìn)一步處理抚官。而運(yùn)行時(shí)異常在編譯時(shí)沒有如此規(guī)定扬跋,所以catch可以省略,你加上catch編譯器也覺得無可厚非凌节。
理論上钦听,編譯器看任何代碼都不順眼洒试,都覺得可能有潛在的問題,所以你即使對(duì)所有代碼加上try朴上,代碼在運(yùn)行期時(shí)也只不過是在正常運(yùn)行的基礎(chǔ)上加一層皮垒棋。但是你一旦對(duì)一段代碼加上try,就等于顯示地承諾編譯器痪宰,對(duì)這段代碼可能拋出的異常進(jìn)行捕獲而非向上拋出處理叼架。如果是普通異常,編譯器要求必須用catch捕獲以便進(jìn)一步處理衣撬;如果運(yùn)行時(shí)異常乖订,捕獲然后丟棄并且+finally掃尾處理,或者加上catch捕獲以便進(jìn)一步處理具练。
至于加上finally乍构,則是在不管有沒捕獲異常,都要進(jìn)行的“掃尾”處理扛点。
- try-catch-finally 中哥遮,如果 catch 中 return 了,finally 還會(huì)執(zhí)行嗎陵究?
答:會(huì)執(zhí)行眠饮,在 return 前執(zhí)行。
代碼示例1:
/*
* java面試題--如果catch里面有return語句畔乙,finally里面的代碼還會(huì)執(zhí)行嗎君仆?
*/
public class FinallyDemo2 {
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
/*
* return a 在程序執(zhí)行到這一步的時(shí)候,這里不是return a 而是 return 30牲距;這個(gè)返回路徑就形成了
* 但是呢返咱,它發(fā)現(xiàn)后面還有finally,所以繼續(xù)執(zhí)行finally的內(nèi)容牍鞠,a=40
* 再次回到以前的路徑,繼續(xù)走return 30咖摹,形成返回路徑之后,這里的a就不是a變量了难述,而是常量30
*/
} finally {
a = 40;
}
// return a;
}
}
執(zhí)行結(jié)果:30
package com.java_02;
/*
* java面試題--如果catch里面有return語句萤晴,finally里面的代碼還會(huì)執(zhí)行嗎?
*/
public class FinallyDemo2 {
public static void main(String[] args) {
System.out.println(getInt());
}
public static int getInt() {
int a = 10;
try {
System.out.println(a / 0);
a = 20;
} catch (ArithmeticException e) {
a = 30;
return a;
/*
* return a 在程序執(zhí)行到這一步的時(shí)候胁后,這里不是return a 而是 return 30店读;這個(gè)返回路徑就形成了
* 但是呢,它發(fā)現(xiàn)后面還有finally攀芯,所以繼續(xù)執(zhí)行finally的內(nèi)容屯断,a=40
* 再次回到以前的路徑,繼續(xù)走return 30,形成返回路徑之后,這里的a就不是a變量了殖演,而是常量30
*/
} finally {
a = 40;
return a; //如果這樣氧秘,就又重新形成了一條返回路徑,由于只能通過1個(gè)return返回趴久,所以這里直接返回40
}
// return a;
}
}
執(zhí)行結(jié)果:40
常見的異常類有哪些丸相?
- NullPointerException:當(dāng)應(yīng)用程序試圖訪問空對(duì)象時(shí),則拋出該異常彼棍。
- SQLException:提供關(guān)于數(shù)據(jù)庫訪問錯(cuò)誤或其他錯(cuò)誤信息的異常灭忠。
- IndexOutOfBoundsException:指示某排序索引(例如對(duì)數(shù)組、字符串或向量的排序)超出范圍時(shí)拋出滥酥。
- NumberFormatException:當(dāng)應(yīng)用程序試圖將字符串轉(zhuǎn)換成一種數(shù)值類型更舞,但該字符串不能轉(zhuǎn)換為適當(dāng)格式時(shí)畦幢,拋出該異常坎吻。
- FileNotFoundException:當(dāng)試圖打開指定路徑名表示的文件失敗時(shí),拋出此異常宇葱。
- IOException:當(dāng)發(fā)生某種I/O異常時(shí)瘦真,拋出此異常。此類是失敗或中斷的I/O操作生成的異常的通用類黍瞧。
- ClassCastException:當(dāng)試圖將對(duì)象強(qiáng)制轉(zhuǎn)換為不是實(shí)例的子類時(shí)诸尽,拋出該異常。
- ArrayStoreException:試圖將錯(cuò)誤類型的對(duì)象存儲(chǔ)到一個(gè)對(duì)象數(shù)組時(shí)拋出的異常印颤。
- IllegalArgumentException:拋出的異常表明向方法傳遞了一個(gè)不合法或不正確的參數(shù)您机。
- ArithmeticException:當(dāng)出現(xiàn)異常的運(yùn)算條件時(shí),拋出此異常年局。例如际看,一個(gè)整數(shù)“除以零”時(shí),拋出此類的一個(gè)實(shí)例矢否。
- NegativeArraySizeException:如果應(yīng)用程序試圖創(chuàng)建大小為負(fù)的數(shù)組仲闽,則拋出該異常。
- NoSuchMethodException:無法找到某一特定方法時(shí)僵朗,拋出該異常赖欣。
- SecurityException:由安全管理器拋出的異常,指示存在安全侵犯验庙。
- UnsupportedOperationException:當(dāng)不支持請(qǐng)求的操作時(shí)顶吮,拋出該異常。
- RuntimeExceptionRuntimeException:是那些可能在Java虛擬機(jī)正常運(yùn)行期間拋出的異常的超類粪薛。
八悴了、網(wǎng)絡(luò)
79. http 響應(yīng)碼 301 和 302 代表的是什么?有什么區(qū)別?
答:301让禀,302 都是HTTP狀態(tài)的編碼挑社,都代表著某個(gè)URL發(fā)生了轉(zhuǎn)移。
**區(qū)別: **
- 301 redirect: 301 代表永久性轉(zhuǎn)移(Permanently Moved)巡揍。
- 302 redirect: 302 代表暫時(shí)性轉(zhuǎn)移(Temporarily Moved )痛阻。
80. forward 和 redirect 的區(qū)別?
Forward和Redirect代表了兩種請(qǐng)求轉(zhuǎn)發(fā)方式:直接轉(zhuǎn)發(fā)和間接轉(zhuǎn)發(fā)腮敌。
直接轉(zhuǎn)發(fā)方式(Forward)阱当,客戶端和瀏覽器只發(fā)出一次請(qǐng)求,Servlet糜工、HTML弊添、JSP或其它信息資源,由第二個(gè)信息資源響應(yīng)該請(qǐng)求捌木,在請(qǐng)求對(duì)象request中油坝,保存的對(duì)象對(duì)于每個(gè)信息資源是共享的。
間接轉(zhuǎn)發(fā)方式(Redirect)實(shí)際是兩次HTTP請(qǐng)求刨裆,服務(wù)器端在響應(yīng)第一次請(qǐng)求的時(shí)候澈圈,讓瀏覽器再向另外一個(gè)URL發(fā)出請(qǐng)求,從而達(dá)到轉(zhuǎn)發(fā)的目的帆啃。
舉個(gè)通俗的例子:
直接轉(zhuǎn)發(fā)就相當(dāng)于:“A找B借錢瞬女,B說沒有,B去找C借努潘,借到借不到都會(huì)把消息傳遞給A”诽偷;
間接轉(zhuǎn)發(fā)就相當(dāng)于:"A找B借錢,B說沒有疯坤,讓A去找C借"报慕。
81. 簡(jiǎn)述 tcp 和 udp的區(qū)別?
- TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無連接的贴膘,即發(fā)送數(shù)據(jù)之前不需要建立連接卖子。
- TCP提供可靠的服務(wù)。也就是說刑峡,通過TCP連接傳送的數(shù)據(jù)洋闽,無差錯(cuò),不丟失突梦,不重復(fù)诫舅,且按序到達(dá);UDP盡最大努力交付,即不保證可靠交付宫患。
- Tcp通過校驗(yàn)和刊懈,重傳控制,序號(hào)標(biāo)識(shí),滑動(dòng)窗口虚汛、確認(rèn)應(yīng)答實(shí)現(xiàn)可靠傳輸匾浪。如丟包時(shí)的重發(fā)控制,還可以對(duì)次序亂掉的分包進(jìn)行順序控制卷哩。
- UDP具有較好的實(shí)時(shí)性蛋辈,工作效率比TCP高,適用于對(duì)高速傳輸和實(shí)時(shí)性有較高的通信或廣播通信将谊。
- 每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一冷溶,一對(duì)多,多對(duì)一和多對(duì)多的交互通信尊浓。
- TCP對(duì)系統(tǒng)資源要求較多逞频,UDP對(duì)系統(tǒng)資源要求較少。
82. tcp 為什么要三次握手栋齿,兩次不行嗎苗胀?為什么?
為了實(shí)現(xiàn)可靠數(shù)據(jù)傳輸褒颈, TCP 協(xié)議的通信雙方柒巫, 都必須維護(hù)一個(gè)序列號(hào)励堡, 以標(biāo)識(shí)發(fā)送出去的數(shù)據(jù)包中谷丸, 哪些是已經(jīng)被對(duì)方收到的。 三次握手的過程即是通信雙方相互告知序列號(hào)起始值应结, 并確認(rèn)對(duì)方已經(jīng)收到了序列號(hào)起始值的必經(jīng)步驟刨疼。
如果只是兩次握手, 至多只有連接發(fā)起方的起始序列號(hào)能被確認(rèn)鹅龄, 另一方選擇的序列號(hào)則得不到確認(rèn)揩慕。
83. 說一下 tcp 粘包是怎么產(chǎn)生的?
①. 發(fā)送方產(chǎn)生粘包
采用TCP協(xié)議傳輸數(shù)據(jù)的客戶端與服務(wù)器經(jīng)常是保持一個(gè)長(zhǎng)連接的狀態(tài)(一次連接發(fā)一次數(shù)據(jù)不存在粘包)扮休,雙方在連接不斷開的情況下迎卤,可以一直傳輸數(shù)據(jù);但當(dāng)發(fā)送的數(shù)據(jù)包過于的小時(shí)玷坠,那么TCP協(xié)議默認(rèn)的會(huì)啟用Nagle算法蜗搔,將這些較小的數(shù)據(jù)包進(jìn)行合并發(fā)送(緩沖區(qū)數(shù)據(jù)發(fā)送是一個(gè)堆壓的過程);這個(gè)合并過程就是在發(fā)送緩沖區(qū)中進(jìn)行的八堡,也就是說數(shù)據(jù)發(fā)送出來它已經(jīng)是粘包的狀態(tài)了樟凄。
?
②. 接收方產(chǎn)生粘包
接收方采用TCP協(xié)議接收數(shù)據(jù)時(shí)的過程是這樣的:數(shù)據(jù)到底接收方,從網(wǎng)絡(luò)模型的下方傳遞至傳輸層兄渺,傳輸層的TCP協(xié)議處理是將其放置接收緩沖區(qū)缝龄,然后由應(yīng)用層來主動(dòng)獲取(C語言用recv、read等函數(shù))叔壤;這時(shí)會(huì)出現(xiàn)一個(gè)問題瞎饲,就是我們?cè)诔绦蛑姓{(diào)用的讀取數(shù)據(jù)函數(shù)不能及時(shí)的把緩沖區(qū)中的數(shù)據(jù)拿出來,而下一個(gè)數(shù)據(jù)又到來并有一部分放入的緩沖區(qū)末尾炼绘,等我們讀取數(shù)據(jù)時(shí)就是一個(gè)粘包企软。(放數(shù)據(jù)的速度 > 應(yīng)用層拿數(shù)據(jù)速度)
?
84. OSI 的七層模型都有哪些?
- 應(yīng)用層:網(wǎng)絡(luò)服務(wù)與最終用戶的一個(gè)接口饭望。
- 表示層:數(shù)據(jù)的表示仗哨、安全、壓縮铅辞。
- 會(huì)話層:建立厌漂、管理、終止會(huì)話斟珊。
- 傳輸層:定義傳輸數(shù)據(jù)的協(xié)議端口號(hào)苇倡,以及流控和差錯(cuò)校驗(yàn)。
- 網(wǎng)絡(luò)層:進(jìn)行邏輯地址尋址囤踩,實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的路徑選擇旨椒。
- 數(shù)據(jù)鏈路層:建立邏輯連接、進(jìn)行硬件地址尋址堵漱、差錯(cuò)校驗(yàn)等功能综慎。
- 物理層:建立、維護(hù)勤庐、斷開物理連接示惊。
85. get 和 post 請(qǐng)求有哪些區(qū)別?
- GET在瀏覽器回退時(shí)是無害的愉镰,而POST會(huì)再次提交請(qǐng)求米罚。
- GET產(chǎn)生的URL地址可以被Bookmark,而POST不可以丈探。
- GET請(qǐng)求會(huì)被瀏覽器主動(dòng)cache录择,而POST不會(huì),除非手動(dòng)設(shè)置碗降。
- GET請(qǐng)求只能進(jìn)行url編碼隘竭,而POST支持多種編碼方式。
- GET請(qǐng)求參數(shù)會(huì)被完整保留在瀏覽器歷史記錄里遗锣,而POST中的參數(shù)不會(huì)被保留货裹。
- GET請(qǐng)求在URL中傳送的參數(shù)是有長(zhǎng)度限制的,而POST么有精偿。
- 對(duì)參數(shù)的數(shù)據(jù)類型弧圆,GET只接受ASCII字符赋兵,而POST沒有限制。
- GET比POST更不安全搔预,因?yàn)閰?shù)直接暴露在URL上霹期,所以不能用來傳遞敏感信息。
- GET參數(shù)通過URL傳遞拯田,POST放在Request body中历造。
說一下 JSONP 實(shí)現(xiàn)原理?
jsonp 即 json+padding船庇,動(dòng)態(tài)創(chuàng)建script標(biāo)簽吭产,利用script標(biāo)簽的src屬性可以獲取任何域下的js腳本,通過這個(gè)特性(也可以說漏洞)鸭轮,服務(wù)器端不在返貨json格式臣淤,而是返回一段調(diào)用某個(gè)函數(shù)的js代碼,在src中進(jìn)行了調(diào)用窃爷,這樣實(shí)現(xiàn)了跨域邑蒋。
九、設(shè)計(jì)模式
88. 說一下你熟悉的設(shè)計(jì)模式按厘?
參考:常用的設(shè)計(jì)模式匯總医吊,超詳細(xì)!
89. 簡(jiǎn)單工廠和抽象工廠有什么區(qū)別逮京?
簡(jiǎn)單工廠模式:
這個(gè)模式本身很簡(jiǎn)單而且使用在業(yè)務(wù)較簡(jiǎn)單的情況下卿堂。一般用于小項(xiàng)目或者具體產(chǎn)品很少擴(kuò)展的情況(這樣工廠類才不用經(jīng)常更改)。
它由三種角色組成:
- 工廠類角色:這是本模式的核心造虏,含有一定的商業(yè)邏輯和判斷邏輯御吞,根據(jù)邏輯不同,產(chǎn)生具體的工廠產(chǎn)品漓藕。如例子中的Driver類。
- 抽象產(chǎn)品角色:它一般是具體產(chǎn)品繼承的父類或者實(shí)現(xiàn)的接口挟裂。由接口或者抽象類來實(shí)現(xiàn)享钞。如例中的Car接口。
- 具體產(chǎn)品角色:工廠類所創(chuàng)建的對(duì)象就是此角色的實(shí)例诀蓉。在java中由一個(gè)具體類實(shí)現(xiàn)栗竖,如例子中的Benz、Bmw類渠啤。
來用類圖來清晰的表示下的它們之間的關(guān)系:
?
抽象工廠模式:
先來認(rèn)識(shí)下什么是產(chǎn)品族: 位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中狐肢,功能相關(guān)聯(lián)的產(chǎn)品組成的家族。
?
圖中的BmwCar和BenzCar就是兩個(gè)產(chǎn)品樹(產(chǎn)品層次結(jié)構(gòu))沥曹;而如圖所示的BenzSportsCar和BmwSportsCar就是一個(gè)產(chǎn)品族份名。他們都可以放到跑車家族中碟联,因此功能有所關(guān)聯(lián)。同理BmwBussinessCar和BenzBusinessCar也是一個(gè)產(chǎn)品族僵腺。
可以這么說鲤孵,它和工廠方法模式的區(qū)別就在于需要?jiǎng)?chuàng)建對(duì)象的復(fù)雜程度上。而且抽象工廠模式是三個(gè)里面最為抽象辰如、最具一般性的普监。抽象工廠模式的用意為:給客戶端提供一個(gè)接口,可以創(chuàng)建多個(gè)產(chǎn)品族中的產(chǎn)品對(duì)象琉兜。
而且使用抽象工廠模式還要滿足一下條件:
- 系統(tǒng)中有多個(gè)產(chǎn)品族凯正,而系統(tǒng)一次只可能消費(fèi)其中一族產(chǎn)品
- 同屬于同一個(gè)產(chǎn)品族的產(chǎn)品以其使用。
來看看抽象工廠模式的各個(gè)角色(和工廠方法的如出一轍):
- 抽象工廠角色: 這是工廠方法模式的核心豌蟋,它與應(yīng)用程序無關(guān)主到。是具體工廠角色必須實(shí)現(xiàn)的接口或者必須繼承的父類。在java中它由抽象類或者接口來實(shí)現(xiàn)涮因。
- 具體工廠角色:它含有和具體業(yè)務(wù)邏輯有關(guān)的代碼县钥。由應(yīng)用程序調(diào)用以創(chuàng)建對(duì)應(yīng)的具體產(chǎn)品的對(duì)象。在java中它由具體的類來實(shí)現(xiàn)往声。
- 抽象產(chǎn)品角色:它是具體產(chǎn)品繼承的父類或者是實(shí)現(xiàn)的接口擂找。在java中一般有抽象類或者接口來實(shí)現(xiàn)。
- 具體產(chǎn)品角色:具體工廠角色所創(chuàng)建的對(duì)象就是此角色的實(shí)例浩销。在java中由具體的類來實(shí)現(xiàn)贯涎。
十、Spring / Spring MVC
90. 為什么要使用 spring慢洋?
1.簡(jiǎn)介
- 目的:解決企業(yè)應(yīng)用開發(fā)的復(fù)雜性
- 功能:使用基本的JavaBean代替EJB塘雳,并提供了更多的企業(yè)應(yīng)用功能
- 范圍:任何Java應(yīng)用
簡(jiǎn)單來說,Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架普筹。
2.輕量
從大小與開銷兩方面而言Spring都是輕量的败明。完整的Spring框架可以在一個(gè)大小只有1MB多的JAR文件里發(fā)布。并且Spring所需的處理開銷也是微不足道的太防。此外妻顶,Spring是非侵入式的:典型地,Spring應(yīng)用中的對(duì)象不依賴于Spring的特定類蜒车。
3.控制反轉(zhuǎn)
Spring通過一種稱作控制反轉(zhuǎn)(IoC)的技術(shù)促進(jìn)了松耦合讳嘱。當(dāng)應(yīng)用了IoC,一個(gè)對(duì)象依賴的其它對(duì)象會(huì)通過被動(dòng)的方式傳遞進(jìn)來酿愧,而不是這個(gè)對(duì)象自己創(chuàng)建或者查找依賴對(duì)象沥潭。你可以認(rèn)為IoC與JNDI相反——不是對(duì)象從容器中查找依賴,而是容器在對(duì)象初始化時(shí)不等對(duì)象請(qǐng)求就主動(dòng)將依賴傳遞給它嬉挡。
4.面向切面
Spring提供了面向切面編程的豐富支持钝鸽,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)(transaction)管理)進(jìn)行內(nèi)聚性的開發(fā)汇恤。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn)寞埠,例如日志或事務(wù)支持屁置。
5.容器
Spring包含并管理應(yīng)用對(duì)象的配置和生命周期,在這個(gè)意義上它是一種容器仁连,你可以配置你的每個(gè)bean如何被創(chuàng)建——基于一個(gè)可配置原型(prototype)蓝角,你的bean可以創(chuàng)建一個(gè)單獨(dú)的實(shí)例或者每次需要時(shí)都生成一個(gè)新的實(shí)例——以及它們是如何相互關(guān)聯(lián)的。然而饭冬,Spring不應(yīng)該被混同于傳統(tǒng)的重量級(jí)的EJB容器使鹅,它們經(jīng)常是龐大與笨重的,難以使用昌抠。
6.框架
Spring可以將簡(jiǎn)單的組件配置患朱、組合成為復(fù)雜的應(yīng)用。在Spring中炊苫,應(yīng)用對(duì)象被聲明式地組合裁厅,典型地是在一個(gè)XML文件里。Spring也提供了很多基礎(chǔ)功能(事務(wù)管理侨艾、持久化框架集成等等)执虹,將應(yīng)用邏輯的開發(fā)留給了你。
所有Spring的這些特征使你能夠編寫更干凈唠梨、更可管理袋励、并且更易于測(cè)試的代碼。它們也為Spring中的各種模塊提供了基礎(chǔ)支持当叭。
91. 解釋一下什么是 aop茬故?
AOP(Aspect-Oriented Programming,面向方面編程)蚁鳖,可以說是OOP(Object-Oriented Programing磺芭,面向?qū)ο缶幊蹋┑难a(bǔ)充和完善。OOP引入封裝才睹、繼承和多態(tài)性等概念來建立一種對(duì)象層次結(jié)構(gòu)徘跪,用以模擬公共行為的一個(gè)集合。當(dāng)我們需要為分散的對(duì)象引入公共行為的時(shí)候琅攘,OOP則顯得無能為力。也就是說松邪,OOP允許你定義從上到下的關(guān)系坞琴,但并不適合定義從左到右的關(guān)系。例如日志功能逗抑。日志代碼往往水平地散布在所有對(duì)象層次中剧辐,而與它所散布到的對(duì)象的核心功能毫無關(guān)系寒亥。對(duì)于其他類型的代碼,如安全性荧关、異常處理和透明的持續(xù)性也是如此溉奕。這種散布在各處的無關(guān)的代碼被稱為橫切(cross-cutting)代碼,在OOP設(shè)計(jì)中忍啤,它導(dǎo)致了大量代碼的重復(fù)加勤,而不利于各個(gè)模塊的重用。
而AOP技術(shù)則恰恰相反同波,它利用一種稱為“橫切”的技術(shù)鳄梅,剖解開封裝的對(duì)象內(nèi)部,并將那些影響了多個(gè)類的公共行為封裝到一個(gè)可重用模塊未檩,并將其名為“Aspect”戴尸,即方面。所謂“方面”冤狡,簡(jiǎn)單地說孙蒙,就是將那些與業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來悲雳,便于減少系統(tǒng)的重復(fù)代碼挎峦,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性怜奖。AOP代表的是一個(gè)橫向的關(guān)系浑测,如果說“對(duì)象”是一個(gè)空心的圓柱體,其中封裝的是對(duì)象的屬性和行為歪玲;那么面向方面編程的方法迁央,就仿佛一把利刃,將這些空心圓柱體剖開滥崩,以獲得其內(nèi)部的消息岖圈。而剖開的切面,也就是所謂的“方面”了钙皮。然后它又以巧奪天功的妙手將這些剖開的切面復(fù)原蜂科,不留痕跡。
使用“橫切”技術(shù)短条,AOP把軟件系統(tǒng)分為兩個(gè)部分:核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)导匣。業(yè)務(wù)處理的主要流程是核心關(guān)注點(diǎn),與之關(guān)系不大的部分是橫切關(guān)注點(diǎn)茸时。橫切關(guān)注點(diǎn)的一個(gè)特點(diǎn)是贡定,他們經(jīng)常發(fā)生在核心關(guān)注點(diǎn)的多處,而各處都基本相似可都。比如權(quán)限認(rèn)證缓待、日志蚓耽、事務(wù)處理。Aop 的作用在于分離系統(tǒng)中的各種關(guān)注點(diǎn)旋炒,將核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn)分離開來步悠。正如Avanade公司的高級(jí)方案構(gòu)架師Adam Magee所說,AOP的核心思想就是“將應(yīng)用程序中的商業(yè)邏輯同對(duì)其提供支持的通用服務(wù)進(jìn)行分離瘫镇《κ蓿”
92. 解釋一下什么是 ioc?
IOC是Inversion of Control的縮寫汇四,多數(shù)書籍翻譯成“控制反轉(zhuǎn)”接奈。
1996年,Michael Mattson在一篇有關(guān)探討面向?qū)ο罂蚣艿奈恼轮型酰紫忍岢隽薎OC 這個(gè)概念序宦。對(duì)于面向?qū)ο笤O(shè)計(jì)及編程的基本思想,前面我們已經(jīng)講了很多了背苦,不再贅述互捌,簡(jiǎn)單來說就是把復(fù)雜系統(tǒng)分解成相互合作的對(duì)象,這些對(duì)象類通過封裝以后行剂,內(nèi)部實(shí)現(xiàn)對(duì)外部是透明的秕噪,從而降低了解決問題的復(fù)雜度,而且可以靈活地被重用和擴(kuò)展厚宰。
IOC理論提出的觀點(diǎn)大體是這樣的:借助于“第三方”實(shí)現(xiàn)具有依賴關(guān)系的對(duì)象之間的解耦腌巾。如下圖:
?
大家看到了吧,由于引進(jìn)了中間位置的“第三方”铲觉,也就是IOC容器澈蝙,使得A、B撵幽、C灯荧、D這4個(gè)對(duì)象沒有了耦合關(guān)系,齒輪之間的傳動(dòng)全部依靠“第三方”了盐杂,全部對(duì)象的控制權(quán)全部上繳給“第三方”IOC容器逗载,所以,IOC容器成了整個(gè)系統(tǒng)的關(guān)鍵核心链烈,它起到了一種類似“粘合劑”的作用厉斟,把系統(tǒng)中的所有對(duì)象粘合在一起發(fā)揮作用,如果沒有這個(gè)“粘合劑”强衡,對(duì)象與對(duì)象之間會(huì)彼此失去聯(lián)系捏膨,這就是有人把IOC容器比喻成“粘合劑”的由來。
我們?cè)賮碜鰝€(gè)試驗(yàn):把上圖中間的IOC容器拿掉食侮,然后再來看看這套系統(tǒng):
?
我們現(xiàn)在看到的畫面号涯,就是我們要實(shí)現(xiàn)整個(gè)系統(tǒng)所需要完成的全部?jī)?nèi)容。這時(shí)候锯七,A链快、B、C眉尸、D這4個(gè)對(duì)象之間已經(jīng)沒有了耦合關(guān)系域蜗,彼此毫無聯(lián)系,這樣的話噪猾,當(dāng)你在實(shí)現(xiàn)A的時(shí)候霉祸,根本無須再去考慮B、C和D了袱蜡,對(duì)象之間的依賴關(guān)系已經(jīng)降低到了最低程度丝蹭。所以,如果真能實(shí)現(xiàn)IOC容器坪蚁,對(duì)于系統(tǒng)開發(fā)而言奔穿,這將是一件多么美好的事情,參與開發(fā)的每一成員只要實(shí)現(xiàn)自己的類就可以了敏晤,跟別人沒有任何關(guān)系贱田!
我們?cè)賮砜纯矗刂品崔D(zhuǎn)(IOC)到底為什么要起這么個(gè)名字嘴脾?我們來對(duì)比一下:
軟件系統(tǒng)在沒有引入IOC容器之前男摧,如圖1所示,對(duì)象A依賴于對(duì)象B译打,那么對(duì)象A在初始化或者運(yùn)行到某一點(diǎn)的時(shí)候耗拓,自己必須主動(dòng)去創(chuàng)建對(duì)象B或者使用已經(jīng)創(chuàng)建的對(duì)象B。無論是創(chuàng)建還是使用對(duì)象B扶平,控制權(quán)都在自己手上帆离。
軟件系統(tǒng)在引入IOC容器之后,這種情形就完全改變了结澄,如圖3所示哥谷,由于IOC容器的加入,對(duì)象A與對(duì)象B之間失去了直接聯(lián)系麻献,所以们妥,當(dāng)對(duì)象A運(yùn)行到需要對(duì)象B的時(shí)候,IOC容器會(huì)主動(dòng)創(chuàng)建一個(gè)對(duì)象B注入到對(duì)象A需要的地方勉吻。
通過前后的對(duì)比监婶,我們不難看出來:對(duì)象A獲得依賴對(duì)象B的過程,由主動(dòng)行為變?yōu)榱吮粍?dòng)行為,控制權(quán)顛倒過來了,這就是“控制反轉(zhuǎn)”這個(gè)名稱的由來惑惶。
93. spring 有哪些主要模塊煮盼?
Spring框架至今已集成了20多個(gè)模塊。這些模塊主要被分如下圖所示的核心容器带污、數(shù)據(jù)訪問/集成,僵控、Web、AOP(面向切面編程)鱼冀、工具报破、消息和測(cè)試模塊。
?
更多信息:howtodoinjava.com/java-spring-framework-tutorials/
94. spring 常用的注入方式有哪些千绪?
Spring通過DI(依賴注入)實(shí)現(xiàn)IOC(控制反轉(zhuǎn))充易,常用的注入方式主要有三種:
- 構(gòu)造方法注入
- setter注入
- 基于注解的注入
95. spring 中的 bean 是線程安全的嗎?
Spring容器中的Bean是否線程安全荸型,容器本身并沒有提供Bean的線程安全策略盹靴,因此可以說spring容器中的Bean本身不具備線程安全的特性,但是具體還是要結(jié)合具體scope的Bean去研究帆疟。
96. spring 支持幾種 bean 的作用域鹉究?
當(dāng)通過spring容器創(chuàng)建一個(gè)Bean實(shí)例時(shí),不僅可以完成Bean實(shí)例的實(shí)例化踪宠,還可以為Bean指定特定的作用域自赔。Spring支持如下5種作用域:
- singleton:?jiǎn)卫J剑谡麄€(gè)Spring IoC容器中柳琢,使用singleton定義的Bean將只有一個(gè)實(shí)例
- prototype:原型模式绍妨,每次通過容器的getBean方法獲取prototype定義的Bean時(shí),都將產(chǎn)生一個(gè)新的Bean實(shí)例
- request:對(duì)于每次HTTP請(qǐng)求柬脸,使用request定義的Bean都將產(chǎn)生一個(gè)新實(shí)例他去,即每次HTTP請(qǐng)求將會(huì)產(chǎn)生不同的Bean實(shí)例。只有在Web應(yīng)用中使用Spring時(shí)倒堕,該作用域才有效
- session:對(duì)于每次HTTP Session灾测,使用session定義的Bean豆?jié){產(chǎn)生一個(gè)新實(shí)例。同樣只有在Web應(yīng)用中使用Spring時(shí)垦巴,該作用域才有效
- globalsession:每個(gè)全局的HTTP Session媳搪,使用session定義的Bean都將產(chǎn)生一個(gè)新實(shí)例。典型情況下骤宣,僅在使用portlet context的時(shí)候有效秦爆。同樣只有在Web應(yīng)用中使用Spring時(shí),該作用域才有效
其中比較常用的是singleton和prototype兩種作用域憔披。對(duì)于singleton作用域的Bean等限,每次請(qǐng)求該Bean都將獲得相同的實(shí)例爸吮。容器負(fù)責(zé)跟蹤Bean實(shí)例的狀態(tài),負(fù)責(zé)維護(hù)Bean實(shí)例的生命周期行為望门;如果一個(gè)Bean被設(shè)置成prototype作用域形娇,程序每次請(qǐng)求該id的Bean,Spring都會(huì)新建一個(gè)Bean實(shí)例怒允,然后返回給程序埂软。在這種情況下,Spring容器僅僅使用new 關(guān)鍵字創(chuàng)建Bean實(shí)例纫事,一旦創(chuàng)建成功,容器不在跟蹤實(shí)例所灸,也不會(huì)維護(hù)Bean實(shí)例的狀態(tài)丽惶。
如果不指定Bean的作用域,Spring默認(rèn)使用singleton作用域爬立。Java在創(chuàng)建Java實(shí)例時(shí)钾唬,需要進(jìn)行內(nèi)存申請(qǐng);銷毀實(shí)例時(shí)侠驯,需要完成垃圾回收抡秆,這些工作都會(huì)導(dǎo)致系統(tǒng)開銷的增加。因此吟策,prototype作用域Bean的創(chuàng)建儒士、銷毀代價(jià)比較大。而singleton作用域的Bean實(shí)例一旦創(chuàng)建成功檩坚,可以重復(fù)使用着撩。因此,除非必要匾委,否則盡量避免將Bean被設(shè)置成prototype作用域拖叙。
97. spring 自動(dòng)裝配 bean 有哪些方式?
Spring容器負(fù)責(zé)創(chuàng)建應(yīng)用程序中的bean同時(shí)通過ID來協(xié)調(diào)這些對(duì)象之間的關(guān)系赂乐。作為開發(fā)人員薯鳍,我們需要告訴Spring要?jiǎng)?chuàng)建哪些bean并且如何將其裝配到一起。
spring中bean裝配有兩種方式:
- 隱式的bean發(fā)現(xiàn)機(jī)制和自動(dòng)裝配
- 在java代碼或者XML中進(jìn)行顯示配置
當(dāng)然這些方式也可以配合使用挨措。
98. spring 事務(wù)實(shí)現(xiàn)方式有哪些挖滤?
- 編程式事務(wù)管理對(duì)基于 POJO 的應(yīng)用來說是唯一選擇。我們需要在代碼中調(diào)用beginTransaction()运嗜、commit()壶辜、rollback()等事務(wù)管理相關(guān)的方法,這就是編程式事務(wù)管理担租。
- 基于 TransactionProxyFactoryBean 的聲明式事務(wù)管理
- 基于 @Transactional 的聲明式事務(wù)管理
- 基于 Aspectj AOP 配置事務(wù)
99. 說一下 spring 的事務(wù)隔離砸民?
事務(wù)隔離級(jí)別指的是一個(gè)事務(wù)對(duì)數(shù)據(jù)的修改與另一個(gè)并行的事務(wù)的隔離程度,當(dāng)多個(gè)事務(wù)同時(shí)訪問相同數(shù)據(jù)時(shí),如果沒有采取必要的隔離機(jī)制岭参,就可能發(fā)生以下問題:
- 臟讀:一個(gè)事務(wù)讀到另一個(gè)事務(wù)未提交的更新數(shù)據(jù)反惕。
- 幻讀:例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,比如這種修改涉及到表中的“全部數(shù)據(jù)行”演侯。同時(shí)姿染,第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入“一行新數(shù)據(jù)”秒际。那么悬赏,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還存在沒有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺一樣娄徊。
- 不可重復(fù)讀:比方說在同一個(gè)事務(wù)中先后執(zhí)行兩條一模一樣的select語句闽颇,期間在此次事務(wù)中沒有執(zhí)行過任何DDL語句,但先后得到的結(jié)果不一致寄锐,這就是不可重復(fù)讀兵多。
100. 說一下 spring mvc 運(yùn)行流程?
Spring MVC運(yùn)行流程圖:
?
Spring運(yùn)行流程描述:
1. 用戶向服務(wù)器發(fā)送請(qǐng)求橄仆,請(qǐng)求被Spring 前端控制Servelt DispatcherServlet捕獲剩膘;
DispatcherServlet對(duì)請(qǐng)求URL進(jìn)行解析,得到請(qǐng)求資源標(biāo)識(shí)符(URI)盆顾。然后根據(jù)該URI怠褐,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對(duì)象(包括Handler對(duì)象以及Handler對(duì)象對(duì)應(yīng)的攔截器),最后以HandlerExecutionChain對(duì)象的形式返回椎扬;
DispatcherServlet 根據(jù)獲得的Handler惫搏,選擇一個(gè)合適的HandlerAdapter;(附注:如果成功獲得HandlerAdapter后蚕涤,此時(shí)將開始執(zhí)行攔截器的preHandler(...)方法)
4. 提取Request中的模型數(shù)據(jù)筐赔,填充Handler入?yún)ⅲ_始執(zhí)行Handler(Controller)揖铜。 在填充Handler的入?yún)⑦^程中茴丰,根據(jù)你的配置,Spring將幫你做一些額外的工作:
- HttpMessageConveter: 將請(qǐng)求消息(如Json天吓、xml等數(shù)據(jù))轉(zhuǎn)換成一個(gè)對(duì)象贿肩,將對(duì)象轉(zhuǎn)換為指定的響應(yīng)信息
- 數(shù)據(jù)轉(zhuǎn)換:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換。如String轉(zhuǎn)換成Integer龄寞、Double等
- 數(shù)據(jù)根式化:對(duì)請(qǐng)求消息進(jìn)行數(shù)據(jù)格式化汰规。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等
- 數(shù)據(jù)驗(yàn)證: 驗(yàn)證數(shù)據(jù)的有效性(長(zhǎng)度、格式等)物邑,驗(yàn)證結(jié)果存儲(chǔ)到BindingResult或Error中
5. Handler執(zhí)行完成后溜哮,向DispatcherServlet 返回一個(gè)ModelAndView對(duì)象滔金;
6. 根據(jù)返回的ModelAndView,選擇一個(gè)適合的ViewResolver(必須是已經(jīng)注冊(cè)到Spring容器中的ViewResolver)返回給DispatcherServlet 茂嗓;
- ViewResolver 結(jié)合Model和View餐茵,來渲染視圖;
8. 將渲染結(jié)果返回給客戶端述吸。
101. spring mvc 有哪些組件忿族?
Spring MVC的核心組件:
- DispatcherServlet:中央控制器,把請(qǐng)求給轉(zhuǎn)發(fā)到具體的控制類
- Controller:具體處理請(qǐng)求的控制器
- HandlerMapping:映射處理器蝌矛,負(fù)責(zé)映射中央處理器轉(zhuǎn)發(fā)給controller時(shí)的映射策略
- ModelAndView:服務(wù)層返回的數(shù)據(jù)和視圖層的封裝類
- ViewResolver:視圖解析器道批,解析具體的視圖
- Interceptors :攔截器,負(fù)責(zé)攔截我們定義的請(qǐng)求然后做處理工作
102. @RequestMapping 的作用是什么朴读?
RequestMapping是一個(gè)用來處理請(qǐng)求地址映射的注解屹徘,可用于類或方法上。用于類上衅金,表示類中的所有響應(yīng)請(qǐng)求的方法都是以該地址作為父路徑。
RequestMapping注解有六個(gè)屬性簿煌,下面我們把她分成三類進(jìn)行說明氮唯。
value, method:
- value:指定請(qǐng)求的實(shí)際地址姨伟,指定的地址可以是URI Template 模式(后面將會(huì)說明)惩琉;
- method:指定請(qǐng)求的method類型, GET夺荒、POST瞒渠、PUT、DELETE等技扼;
consumes伍玖,produces
- consumes:指定處理請(qǐng)求的提交內(nèi)容類型(Content-Type),例如application/json, text/html剿吻;
- produces:指定返回的內(nèi)容類型窍箍,僅當(dāng)request請(qǐng)求頭中的(Accept)類型中包含該指定類型才返回;
params丽旅,headers
- params: 指定request中必須包含某些參數(shù)值是椰棘,才讓該方法處理。
- headers:指定request中必須包含某些指定的header值榄笙,才能讓該方法處理請(qǐng)求邪狞。