1. 程式人生 > >阿里JAVA開發面試常問問題總結4

阿里JAVA開發面試常問問題總結4

java的三大特性

封裝、繼承、多型

抽象類和介面的區別

Java抽象類:
使用關鍵字abstract修飾的類叫做抽象類。
用abstract來修飾的方法叫做抽象方法。
特點:
1含有抽象方法的類必須被宣告為抽象類(不管是否還包含其他一般方法)(否則編譯通不過);
2抽象類可以沒有抽象方法,可以有普通方法。
3抽象類必須被繼承,抽象方法必須被重寫:
若子類還是一個抽象類,不需要重寫;否則必須要重寫(override)。
抽象類不能被例項化(不能直接構造一個該類的物件);

抽象方法:
在類中沒有方法體(抽象方法只需宣告,而不需實現某些功能);
抽象類中的抽象方法必須被實現;
如果一個子類沒有實現父類中的抽象方法,則子類也變成了一個抽象類;

虛方法:
虛擬函式的存在是為了多型。
Java中沒有虛擬函式的概念。它的普通函式就相當於c++的虛擬函式,動態繫結是java的預設行為。如果java中不希望某個函式具有虛擬函式特性,可以加上final關鍵字變為非虛擬函式。

Java介面:
是一系列方法的宣告。
1只有宣告沒有實現;
2在不同的類中有不同的方法實現;

共同點

1、介面和抽象類都不能被例項化,他們都位於繼承樹的頂端,用於被其他類實現和繼承。
2、介面和抽象類都可以包含抽象方法,實現介面或繼承抽象類的普通子類都必須實現這些方法。

不同點

1、接口裡只能包含抽象方法和預設方法,不能為普通方法提供方法實現;抽象類則完全可以包含普通方法。
2、接口裡不能定義靜態方法,抽象類裡可以定義靜態方法。
3、接口裡只能定義靜態常量,不能定義普通成員變數;抽象類裡則既可以定義普通成員變數,也可以定義靜態常量。
4、接口裡不包含構造器,抽象類裡可以包含構造器,抽象類裡的構造器並不是用於建立物件,而是讓其子類呼叫這些構造器來完成屬於抽象類的初始化操作。
5、接口裡不能包含初始化塊,但抽象類則完全可以包含初始化塊。
6、一個類最多隻能有一個直接父類,包括抽象類;但一個類可以直接實現多個介面,通過實現多個介面可以彌補Java單繼承的不足。

棧記憶體和堆記憶體,引用和值傳遞

棧記憶體、堆記憶體

在函式中定義的一些基本型別的變數和物件的引用變數都是在函式的棧記憶體中分配。當在一段程式碼塊中定義一個變數時,java就在棧中為這個變數分配記憶體空間,當超過變數的作用域後,java會自動釋放掉為該變數分配的記憶體空間,該記憶體空間可以立刻被另作他用。
堆記憶體用於存放由new建立的物件和陣列。在堆中分配的記憶體,由java虛擬機器自動垃圾回收器來管理。在陣列和物件在沒有引用變數指向它的時候,才變成垃圾,不能再被使用,但是仍然佔著記憶體,在隨後的一個不確定的時間被垃圾回收器釋放掉。這個也是java比較佔記憶體的主要原因。

引用、值傳遞

值傳遞:方法呼叫時,實際引數把它的值傳遞給對應的形式引數,方法執行中形式引數值的改變不影響實際引數的值。

引用傳遞:也稱為傳地址。方法呼叫時,實際引數的引用(地址,而不是引數的值)被傳遞給方法中相對應的形式引數,在方法執行中,對形式引數的操作實際上就是對實際引數的操作,方法執行中形式引數值的改變將會影響實際引數的值。

單例模式及好處

建構函式私有化,用一個靜態方法來獲取物件例項。

特點:
1)單例類只能有一個例項。
2)單例類必須自己建立自己的唯一例項。
3)單例類必須給所有其他物件提供這一例項。
主要優點:
1)提供了對唯一例項的受控訪問。
2)由於在系統記憶體中只存在一個物件,因此可以節約系統資源,對於一些需要頻繁建立和銷燬的物件單例模式無疑可以提高系統的效能。
3)允許可變數目的例項。

主要缺點:
1)由於單利模式中沒有抽象層,因此單例類的擴充套件有很大的困難。
2)單例類的職責過重,在一定程度上違背了“單一職責原則”。
3)濫用單例將帶來一些負面問題,如為了節省資源將資料庫連線池物件設計為的單例類,可能會導致共享連線池物件的程式過多而出現連線池溢位;如果例項化的物件長時間不被利用,系統會認為是垃圾而被回收,這將導致物件狀態的丟失。

過載和重寫

過載:Overloading
(1) Java的方法過載,就是在類中可以建立多個方法,它們具有相同的名字,但具有不同的引數和不同的定義。呼叫方法時通過傳遞給它們的不同引數個數和引數型別來決定具體使用哪個方法, 這就是多型性。
(2) 過載的時候,方法名要一樣,但是引數型別和個數不一樣,返回值型別可以相同也可以不相同。無法以返回型別作為過載函式的區分標準。

重寫:Overriding
注意:當要重寫父類方法時,要使用@Override標籤提醒編譯器檢查程式碼是否是重寫,而不是過載了原來的方法。
(1) 父類與子類之間的多型性,對父類的函式進行重新定義。如果在子類中定義某方法與其父類有相同的名稱和引數,我們說該方法被重寫 (Overriding)。在Java中,子類可繼承父類中的方法,而不需要重新編寫相同的方法。但有時子類並不想原封不動地繼承父類的方法,而是想作一定的修改,這就需要採用方法的重寫。方法重寫又稱方法覆蓋。
(2)若子類中的方法與父類中的某一方法具有相同的方法名、返回型別和引數表,則新方法將覆蓋原有的方法。如需父類中原有的方法,可使用super關鍵字,該關鍵字引用了當前類的父類。
(3)子類函式的訪問修飾許可權不能少於父類的。

子類、父類間的轉換和構造順序

子類、父類間的轉換:
子類能夠自動轉換成父類型別。
當建立子類物件的時候:
①先呼叫了子類的建構函式
②呼叫了父類的建構函式
③執行了父類的建構函式
④執行了子類的建構函式

Final、finally、finalize

final 用於宣告屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。
finally是異常處理語句結構的一部分,表示總是執行。
finalize是Object類的一個方法,在垃圾收集器執行的時候會呼叫被回收物件的此方法,可以覆蓋此方法提供垃圾收集時的其他資源回收,例如關閉檔案等

Synchronized和volatile的區別

volatile只作用於在多個執行緒之間能夠被共享的變數。如果一個欄位被宣告成volatile,java執行緒記憶體模型確保所有執行緒看到這個變數的值是一致的。Volatile變數修飾符如果使用恰當的話,它比synchronized的使用和執行成本會更低,因為它不會引起執行緒上下文的切換和排程。
synchronized獲得並釋放監視器——如果兩個執行緒使用了同一個物件鎖,監視器能強制保證程式碼塊同時只被一個執行緒所執行——這是眾所周知的事實。但是,synchronized也同步記憶體:事實上,synchronized在“ 主”記憶體區域同步整個執行緒的記憶體。
因此volatile只是在執行緒記憶體和“主”記憶體間同步某個變數的值,而synchronized通過鎖定和解鎖某個監視器同步所有變數的值。顯然synchronized要比volatile消耗更多資源。

1)volatile本質是在告訴jvm當前變數在暫存器(工作記憶體)中的值是不確定的,需要從主存中讀取,沒有互斥鎖;synchronized則是鎖定當前變數,只有當前執行緒可以訪問該變數,其他執行緒被阻塞住。
2)volatile僅能使用在變數級別;synchronized則可以使用在變數、方法、和類級別的
3)volatile只是在執行緒記憶體和“主”記憶體間同步某個變數的值,而synchronized通過鎖定和解鎖某個監視器同步所有變數的值;顯然synchronized要比volatile消耗更多資源。
4)volatile不會造成執行緒的阻塞;synchronized可能會造成執行緒的阻塞。
5)volatile標記的變數不會被編譯器優化;synchronized標記的變數可以被編譯器優化 。

集合

Collection:代表一組物件,每一個物件都是它的子元素。
Set:不包含重複元素的Collection。
List:有順序的Collection,並且可以包含重複元素。
Map:可以把鍵(key)對映到值(value)的物件,鍵不能重複。

集合類沒有實現Cloneable和Serializable介面的原因

Collection介面指定一組物件,物件即為它的元素。如何維護這些元素由Collection的具體實現決定。例如,一些如List的Collection實現允許重複的元素,而其它的如Set就不允許。很多Collection實現有一個公有的clone方法。然而,把它放到集合的所有實現中也是沒有意義的。這是因為Collection是一個抽象表現。重要的是實現。
當與具體實現打交道的時候,克隆或序列化的語義和含義才發揮作用。所以,具體實現應該決定如何對它進行克隆或序列化,或它是否可以被克隆或序列化。
在所有的實現中授權克隆和序列化,最終導致更少的靈活性和更多的限制。特定的實現應該決定它是否可以被克隆和序列化。

hashCode()和equals()方法的重要性體現在什麼地方?

HashMap使用Key物件的hashCode()和equals()方法去決定key-value對的索引。當我們試著從HashMap中獲取值的時候,這些方法也會被用到。如果這些方法沒有被正確地實現,在這種情況下,兩個不同Key也許會產生相同的hashCode()和equals()輸出,HashMap將會認為它們是相同的,然後覆蓋它們,而非把它們儲存到不同的地方。同樣的,所有不允許儲存重複資料的集合類都使用hashCode()和equals()去查詢重複,所以正確實現它們非常重要。
equals()和hashCode()的實現應該遵循以下規則:
(1)如果o1.equals(o2),那麼o1.hashCode() == o2.hashCode()總是為true的。
(2)如果o1.hashCode() == o2.hashCode(),並不意味著o1.equals(o2)會為true。
Java中的HashMap使用hashCode()和equals()方法來確定鍵值對的索引,當根據鍵獲取值的時候也會用到這兩個方法。如果沒有正確的實現這兩個方法,兩個不同的鍵可能會有相同的hash值,因此,可能會被集合認為是相等的。而且,這兩個方法也用來發現重複元素。所以這兩個方法的實現對HashMap的精確性和正確性是至關重要的。

HashMap和HashTabel的區別

HashMap和Hashtable都實現了Map介面,因此很多特性非常相似。但是,他們有以下不同點:
1)HashMap允許鍵和值是null,而Hashtable不允許鍵或者值是null。
2)Hashtable是同步的,而HashMap不是。因此,HashMap更適合於單執行緒環境,而Hashtable適合於多執行緒環境。
3)HashMap提供了可供應用迭代的鍵的集合,因此,HashMap是快速失敗的。另一方面,Hashtable提供了對鍵的列舉(Enumeration)。
一般認為Hashtable是一個遺留的類。

Comparable和Comparator介面

Comparable和Comparator都是用來實現集合中的排序的,只是Comparable是在集合內部定義的方法實現的排序,Comparator是在集合外部實現的排序,所以,如想實現排序,就需要在集合外定義Comparator介面的方法compare()或在集合內實現Comparable介面的方法compareTo()。
comparable是支援自比較,而後者是支援外部比較;
Comparable是一個物件本身就已經支援自比較所需要實現的介面(如String、Integer自己就可以完成比較大小操作)
而Comparator是一個專用的比較器,當這個物件不支援自比較或者自比較函式不能滿足你的要求時,你可以寫一個比較器來完成兩個物件之間大小的比較。
也就是說當你需要對一個自定義的類的一個數組或者集合進行比較的時候可以實現Comparable介面,當你需要對一個已有的類的陣列或者集合進行比較的時候就一定要實現Comparator介面。另外,這兩個介面是支援泛型的,所以我們應該在實現介面的同時定義比較型別。

Java中HashMap的工作原理是?

Java中的HashMap是以鍵值對(key-value)的形式儲存元素的。HashMap需要一個hash函式,它使用hashCode()和equals()方法來向集合/從集合新增和檢索元素。當呼叫put()方法的時候,HashMap會計算key的hash值,然後把鍵值對儲存在集合中合適的索引上。如果key已經存在了,value會被更新成新值。HashMap的一些重要的特性是它的容量(capacity),負載因子(load factor)和擴容極限(threshold resizing)。
1)HashMap有一個叫做Entry的內部類,它用來儲存key-value對。
2)上面的Entry物件是儲存在一個叫做table的Entry陣列中。
3)table的索引在邏輯上叫做“桶”(bucket),它儲存了連結串列的第一個元素。
4)key的hashcode()方法用來找到Entry物件所在的桶。
5)如果兩個key有相同的hash值,他們會被放在table陣列的同一個桶裡面。
6)key的equals()方法用來確保key的唯一性。
7)value物件的equals()和hashcode()方法根本一點用也沒有。
重點內容
Put:根據key的hashcode()方法計算出來的hash值來決定key在Entry陣列的索引。
Get:通過hashcode找到陣列中的某一個元素Entry

Hashcode的實現

hashCode 的常規協定是:
在 Java 應用程式執行期間,在同一物件上多次呼叫 hashCode 方法時,必須一致地返回相同的整數,前提是物件上 equals 比較中所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。
如果根據 equals(Object) 方法,兩個物件是相等的,那麼在兩個物件中的每個物件上呼叫 hashCode 方法都必須生成相同的整數結果。
當equals方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定宣告相等物件必須具有相等的雜湊碼。

String、StringBffer、StringBuilder的區別

1)可變與不可變
String類中使用字元陣列儲存字串,如下就是,因為有“final”修飾符,所以可以知道string物件是不可變的。
    private final char value[];
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字元陣列儲存字串,如下就是,可知這兩種物件都是可變的。
    char[] value;
2)是否多執行緒安全
String中的物件是不可變的,也就可以理解為常量,顯然執行緒安全。
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。
  StringBuffer對方法加了同步鎖或者對呼叫的方法加了同步鎖,所以是執行緒安全的

HashMap、HashSet、HashTable的區別

HashSet和HashMap的區別
1)HashSet是set的一個實現類,hashMap是Map的一個實現類,同時hashMap是hashTable的替代品.
2)HashSet以物件作為元素,而HashMap以(key-value)的一組物件作為元素,且HashSet拒絕接受重複的物件.HashMap可以看作三個檢視:key的Set,value的Collection,Entry的Set。HashSet其實就是HashMap的一個檢視。

HashSet內部就是使用Hashmap實現的,和Hashmap不同的是它不需要Key和Value兩個值。
往hashset中插入物件其實只不過是內部做了
public boolean add(Object o) {
return map.put(o, PRESENT)==null;
}

hastTable和hashMap的區別:
1)Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map介面的一個實現。
2)這個不同即是最重要的一點:Hashtable中的方法是同步的,而HashMap方法(在預設情況下)是非同步的。即是說,在多執行緒應用程式中,不用專門的操作就安全地可以使用Hashtable了;而對於HashMap,則需要額外的同步機制。
3)只有HashMap可以讓你將空值作為一個表的條目的key或value。HashMap中只有一條記錄可以是一個空的key,但任意數量的條目可以是空的value。這就是說,如果在表中沒有發現搜尋鍵,或者如果發現了搜尋鍵,但它是一個空的值,那麼get()將返回null。如果有必要,用containKey()方法來區別這兩種情況。

執行緒安全的HashMap —— java.util.concurrent.ConcurrentHashMap
ConcurrentHashMap 增加了Segment 層,每個Segment 原理上等同於一個 Hashtable, ConcurrentHashMap 為 Segment 的陣列。
向 ConcurrentHashMap 中插入資料或者讀取資料,首先都要講相應的 Key 對映到對應的 Segment,因此不用鎖定整個類, 只要對單個的 Segment 操作進行上鎖操作就可以了。理論上如果有 n 個 Segment,那麼最多可以同時支援 n 個執行緒的併發訪問,從而大大提高了併發訪問的效率。另外 rehash() 操作也是對單個的 Segment 進行的,所以由 Map 中的資料量增加導致的 rehash 的成本也是比較低的。

ArrayList和LingkedList的區別

1)ArrayList:底層用陣列實現的List
特點:查詢效率高,增刪效率低 輕量級 執行緒不安全
2)LinkedList:底層用雙向迴圈連結串列 實現的List
特點:查詢效率低,增刪效率高

垃圾回收機制

Java的垃圾回收機制是Java虛擬機器提供的能力,用於在空閒時間以不定時的方式動態回收無任何引用的物件佔據的記憶體空間。
需要注意的是:垃圾回收回收的是無任何引用的物件佔據的記憶體空間而不是物件本身。
兩種常用的方法是引用計數和物件引用遍歷。
引用計數:在這種方法中,堆中每個物件(不是引用)都有一個引用計數。當一個物件被建立時,且將該物件分配給一個變數,該變數計數設定為1。當任何其它變數被賦值為這個物件的引用時,計數加1(a = b,則b引用的物件+1),但當一個物件的某個引用超過了生命週期或者被設定為一個新值時,物件的引用計數減1。任何引用計數為0的物件可以被當作垃圾收集。當一個物件被垃圾收集時,它引用的任何物件計數減1。
物件引用遍歷:從一組物件開始,沿著整個物件圖上的每條連結,遞迴確定可到達(reachable)的物件。如果某物件不能從這些根物件的一個(至少一個)到達,則將它作為垃圾收集。

序列化和反序列化

序列化是將物件狀態轉換為可保持或傳輸的格式的過程。與序列化相對的是反序列化,它將流轉換為物件。這兩個過程結合起來,可以輕鬆地儲存和傳輸資料。
序列化的目的  
1、以某種儲存形式使自定義物件持久化;  
2、將物件從一個地方傳遞到另一個地方。  
3、使程式更具維護性
當兩個程序在進行遠端通訊時,彼此可以傳送各種型別的資料。無論是何種型別的資料,都會以二進位制序列的形式在網路上傳送。傳送方需要把這個物件轉換為位元組序列,才能在網路上傳送;接收方則需要把位元組序列再恢復為物件。
把物件轉換為位元組序列的過程稱為物件的序列化。
把位元組序列恢復為物件的過程稱為物件的反序列化。
說的再直接點,序列化的目的就是為了跨程序傳遞格式化資料

Java的靈活性體現在什麼機制上?

反射機制

Sleep和wait的區別

1、sleep()方法,是屬於Thread類中的。而wait()方法,則是屬於Object類中的。
2、在呼叫sleep()方法的過程中,執行緒不會釋放物件鎖。而當呼叫wait()方法的時候,執行緒會放棄物件鎖。
sleep()方法導致了程式暫停執行指定的時間,讓出cpu給其他執行緒,但是他的監控狀態依然保持著,當指定的時間到了又會自動恢復執行狀態。而當呼叫wait()方法的時候,執行緒會放棄物件鎖,進入等待此物件的等待鎖定池,只有針對此物件呼叫notify()方法後本執行緒才進入物件鎖定池準備。

IO和NIO

1、IO是面向流的,NIO是面向緩衝區的。
Java IO面向流意味著每次從流中讀一個或多個位元組,直至讀取所有位元組,它們沒有被快取在任何地方。此外,它不能前後移動流中的資料。如果需要前後移動從流中讀取的資料,需要先將它快取到一個緩衝區。 Java NIO的緩衝導向方法略有不同。資料讀取到一個它稍後處理的緩衝區,需要時可在緩衝區中前後移動。這就增加了處理過程中的靈活性。但是,還需要檢查是否該緩衝區中包含所有您需要處理的資料。而且,需確保當更多的資料讀入緩衝區時,不要覆蓋緩衝區裡尚未處理的資料。
2、Java IO的各種流是阻塞的,Java NIO的非阻塞模式。
Java IO的各種流是阻塞的。這意味著,當一個執行緒呼叫read() 或 write()時,該執行緒被阻塞,直到有一些資料被讀取,或資料完全寫入。該執行緒在此期間不能再幹任何事情了。 Java NIO的非阻塞模式,使一個執行緒從某通道傳送請求讀取資料,但是它僅能得到目前可用的資料,如果目前沒有資料可用時,就什麼都不會獲取。而不是保持執行緒阻塞,所以直至資料變的可以讀取之前,該執行緒可以繼續做其他的事情。 非阻塞寫也是如此。一個執行緒請求寫入一些資料到某通道,但不需要等待它完全寫入,這個執行緒同時可以去做別的事情。 執行緒通常將非阻塞IO的空閒時間用於在其它通道上執行IO操作,所以一個單獨的執行緒現在可以管理多個輸入和輸出通道(channel)。
3、Java NIO的選擇器允許一個單獨的執行緒來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的執行緒來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的執行緒很容易來管理多個通道。而Java IO無選擇器。

Scoket

對於一個功能齊全的Socket,都要包含以下基本結構,其工作過程包含以下四個基本的步驟:
  (1) 建立Socket;
  (2) 開啟連線到Socket的輸入/出流;
  (3) 按照一定的協議對Socket進行讀/寫操作;
  (4) 關閉Socket.
  
  可參考部落格:
http://www.cnblogs.com/linzheng/archive/2011/01/23/1942328.html

深克隆、淺克隆

淺複製僅僅複製所考慮的物件,而不復制它所引用的物件。
深複製把要複製的物件所引用的物件都複製了一遍。

在java中只有單繼承,如果要讓一個類賦予新的特性,通常是使用介面來實現。
在c++中支援多繼承,允許一個子類同時具有多個父類的介面和功能。

UDP和TCP

UDP和TCP都屬於傳輸層協議。
TCP協議:面向連線的、可靠的、基於位元組流
UDP協議:無連線、不可靠、基於報文
1、TCP協議中包含了專門的傳遞保證機制,當資料接收方收到傳送方傳來的資訊時,會自動向傳送方發出確認訊息;傳送方只有在接收到該確認訊息之後才繼續傳送其它資訊,否則將一直等待直到收到確認資訊為止。
與TCP不同,UDP協議並不提供資料傳送的保證機制。如果在從傳送方到接收方的傳遞過程中出現數據報的丟失,協議本身並不能做出任何檢測或提示。因此,通常人們把UDP協議稱為不可靠的傳輸協議。
2、相對於TCP協議,UDP協議的另外一個不同之處在於如何接收突發性的多個數據報。不同於TCP,UDP並不能確保資料的傳送和接收順序。

紅黑樹

是一種自平衡二叉查詢樹,紅黑樹是一種很有意思的平衡檢索樹;每次插入的時候都要進行計算,保證二叉樹的平衡;如果有2的N次方資料量級,查詢的時候只需要查詢N次即可。
我們對任何有效的紅黑樹加以如下增補要求:
1.節點是紅色或黑色。
2.根是黑色。
3.所有葉子(外部節點)都是黑色。
4.每個紅色節點的兩個子節點都是黑色。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點)
5.從每個葉子到根的所有路徑都包含相同數目的黑色節點。
這些約束強制了紅黑樹的關鍵屬性: 從根到葉子的最長的可能路徑不多於最短的可能路徑的兩倍長。結果是這個樹大致上是平衡的。

反射

反射機制指的是程式在執行時能夠獲取自身的資訊。
用反射機制實現對資料庫資料的增、查例子 。
基本原理:儲存資料時,把需要儲存的物件的屬性值全部取出來再拼湊sql語句;查詢時,將查詢到的資料全部包裝成一個java物件。
1)資料庫的每一個表對應一個pojo類,表中的每一個欄位對應pojo類的中的一個屬性。 並且pojo類的名字和表的名字相同,屬性名和欄位名相同,大小寫沒有關係,因為資料庫一般不區分大小寫
2)為pojo類中的每一個屬性新增標準的set和get方法。

三次握手和四次揮手

三次握手:首先Client端傳送連線請求報文,Server段接受連線後回覆ACK報文,併為這次連線分配資源。Client端接收到ACK報文後也向Server段傳送ACK報文,並分配資源,這樣TCP連線就建立了。

四次握手:
由於TCP連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
(1) TCP客戶端傳送一個FIN,用來關閉客戶到伺服器的資料傳送。
(2) 伺服器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1。和SYN一樣,一個FIN將佔用一個序號。
(3) 伺服器關閉客戶端的連線,傳送一個FIN給客戶端。
(4) 客戶端發回ACK報文確認,並將確認序號設定為收到序號加1。

Equals()和== 

  1、java中equals和==的區別 值型別是儲存在記憶體中的堆疊(簡稱棧),而引用型別的變數在棧中僅僅是儲存引用型別變數的地址,而其本身則儲存在堆中。
  2、==操作比較的是兩個變數的值是否相等,對於引用型變量表示的是兩個變數在堆中儲存的地址是否相同,即棧中的內容是否相同。
  3、equals操作表示的兩個變數是否是對同一個物件的引用,即堆中的內容是否相同。
  4、==比較的是2個物件的地址,而equals比較的是2個物件的內容,顯然,當equals為true時,==不一定為true。