2020-07-06

一嗅绰、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ò)誤信息:

image
image.gif

?

接口和抽象類有什么區(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 容器都有哪些递沪?

常用容器的圖錄:

image
image.gif

?

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ū)別是什么送悔?

image
image.gif
  1. HashMap 和 Hashtable 有什么區(qū)別慢显?
    hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法欠啤。
    hashTable同步的荚藻,而HashMap是非同步的,效率上逼hashTable要高洁段。
    hashMap允許空鍵值应狱,而hashTable不允許。

  2. 如何決定使用 HashMap 還是 TreeMap祠丝?
    對(duì)于在Map中插入疾呻、刪除和定位元素這類操作,HashMap是最好的選擇写半。然而岸蜗,假如你需要對(duì)一個(gè)有序的key集合進(jìn)行遍歷,TreeMap是更好的選擇叠蝇×г溃基于你的collection的大小,也許向HashMap中添加元素會(huì)更快悔捶,將map換為TreeMap進(jìn)行有序key的遍歷矾睦。

  3. 說一下 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)

  1. 說一下 HashSet 的實(shí)現(xiàn)原理闷串?
    HashSet底層由HashMap實(shí)現(xiàn)
    HashSet的值存放于HashMap的key上
    HashMap的value統(tǒng)一為PRESENT

  2. ArrayList 和 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)数初。

  3. 如何實(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方法泡孩。

  4. ArrayList 和 Vector 的區(qū)別是什么?
    Vector是同步的荚守,而ArrayList不是珍德。然而,如果你尋求在迭代的時(shí)候?qū)α斜磉M(jìn)行改變矗漾,你應(yīng)該使用CopyOnWriteArrayList锈候。
    ArrayList比Vector快,它因?yàn)橛型匠ü保粫?huì)過載泵琳。
    ArrayList更加通用,因?yàn)槲覀兛梢允褂肅ollections工具類輕易地獲取同步列表和只讀列表誊役。

  5. Array 和 ArrayList 有何區(qū)別获列?
    Array可以容納基本類型和對(duì)象,而ArrayList只能容納對(duì)象蛔垢。
    Array是指定大小的击孩,而ArrayList大小是固定的。
    Array沒有提供ArrayList那么多功能鹏漆,比如addAll巩梢、removeAll和iterator等。

  6. 在 Queue 中 poll()和 remove()有什么區(qū)別艺玲?
    poll() 和 remove() 都是從隊(duì)列中取出一個(gè)元素括蝠,但是 poll() 在獲取元素失敗的時(shí)候會(huì)返回空,但是 remove() 失敗的時(shí)候會(huì)拋出異常饭聚。

  7. 哪些集合類是線程安全的忌警?
    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)于迭代器。

  8. 迭代器 Iterator 是什么犀忱?
    迭代器是一種設(shè)計(jì)模式募谎,它是一個(gè)對(duì)象,它可以遍歷并選擇序列中的對(duì)象阴汇,而開發(fā)人員不需要了解該序列的底層結(jié)構(gòu)数冬。迭代器通常被稱為“輕量級(jí)”對(duì)象,因?yàn)閯?chuàng)建它的代價(jià)小搀庶。

  9. 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中插入和刪除元素。

  1. Iterator 和 ListIterator 有什么區(qū)別附迷?
    Iterator可用來遍歷Set和List集合惧互,但是ListIterator只能用來遍歷List。
    Iterator對(duì)集合只能是前向遍歷挟秤,ListIterator既可以前向也可以后向。
    ListIterator實(shí)現(xiàn)了Iterator接口抄伍,并包含其他的功能艘刚,比如:增加元素,替換元素截珍,獲取前一個(gè)和后一個(gè)元素的索引攀甚,等等箩朴。
    三、多線程

  2. 并行和并發(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á)到最高的處理性能兽泣。

  3. 線程和進(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í)行怨咪。

  4. 守護(hù)線程是什么?
    守護(hù)線程(即daemon thread)润匙,是個(gè)服務(wù)線程诗眨,準(zhǔn)確地來說就是服務(wù)其他的線程。

  5. 創(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é)束后的返回值味滞。

  1. 說一下 runnable 和 callable 有什么區(qū)別?
    有點(diǎn)深的問題了钮呀,也看出一個(gè)Java程序員學(xué)習(xí)知識(shí)的廣度剑鞍。

Runnable接口中的run()方法的返回值是void,它做的事情只是純粹地去執(zhí)行run()方法中的代碼而已爽醋;
Callable接口中的call()方法是有返回值的蚁署,是一個(gè)泛型,和Future蚂四、FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果光戈。

  1. 線程有哪些狀態(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)切換框架圖:

image
image.gif

?

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í)的圖示過程:

image
image.gif

?

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ī)劃。

  1. 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ì)象

  1. 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)化永乌。

  2. 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鎖適合代碼少量的同步問題涛救。

  3. 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眷蜈。

  1. 說一下 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)程的問題构回。

四夏块、反射

  1. 什么是反射?
    反射主要是指程序可以訪問纤掸、檢測(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ì)象的方法卵牍。

  1. 什么是 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í)候厅各;

  1. 動(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)限
加日志

  1. 怎么實(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的一種方式夕春。

  1. 說一下 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)的值了迫卢。

  2. 如果客戶端禁止 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頁面判斷代碼

  1. 什么是 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)行編碼际跪。

  1. 什么是 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í)意愿下的操作行為紧阔。

如何避免:

  1. 驗(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 攻擊憾儒。

  1. 使用驗(yàn)證碼

關(guān)鍵操作頁面加上驗(yàn)證碼,后臺(tái)收到請(qǐng)求后通過判斷驗(yàn)證碼可以防御CSRF乃沙。但這種方法對(duì)用戶不太友好起趾。

  1. 在請(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)求了厚骗。

  1. 在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)站中去。

七民轴、異常

  1. throw 和 throws 的區(qū)別攻柠?
    throws是用來聲明一個(gè)方法可能拋出的所有異常信息球订,throws是將異常聲明但是不處理,而是將異常往上傳辙诞,誰調(diào)用我就交給誰處理辙售。而throw則是指拋出的一個(gè)具體的異常類型轻抱。

  2. 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(),回收垃圾限煞。

  3. 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)行的“掃尾”處理扛点。

  1. 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)了樟凄。

image
image.gif

?

②. 接收方產(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ù)速度)

image
image.gif

?

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

  1. 應(yīng)用層:網(wǎng)絡(luò)服務(wù)與最終用戶的一個(gè)接口饭望。
  2. 表示層:數(shù)據(jù)的表示仗哨、安全、壓縮铅辞。
  3. 會(huì)話層:建立厌漂、管理、終止會(huì)話斟珊。
  4. 傳輸層:定義傳輸數(shù)據(jù)的協(xié)議端口號(hào)苇倡,以及流控和差錯(cuò)校驗(yàn)。
  5. 網(wǎng)絡(luò)層:進(jìn)行邏輯地址尋址囤踩,實(shí)現(xiàn)不同網(wǎng)絡(luò)之間的路徑選擇旨椒。
  6. 數(shù)據(jù)鏈路層:建立邏輯連接、進(jìn)行硬件地址尋址堵漱、差錯(cuò)校驗(yàn)等功能综慎。
  7. 物理層:建立、維護(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)系:


image
image.gif

?

抽象工廠模式:

先來認(rèn)識(shí)下什么是產(chǎn)品族: 位于不同產(chǎn)品等級(jí)結(jié)構(gòu)中狐肢,功能相關(guān)聯(lián)的產(chǎn)品組成的家族。

image
image.gif

?

圖中的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ì)象琉兜。

而且使用抽象工廠模式還要滿足一下條件:

  1. 系統(tǒng)中有多個(gè)產(chǎn)品族凯正,而系統(tǒng)一次只可能消費(fèi)其中一族產(chǎn)品
  2. 同屬于同一個(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ì)象之間的解耦腌巾。如下圖:

image
image.gif

?

大家看到了吧,由于引進(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):

image
image.gif

?

我們現(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è)試模塊。

image
image.gif

?

更多信息:howtodoinjava.com/java-spring-framework-tutorials/

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

Spring通過DI(依賴注入)實(shí)現(xiàn)IOC(控制反轉(zhuǎn))充易,常用的注入方式主要有三種:

  1. 構(gòu)造方法注入
  2. setter注入
  3. 基于注解的注入

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)方式有哪些挖滤?

  1. 編程式事務(wù)管理對(duì)基于 POJO 的應(yīng)用來說是唯一選擇。我們需要在代碼中調(diào)用beginTransaction()运嗜、commit()壶辜、rollback()等事務(wù)管理相關(guān)的方法,這就是編程式事務(wù)管理担租。
  2. 基于 TransactionProxyFactoryBean 的聲明式事務(wù)管理
  3. 基于 @Transactional 的聲明式事務(wù)管理
  4. 基于 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)行流程圖:

image
image.gif

?

Spring運(yùn)行流程描述:

1. 用戶向服務(wù)器發(fā)送請(qǐng)求橄仆,請(qǐng)求被Spring 前端控制Servelt DispatcherServlet捕獲剩膘;

  1. 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ì)象的形式返回椎扬;

  2. 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 茂嗓;

  1. ViewResolver 結(jié)合Model和View餐茵,來渲染視圖;

8. 將渲染結(jié)果返回給客戶端述吸。

101. spring mvc 有哪些組件忿族?

Spring MVC的核心組件:

  1. DispatcherServlet:中央控制器,把請(qǐng)求給轉(zhuǎn)發(fā)到具體的控制類
  2. Controller:具體處理請(qǐng)求的控制器
  3. HandlerMapping:映射處理器蝌矛,負(fù)責(zé)映射中央處理器轉(zhuǎn)發(fā)給controller時(shí)的映射策略
  4. ModelAndView:服務(wù)層返回的數(shù)據(jù)和視圖層的封裝類
  5. ViewResolver:視圖解析器道批,解析具體的視圖
  6. 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)求邪狞。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茅撞,隨后出現(xiàn)的幾起案子帆卓,更是在濱河造成了極大的恐慌巨朦,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鳞疲,死亡現(xiàn)場(chǎng)離奇詭異罪郊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)尚洽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門悔橄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腺毫,你說我怎么就攤上這事癣疟。” “怎么了潮酒?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵睛挚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我急黎,道長(zhǎng)扎狱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任勃教,我火速辦了婚禮淤击,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘故源。我一直安慰自己污抬,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布绳军。 她就那樣靜靜地躺著印机,像睡著了一般。 火紅的嫁衣襯著肌膚如雪门驾。 梳的紋絲不亂的頭發(fā)上射赛,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音猎唁,去河邊找鬼咒劲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛诫隅,可吹牛的內(nèi)容都是我干的腐魂。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼逐纬,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蛔屹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起豁生,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤兔毒,失蹤者是張志新(化名)和其女友劉穎漫贞,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體育叁,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡迅脐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了豪嗽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谴蔑。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖龟梦,靈堂內(nèi)的尸體忽然破棺而出隐锭,到底是詐尸還是另有隱情,我是刑警寧澤计贰,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布钦睡,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望眯亦。 院中可真熱鬧,春花似錦、人聲如沸笤昨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挖帘。三九已至,卻和暖如春恋技,著一層夾襖步出監(jiān)牢的瞬間拇舀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國打工蜻底, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留骄崩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓薄辅,卻偏偏與公主長(zhǎng)得像要拂,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子站楚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361