1. 程式人生 > >java知識點總結

java知識點總結

1、JDK和JRE的區別

JDK是java的開發工具集,包含編譯工具(javac)和打包工具(jar)等。他還包含jre。(所以安裝jdk就可以了,不需要單獨裝jre)。

JRE是java執行環境,他包含java的核心類庫和jvm虛擬機器。

2、java程式執行機制

編寫好原始檔(.java檔案)以後,通過jdk中的編譯指令(javac)進行編譯,生成位元組碼檔案(.class檔案),然後通過jvm虛擬機器進行載入,執行,最後執行出結果

3、垃圾回收機制

在java中,當一個物件不再被引用時,就會被垃圾回收機制(GC)處理掉。垃圾回收機制的工作內容就是回收無用物件的所佔的記憶體空間,這些記憶體空間都是jvm堆記憶體的記憶體空間,垃圾回收只能回收記憶體資源,對物理資源無法回收(如資料庫連線、io流等資源)。導致java記憶體溢位的原因就是無用物件沒有被GC機制處理掉,而一直佔用著記憶體空間。

堆記憶體和棧記憶體的區別:當一個方法執行時,會建立屬於自己的記憶體棧。當方法執行結束後,對應的記憶體棧也會隨之銷燬。在程式中建立一個物件時,該物件會儲存在堆記憶體中,這個物件中的方法會被反覆呼叫,當這個物件失去引用時,就會被垃圾回收機制處理掉。在宣告並建立一個物件的時候,引用儲存在棧記憶體,物件則儲存在堆記憶體。

在垃圾回收機制回收任何物件之前,總會先呼叫finalize()方法。該方法可能回使該物件復活(重新被引用),從而導致垃圾回收機制取消回收。當一個物件在堆記憶體中執行時,根據它被引用變數所引用的狀態可以把它所處的狀態分為以下三種:

(1)可達狀態:當一個物件被建立以後,如果有一個及一個以上的引用變數引用它的時候,這個物件就處於可達狀態,程式可以通過引用變數來呼叫該物件的方法和屬性。

(2)可恢復狀態:當一個物件在程式中不再有任何引用變數引用它的時候,即為可恢復狀態。這種狀態下,系統的垃圾回收機制就會準備回收該物件所佔用的記憶體,在回收之前,會呼叫該物件的finalize()方法,這個方法執行後,可能會讓該物件重新被引用變數所引用,這時便回到了可達狀態,如果沒有被引用,則會進入不可達狀態。

(3)不可達狀態:當一個物件切斷了所有和引用變數之間的引用,並且系統已經呼叫了finalize()方法之後,該物件仍然沒有變成可達狀態,那麼這個物件將永久的失去引用,成為了不可達狀態。這時,系統的垃圾回收機制才會對該物件所佔用的記憶體進行回收。

由於系統的垃圾回收機制存在時間、執行上的不確定性,java還提供了強制垃圾回收,這種強制只是通知系統進行垃圾回收

。但是系統是否進行垃圾回收仍然不確定。但大部分時候,強制回收都會有一些效果。強制垃圾回收存在以下兩種方式:System.gc();Runtime.getRuntime().gc();

關於物件的引用方式分為4種:(1)強引用:該引用是最常見的一種引用方式,程式中建立一個物件並把該物件直接賦給一個引用變數。程式通過該引用變數來呼叫該物件的方法和屬性,當一個物件被一個或一個以上引用變數引用時,該物件就處於可達狀態,不會被垃圾回收機制回收。(2)軟引用:軟引用通過SoftReference類來實現,當一個物件只有軟引用時,有可能被垃圾回收機制回收。對於只有軟引用的物件而言,當系統記憶體充足時,他不會被回收,當記憶體不足時,可能被垃圾回收機制回收。軟引用通常被應用到記憶體敏感的程式中。(3)弱引用:弱引用通過WeakReference類實現,他和軟引用很像,但是引用級別更低,當垃圾回收機制執行時,不論記憶體是否充足,弱引用所引用的物件都會被處理掉。(4)虛引用:虛引用通過PhantomReference類來實現,虛引用類似於物件沒有引用,如果物件只有一個虛引用,那麼他和沒有引用的狀態幾乎相同。虛引用主要用於跟蹤物件被垃圾回收的狀態。

4、基本資料型別

byte(位元組型)、char(字元型)、boolean(布林型)、short(短整型)、int(整型)、long(長整型)、float(單精度浮點型)、double(雙精度浮點型)

小的型別轉大的型別,自動轉換,大轉小,需要做強轉。

基本資料型別和包裝類的之間的相互轉換:如基本資料型別 int a=2; 轉成int的包裝類Integer Integer b=new Integer(a); 包裝類轉換成基本資料型別 int c=b.intValue();其他型別也是如此。在java的1.5以後出現了新特性:可以自動拆裝箱。即 int a=2; Integer b=a;

java中的資料型別分為基本資料型別和引用型別,基本資料型別就是上面列出的那些,引用型別一般是自己建立的java類,但是String也屬於引用型別。

5、陣列

int[] a;   宣告陣列   a=new int[5]  動態初始化陣列  a={1,2,3,4} 靜態初始化陣列

6、面向物件

面向物件三大特徵:封裝、繼承、多型。面向過程:強調的是功能行為,先幹啥,再幹啥。面向物件:強調的是具備某種功能的物件。關於多型就是:父類變數可以直接指向子類的例項化物件。反過來子類變數也可以直接指向父類的例項化物件(需要強轉)。

7、類

類是對一種事物的共同點的一種抽象,將一組事物的公共點抽象出來。物件則是具體的,具備這些公共點的具體事務。關於類中的構造方法,多個建構函式說簡單點就是方法過載。

8、static關鍵字

static用於修飾類中的方法和屬性,被它修飾的方法可以通過類名來呼叫。它隨著類的載入而載入,優先於物件存在。

9、程式碼塊

程式碼塊就是指使用“{}”括起來的一段程式碼,程式碼塊可以分為4種:

1、普通程式碼塊

java類中直接定義的方法。如 

public void test(){
System.out.print(123);
}

2、構造程式碼塊

直接定義在java類中的程式碼塊。如 

{
System.out.print(456);
} //構造程式碼塊優先於建構函式執行,每次例項化物件之前都會先執行構造程式碼塊。

3、靜態程式碼塊

使用static關鍵字來修飾的程式碼塊。如 

static {
System.out.print(789);
}  //優先於主方法執行,優先於構造程式碼塊執行,只執行一次,可以用於給靜態變數賦值。

4、同步程式碼塊

synchronized(obj){
    //同步程式碼塊內容
}

在使用多執行緒程式設計的時候,會出現併發問題,並導致資料出現錯誤,這時需要將方法中可能會導致執行緒問題的程式碼放入同步程式碼塊中,並傳遞相應引數。這樣,當程式執行到這個程式碼塊的時候,會通過傳遞的引數來鎖定執行的執行緒。以此來避免資料錯誤的問題。

10、Singleton模式(單例模式) 餓漢式和懶漢式

目的:在整個應用中有且只能有一個例項,所有指向該型別的引用都指向該例項。

餓漢式例項:直接將例項定義出來

class SingleDemo{
    private static SingleDemo s1=new SingleDemo();
    private SingleDemo(){
        //將建構函式私有化,這樣外部就不能例項化該類了
    }
    public static SingleDemo getSingle(){
        return s1;
    }
}

懶漢式例項:只給變數,不給例項初始化

class SingleDemo{
    private static SingleDemo s1;
    private SingleDemo(){
        //將建構函式私有化,這樣外部就不能例項化該類了
    }
    public static SingleDemo getSingle() 
   {
        if(s1==null){
            s1=new SingleDemo();
        }
        return s1;
    }
}

這兩種方式都使用static修飾,但餓漢式直接將例項定義出來,因為static的緣故,每次都會隨著類的載入而載入,會損耗效能,但相對簡單。懶漢式只會第一次載入較慢,但執行緒不安全。

11、抽象類

通過abstract關鍵字來修飾的類叫做抽象類,抽象類不能被例項化,抽象類中可以包含抽象方法和普通方法,抽象方法也是通過abstract來修飾,並且抽象方法只能做宣告,不能有內容。如果一個類繼承了一個抽象類,就必須實現他的所有抽象方法。

12、抽象類的體現-模板模式

抽象類是多個具體子類抽象出來的父類,以該抽象類作為子類的模板可以避免子類設計的隨意性。抽象類的體現主要就是模板設計模式。抽象父類只定義用到的某些方法,具體交給子類去實現。抽象方法不能定義void返回型別。

13、介面

介面相當於更加抽象的抽象類,介面中全是抽象方法,介面之間可以實現多繼承。一個類可以實現多個介面。介面不能被例項化,但是可以宣告介面並指向他的實現類。

14、面向介面程式設計之簡單工廠模式

簡單來說就是構建一個工廠出來,在裡面進行建立,用的時候直接傳遞引數來用。這樣做的好處:可以遮蔽不同子類實現的差異,提高程式碼的可拓展性和可維護性。

interface Phone{//制定標準,要實現的介面
    public void send();
}
//實現介面
class IPhone implements Phone{
    public void send(){
        System.out.print("IPhone在傳送簡訊");
    }
}
class AndroidPhone implements Phone{
    public void send(){
        System.out.print("AndroidPhone在傳送簡訊");
    }
}
class MyPhone implements Phone{
    public void send(){
        System.out.print("我的手機在傳送簡訊");
    }
}
//建立工廠
class Factory{
    public static void show(String s){
        if(s.equals("")){
            System.out.print("您的輸入為空");
            return;
        }
        //宣告介面
        Phone p=null;
        if(s.equals("IPhone")){
            p=new IPhone();
        }else if(s.equals("AndroidPhone")){
            p=new AndroidPhone();
        }else if(s.equals("MyPhone")){
            p=new MyPhone();
        }
        p.send();
    }
}
//呼叫該工廠
class Test{
    public static void main(String[] args){
        new Factory().show("");
        new Factory().show("IPhone");
        new Factory().show("AndroidPhone");
        new Factory().show("MyPhone");
    }
}
//執行結果:您的輸入為空、IPhone在傳送簡訊、AndroidPhone在傳送簡訊、我的手機在傳送簡訊

15、面向介面程式設計之介面卡模式

有一個現成的類,但是他實現的介面的方法只有一個方法是你需要的,別的都不需要,這是就需要使用介面卡模式。

//定義介面,包含如下方法:open()、close()、loading(),最終只想用loading方法
interface Window{
    void open();
    void loading();
    void close();
}
//定義一個類,實現上述介面
class AdapterWindow implements Window{
    public void open(){
        System.out.print("開啟");
    }
    public void loading(){
        System.out.print("載入中");
    }
    public void close(){
        System.out.print("關閉");
    }
}
//在定義一個類,繼承上邊的類,複寫loading方法
class MyWindow extends AdapterWindow{
    //覆寫父類的方法
    public void loading(){
        System.out.print("正在載入中");
    }
}
//呼叫測試
class Test{
    public static void main(String[] args){
        new MyWindow().loading();
    }
}
//顯示結果:正在載入中

16、內部類

在一些情況下,一個類會被定義到另一個類的內部,這個定義在其他類內部的類叫做內部類(巢狀類)。包含內部類的類被稱作外部類。內部類相當於外部類的成員,所以內部類可以訪問其外部類的其他成員。但是外部類不能訪問其內部類的實現細節,比如內部類的成員變數。匿名內部類適用於建立那些只需要使用一次的類。內部類的定義和正常類的定義基本相同,只是多了三個修飾符:private、protected、static。

大部分時候內部類都會被作為成員內部類。而區域性內部類和匿名內部類都不屬於類成員。

17、匿名內部類

匿名內部類適用於那些只需要使用一次的類。他不能重複使用。

new 父類構造器(引數列表)|實現介面()  
    {  
     //匿名內部類的類體部分  
    }

18、列舉類

列舉類通過enum關鍵字來定義,建立的列舉類預設繼承java.lang.enum類而不是object類。該類實現了java.lang.Serializable介面和java.lang.Comparable兩個介面。使用enum建立的非抽象的列舉類預設被final修飾,所以列舉類不能衍生子類。列舉類的構造器只能使用private。並且列舉類的例項必須在第一行顯示列出,否則永遠不能建立列舉類。

非執行緒安全是指多執行緒操作同一個物件可能會出現問題。而執行緒安全則是多執行緒操作同一個物件不會有問題。

19、String類、StringBuffer類和StringBuilder類

字串就是一連串的字元序列,String類是不可變類,該物件一旦被建立以後就不能改變,直到銷燬。StringBuffer則是一個字元序列可變的字串,有相關的一些系列方法,同時可以通過toString()方法將StringBuffer物件轉換成String物件。JDK1.5以後增加了StringBuilder類,該類和StringBuffer類功能上幾乎相同。不同的是StringBuffer是執行緒安全的,StringBuilder是執行緒不安全的,但StringBuilder的效能相對較高。

20、java集合類

java的集合類主要由兩個介面衍生,分別是Collection和Map。這兩個介面包含了一些子介面和實現類。其中,Set和List是Collection派生出來的子介面,分別代表了無序集合和有序集合。(Queue也是Collection下派生出來的,它是佇列)

List和Set的異同點:List元素可重複、元素有序(和新增順序一致)、元素可為空。Set元素不可重複、元素無序、元素可為空

List子類:ArrayList(常用)、LinkedList、Vector

ArrayList底層資料結構是順序儲存(便於查詢),LinkedList底層資料結構是連結串列(便於儲存)(同時LinkedList也可以還實現了‘雙端佇列’,即可以當作佇列來用,也可以當作來使用)。Vecotor和ArrayList差不多,但是執行緒安全,這也就意味著它速率比ArrayList慢。

Set子類:HashSet(常用)、TreeSet、EnumSet

HashSet底層資料結構是雜湊表結構,便於查詢和刪除,新增慢。向HashSet中儲存自定義物件需要重寫hashCode()和equals()方法。TreeSet底層資料結構是二叉樹,資料越多越慢。EnumSet是專門為列舉型別存在的集合類。

Queue佇列子類:PriorityQueue、ArrayDeque

PriorityQueue沒有按照佇列‘先進先出’的標準來讀取,而是按照大小來讀取,每次取得資料都是佇列中最小的元素。並且PeiorityQueue不允許儲存空值。

ArrayDeque則是一個雙端佇列,它既可以當作‘先進先出’的佇列來使用,也可以當作‘後進先出’的棧來使用。

Map子類:HashMap(常用)、HashTable、LinkedHashMap、Properties、TreeMap、WeakHashMap、EnumMap

HashMap效率高,執行緒不安全。由於他的key不能重複,所以只能有一個key為null,但是value可以隨意null。

HashTable效率相對差一些,執行緒安全。他的key和value都不允許為null。

LinkedHashMap作為HashMap的子類,底層則使用了雙向連結串列。使用它儲存遍歷資料時,她會按照儲存時的順序來進行讀取。它的效能略低於HashMap。

Properties則是HashTable的子類,通過它可以很方便的讀寫屬性檔案。它包含讀寫檔案的相關方法,除此之外,他相當於一個key、value都是String的Map。

TreeMap向名字說的那樣,底層實現就是二叉樹。

WeakHashMap中的key是弱引用,當執行垃圾回收機制時,map中的鍵值對會被清除。而HashMap中的key是強引用,除非HashMap失去引用,否則永遠不會被垃圾回收機制處理。

21、異常處理

java異常分為Error和RuntimeException兩種型別。在寫catch塊的時候如果可能涉及到多個異常,要先將小的異常放在前邊,大的異常放在後邊。否則會引起編譯錯誤。因為大的異常已經包含小的異常。除非在try、catch塊中呼叫退出虛擬機器的方法System.exit(1);finally塊中的程式碼不會執行。否則無論怎樣都會被執行。

在java7以後,出現了增強try語句的功能,在try後邊緊跟一對兒小括號,並且在小括號裡面宣告並初始化一些資源類的物件。(這裡的資源指的是資料庫連線、IO流之類的)這些物件可以不用通過finally塊自動釋放資源。但是這些類都必須實現AutoCloseable或者Closeable介面。自動關閉資源的try語句相當於包含隱式的finally塊。

在catch塊捕獲到一個異常以後,接著丟擲另一個異常,並把原始異常欣喜儲存起來是一種典型的鏈式處理(也稱作職責鏈模式)。

22、資料庫

資料庫的索引相當於一本書的目錄,當給資料庫表格的某個欄位新增索引以後,可以提高查詢速度。新增索引的語句格式如下:create index index_name on table_name(列名...);其中列名可以是多個。

資料庫事務:資料庫事務是由一步或幾步組成的邏輯執行單元,這一系列操作要麼全部執行,要麼全部不執行。事務具備以下四個特性:原子性、一致性、隔離性、持續性。

資料庫連線池:當程式啟動時,系統會主動建立多個數據庫連線,並通過這些資料庫連線組成一個連線池。每次程式請求資料庫連線時,不會新建資料庫連線,而是去連線池中取出已有的連線。使用完以後,不會關閉該連線,而是將該資料庫連線返還給連線池。通過使用連線池可以大大提高效率。

23、java註解

java的註解分為系統提供的註解和自定義的註解。註解的主要作用有以下幾點:1、提供資訊給編輯器(編輯器可以利用註解來探測錯誤和警告資訊)。2、編譯階段時的處理(軟體工具可以利用註解資訊來生成程式碼、html文件或是做其他處理)。3、*執行時的處理(一些註解可以接受執行時程式碼的提取)。最常用的就是這個功能,可以通過反射來提取註解的相關資訊。

系統提供的註解有以下幾種:@Deprecated   該註解用於標識已過時的元素。@Override 該註解標識正在複寫父類的方法(通常會在介面的實現類的方法上看到)。@SuppressWarnings  該註解會取消已過時的元素的警告  @SafeVarargs 引數安全型別的註解  @FunctionalInterface  函式式介面註解 

自定義註解:註解通過  @interface 關鍵字進行定義。

public @interface testAnnotation{
}

@testAnnotation
public class Test{
}
//上邊的程式碼自定義並應用了一個註解

註解的定義和介面十分相似,只是在interface前邊加上一個@。不過,這樣定義的註解並沒有什麼意義,想要自定義的註解有實用性,需要在自定義註解上新增元註解元註解就是可以註解到註解上的註解。元註解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 種。

@Retention

Retention 的英文意為保留期的意思。當 @Retention 應用到一個註解上的時候,它解釋說明了這個註解的的存活時間。

它的取值如下: 
- RetentionPolicy.SOURCE 註解只在原始碼階段保留,在編譯器進行編譯時它將被丟棄忽視。 
- RetentionPolicy.CLASS 註解只被保留到編譯進行的時候,它並不會被載入到 JVM 中。 
- RetentionPolicy.RUNTIME 註解可以保留到程式執行的時候,它會被載入進入到 JVM 中,所以在程式執行時可以獲取到它們(常用)。只有存活到程式執行時的註解才能通過反射來讀取到註解資訊。

@Documented

顧名思義。它的作用是能夠將註解中的元素包含到 Javadoc 中去。

@Target

Target 是目標的意思,@Target 指定了註解運用的地方。@Target 有下面的取值:

  • ElementType.ANNOTATION_TYPE 可以給一個註解進行註解
  • ElementType.CONSTRUCTOR 可以給構造方法進行註解
  • ElementType.FIELD 可以給屬性進行註解
  • ElementType.LOCAL_VARIABLE 可以給區域性變數進行註解
  • ElementType.METHOD 可以給方法進行註解
  • ElementType.PACKAGE 可以給一個包進行註解
  • ElementType.PARAMETER 可以給一個方法內的引數進行註解
  • ElementType.TYPE 可以給一個型別進行註解,比如類、介面、列舉

@Inherited

Inherited 是繼承的意思,但是它並不是說註解本身可以繼承,而是說如果一個超類被 @Inherited 註解過的註解進行註解的話,那麼如果它的子類沒有被任何註解應用的話,那麼這個子類就繼承了超類的註解。 
說的比較抽象。程式碼來解釋。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}


@Test
public class A {}


public class B extends A {}

註解 Test 被 @Inherited 修飾,之後類 A 被 Test 註解,類 B 繼承 A,類 B 也擁有 Test 這個註解。

@Repeatable

Repeatable 自然是可重複的意思。@Repeatable 是 Java 1.8 才加進來的,所以算是一個新的特性。

什麼樣的註解會多次應用呢?通常是註解的值可以同時取多個。

舉個例子,一個人他既是程式設計師又是產品經理,同時他還是個畫家。


@interface Persons {
    Person[]  value();
}


@Repeatable(Persons.class)
@interface Person{
    String role default "";
}


@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{

}

注意上面的程式碼,@Repeatable 註解了 Person。而 @Repeatable 後面括號中的類相當於一個容器註解。

什麼是容器註解呢?就是用來存放其它註解的地方。它本身也是一個註解。

註解屬性:註解的屬性也稱作成員變數,註解只包含成員變數,沒有方法。註解在定義成員變數時,形式很特別。他採用的是“無形參的方法”來進行定義的。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    int id();

    String msg();

}

上面程式碼定義了 TestAnnotation 這個註解中擁有 id 和 msg 兩個屬性。在使用的時候,我們應該給它們進行賦值。

賦值的方式是在註解的括號內以 value=”” 形式,多個屬性之前用 ,隔開。

@TestAnnotation(id=3,msg="hello annotation")
public class Test {

}

需要注意的是,在註解中定義屬性時它的型別必須是 8 種基本資料型別外加 類、介面、註解及它們的陣列。

註解中屬性可以有預設值,預設值需要用 default 關鍵值指定。比如:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    public int id() default -1;

    public String msg() default "Hi";

}

TestAnnotation 中 id 屬性預設值為 -1,msg 屬性預設值為 Hi。 
它可以這樣應用。

@TestAnnotation()
public class Test {}

因為有預設值,所以無需要再在 @TestAnnotation 後面的括號裡面進行賦值了,這一步可以省略。

另外,還有一種情況。如果一個註解內僅僅只有一個名字為 value 的屬性時,應用這個註解時可以直接接屬性值填寫到括號內。

public @interface Check {
    String value();
}

上面程式碼中,Check 這個註解只有 value 這個屬性。所以可以這樣應用。

@Check("hi")
int a;

這和下面的效果是一樣的

@Check(value="hi")
int a;

最後,還需要注意的一種情況是一個註解沒有任何屬性。比如

public @interface Perform {}

那麼在應用這個註解的時候,括號都可以省略。

@Perform
public void testMethod(){}

24、mybatis一級快取與二級快取

 快取存在的意義就是為了提高程式效能,減少資料庫壓力。

mybatis的一級快取預設為開啟狀態,一級快取是sqlSession級別的快取,在使用mybatis作為持久層框架時,當需要操作資料庫時,需要構建sqlSession物件,在這個物件中有一個數據結構(HashMap)使用者儲存快取資料。不同的sqlSession之間的資料不共享。當需要對資料庫進行增刪改操作時,需要清空快取。這樣可以避免髒讀。一級快取就是同一個sqlSession物件下,如果多次呼叫同一個查詢語句,並且傳遞的引數一致,這樣就只有第一次查詢需要走sql語句,其餘的查詢都會走快取。二級快取則是mapper級別的快取,mybatis的二級快取需要手動在mapper中配置,二級快取的作用範圍相對於一級快取更大,多個sqlSession物件之間可以共享快取資料。

25、IO流

java通過輸入、輸出流來控制檔案,他分為兩種,分別是位元組流和字元流。除了操作的資料單位不同,用法幾乎都一樣。java所有的IO流都是以這兩種流為基礎的。RandomAccessFile類可以用來給檔案追加內容,或者在檔案中間插入內容。IO子類根據具體需求去查文件即可。

26、物件序列化

java物件序列化的目的就是將java物件儲存到磁碟中或者在網路中直接傳輸物件。物件序列化機制把java物件轉換成和平臺無關的二進位制流。物件的序列化簡單說就是將java物件存入IO流中,與之對應的則是java的反序列化,他是通過IO流將java物件恢復。如果想讓某個java物件支援序列化機制,就需要實現Serializable或者Externalizable這兩個介面之一。

27、NIO

NIO意為new IO 就是新的IO流。新的IO流採用了不同的方式來處理檔案的輸入和輸出。新IO主要就是使用記憶體對映檔案的方式。就是將檔案或者檔案的部分內容對映到記憶體中。這樣就可以像訪問記憶體一樣訪問檔案內容了。Channel(通道)和Buffer(緩衝)是NIO的兩個核心物件。Channel和傳統IO最大的區別就是他有一個map()方法。他可以將一塊資料直接對映到記憶體中。傳統的IO是面向流的處理,NIO則是面向塊的處理。

從檔案轉換到二進位制的過程叫做編碼,從二進位制到檔案的過程叫做解碼。(字元到位元組:編碼。位元組到字元:解碼)

28、多執行緒

執行緒和程序:作業系統可以執行多個任務,每個任務就是程序。程序可以執行多個任務,每個任務就是執行緒。

併發性:在同一時刻只能有一條指令執行,對於cpu而言,在某一個時間點只能執行一個程式,因為cpu的執行速度特別快,才會給人覺得多個程式在同時執行。

多執行緒的建立(1):繼承Thread類,實現run()方法。run()方法就是執行緒的執行體。執行緒啟動:new 子類().start() *使用繼承Thread類來建立的執行緒類,多個執行緒無法共享執行緒類的例項變數。

多執行緒的建立(2):實現Runnable介面,實現run()方法。run()方法就是執行緒的執行體。執行緒啟動:new Thread(Runnable實現類).start()*實現Runnable介面來建立的執行緒類,多個執行緒共享執行緒類的例項變數。

多執行緒的建立(3):實現Callable介面,實現call()方法。該方法返回一個泛型結果。將該實現類作為引數例項化一個FutureTask類。FutureTask實現了Runnable介面。*通過這種方式建立的執行緒,多個執行緒共享執行緒類的例項變數。一般使用下邊兩種方式實現多執行緒。

執行緒的生命週期分為以下5種狀態:新建、就緒、執行、阻塞、死亡。對於已經死亡或者已經呼叫過start()方法的執行緒,不能再次呼叫start()方法,否則會引發執行緒異常。Thread類下提供了一系列控制執行緒的方法,join()方法。在程式執行流程中,當一個執行緒呼叫join()方法後,會立即阻塞當前執行的執行緒,並執行呼叫join的執行緒,直到呼叫join的執行緒執行結束。setDaemon(true)方法。當一個執行緒呼叫該方法後,就會變成守護執行緒(也稱作後臺執行緒)。他的任務就是為其他執行緒提供服務,當程式中所有前臺執行緒都死亡以後,後臺執行緒才會死亡,否則會一直存活。(jvm的垃圾回收執行緒就屬於後臺執行緒)類方法sleep()方法。呼叫sleep()方法可以讓當前執行的執行緒由執行狀態變為阻塞狀態,該方法可以設定阻塞時間。類方法yield()方法。呼叫yield()方法可以讓當前執行的執行緒由執行狀態變為就緒狀態。呼叫該方法可能會使執行緒指停止一瞬間又被執行緒排程器重新呼叫。(該方法也可以讓執行緒停止執行。但通常使用sleep()方法)執行緒存在優先順序的概念,優先順序高的執行緒會獲得較多的執行機會。執行緒可以手動設定優先順序。

在使用多執行緒程式設計的時候,由於多執行緒的併發性,可能會導致多個執行緒併發操作同一個資料的時候出現數據錯誤。這時就需要使用到同步程式碼塊或者同步方法。同步程式碼塊和同步方法可以阻止多個執行緒對他們的同一個共享資源做併發訪問。只需在可能出現執行緒安全問題的方法上加synchronized修飾即可。同步程式碼塊和同步方法都屬於隱式的控制執行緒同步。java5以後出現了顯式的執行緒同步控制。就是Lock。其中最常用的就是ReentrantLock類。在類中宣告並定義例項化一個ReentrantLock的常量。在有執行緒問題的方法裡面呼叫lock()方法加鎖。在方法結束的時候呼叫unlock()方法解鎖。這樣就能顯式的控制執行緒問題了。

執行緒通訊:在多執行緒的程式中,由於執行緒排程器的隨機性,無法準確控制執行緒的輪換執行。java也提供了一些機制來控制執行緒的協調執行。針對隱式的執行緒控制,提供了wait()【讓執行緒等待】、notify()【讓執行緒繼續執行】、notifyAll()【讓執行緒全部執行】等Object類的方法來控制。其中如果使用的是同步程式碼塊,這些方法則由程式碼塊傳遞的引數來呼叫。如果是同步方法,則直接呼叫。針對顯式的執行緒控制Lock,則提供了Condition類。該類的物件由Lock的newCondition()方法獲取。該類也提供了三個類似的方法,分別是await()signal()signalAll()

執行緒組:簡單來說就是一個裝載執行緒的陣列。通過它可以對多個執行緒進行統一控制。

執行緒池:與資料庫連線池的概念類似。當系統多次建立執行緒的時候是非常消耗效能的,這時就需要用到執行緒池。執行緒池在系統啟動時會建立一定數量的空閒執行緒。通過執行緒池可以有效的控制系統中執行緒併發的數量。程式將Runnable物件或者Callable物件傳給執行緒池,執行緒池就會啟動一個執行緒來執行他的run()或者call()方法。當執行結束後,該執行緒不會死亡,而是重新來到空閒狀態。等待執行下一個Runnable物件或者Callable物件。

29、反射

每個類被jvm虛擬機器載入之後,都會生成一個Class物件。通過這個Class物件就可以訪問jvm中的這個類。獲取這個Class物件通常有三種方式:Class.forName("該類的完整包名")、類名.Class、物件.getClass()、獲取到Class物件以後,可以根據該物件獲取該類的構造方法、屬性、方法、註解等。具體操作檢視文件即可。java框架的配置檔案就是通過Properties來讀取,再通過反射建立相關物件。

30、動態代理

在java中,想要實現動態代理需要用到Proxy類和InvocationHandler介面,首先把需要被代理的類抽象成一個介面,建立一個需要被代理的類的物件,這個類需要實現該介面。然後再次建立一個類實現InvocationHandler介面,該介面需要設定一個屬性,用來接收被代理的例項(通過建構函式設定即可,因為Invoke方法引數的緣故,需要將代理例項轉換成Object)。該介面中有一個invoke方法需要實現(這個方法就是生成的動態代理類每次呼叫被代理的物件方法的方法,在此方法中還可以在呼叫的基礎上作其他附加處理)。準備好這兩個類後,通過Proxy的newProxyInstance(常用)方法來建立動態代理類。該方法接收三個引數。分別是類載入器、陣列型別的代理介面、InvocationHandler的例項物件。通過這個方法返回一個Object物件,再將該物件轉換成被代理的型別,就可以實現呼叫被代理的方法了,每次呼叫方法實際上呼叫的都是InvocationHandler介面的invoke方法。newProxyInstance方法返回的動態代理物件,Proxy還提供了一個返回動態代理類的方法getProxyClass(不常用)

31、Spring IOC實現原理

Spring框架通過容器來管理物件的生命週期,通過beanFactory來建立bean物件。beanFactory的實現原理就是簡單工廠模式。一般的簡單工廠模式需要傳遞用於區分的類的引數,這裡需要將傳參改造一下,改成反射的方式。通過傳遞的完整類名,以反射的方式來建立物件。beanFactory的實現思路如下:將編寫好的xml配置檔案通過程式碼進行解析(dom4j或者其他解析xml的工具)。將解析出來的完整類名傳遞給改造完的beanFactory,通過反射的方式進行建立物件。