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

java基礎知識總結

ant 共享方式 而且 file processor 此外 輸入流 執行 color

1、基本:

  1.1、關於面向對象的特征:

    有四個基本特征:繼承、封裝、抽象、多態。

    繼承:子類繼承父類,是弗雷德一個特殊化的實例,子類繼承父類的方法以及屬性(不包括private修飾符下的),子類可以super關鍵字顯示調用父類屬性及方法,子類的無參構造函數會默認調用父類無參構造函數。

    封裝:對數據以及行為的封裝,將信息封裝到具體的對象中,雖然看上去步驟增加了,變復雜了,但是能更好的保證數據的安全性。

    抽象:對數據和行為的抽象,定義方法,等待子類或者實現類的具體去實現

    多態:多態有點類似於上面的整合,我理解的定義是:調用一個相同的方法,中間進行的行為和最終獲得結果卻是不同的(方法的重寫,重載);重寫與重載的區別:重寫是定義全部保持一致(拋出的異常可以小於等於父類的範圍),但是內部的邏輯是不同於之前的,通常應用在子類的實現場景下;而對於重載則更加靈活,一同:方法名的相同;3不同:方法參數個數不同,類型不同,返回值可以不同(若其他都相同,只有返回值不同是不可以的)

  1.2、final,finalize,finally的區別

    final:可修飾類、屬性、方法,表示不可被繼承,不可被改變,不可被重寫以及重載

    finalize:準確來說是finalize(),在jvm進行GC操作的時候會在不確定的時間調用這個函數(有且僅調用一次),其主要的目的是為了釋放資源,但是後續的finally可以完美的替代finalize(),finally會保證方法調用最後一定會執行此方法中的內容;

  1.3、int與Integer的區別

    首先int是java中的關鍵字,是八種基本類型(byte,short,int,long,char,boolean,float,double)中的其中一種,而Integer是一個包裝類(在於int相關操作時,會自動裝箱\拆箱eq:Integer對象與int進行==操作時,比較的是真正的值而不是引用 ,在int取值範圍中-128-127之間兩個非new Integer()的==比較是true的       

               Integer i1 = 100;

               Integer i2 = 100; i1==i2 輸出為true

               關鍵是明白對象的原理(new 代表的是引用)

               java對於-128到127之間的數,會進行緩存,Integer i = 127時,會將127進行緩存,下次再寫Integer j = 127時,就會直接從緩存中取,就不會new了

),使用Integer必須進行初始化(因為是類),它的初始值null,int初始值為0;

  1.4、抽象類和接口的區別

    1、修飾符的不一樣,抽象類abstract,接口interface。

    2、與一般的類相比較:抽象類增加了抽象的概念,可以定義抽象方法,繼承它的子類必須實現這個抽象方法,其他差不多;接口裏面只有抽象方法(java8中可以有默認的方法),而且其中的屬性固定是public static final類型的;抽象類和接口都不能被final修飾符修飾。

  1.5、反射的用途及實現

    首先我們知道java是一個編譯性語言,但是他卻支持運行期語言(反射),反射是在程序運行期進行操作的,反射可以得到一個類的所有信息包括私有屬性。在各大框架底層的實現中都用到了反射的原理,比如spring中,對於bean的創建就運用了反射的原理實現,而且在你日常使用IDE進行編程的時,當你new出一個對象時,你可以使用 . 進行訪問類中的信息也是反射的原理。

  1.6、如何進行序列化

    序列化是值將一個對象轉成二進制文件存儲在磁盤中或進行傳輸,前提需要此對象實現 Serializable 接口,每個要進行序列化的類都有一個static final的id屬性(標識這個序列化對象);其中涉及到的輸入輸出流對象有以下幾種

    1、ObjectOutputStream:將對象寫出到文件中 FileOutputStream在本地創建一個文件等待寫入文件的輸出流

      ObjectInputStream:將對象從文件流中讀取到JVM中 FileInputStream讀取一個文件的輸入流

    2、ByteArrayOutputStream out = new ByteArrayOutputStream();//字節數組輸出流

      ObjectOutputStream obj = new ObjectOutputStream(out);//對象輸出流

      //讀取輸出流中的對象

      ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new java.io.ByteArrayInputStream(out.toByteArray())));

  1.7關於自定義的註解

    使用場景:如要降低代碼的耦合性,替代配置文件,在一個方法運行中,可以額外賦值。

    1.7.1、首先你新建一個自定義註解類如圖1.7-1:要註意以下幾點:

      @Target 標識你這個註解類可以作用的範圍,主要有:

        1.CONSTRUCTOR:用於描述構造器
        2.FIELD:用於描述域
        3.LOCAL_VARIABLE:用於描述局部變量
        4.METHOD:用於描述方法
        5.PACKAGE:用於描述包
        6.PARAMETER:用於描述參數
        7.TYPE:用於描述類、接口(包括註解類型) 或enum聲明)

    @Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請註意並不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。

  作用:表示需要在什麽級別保存該註釋信息,用於描述註解的生命周期(即:被描述的註解在什麽範圍內有效)

  取值(RetentionPoicy)有:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在運行時有效(即運行時保留)

    @Document標識可以被jdoc識別

    技術分享圖片

                      1.7.1-1

    1.7.2、自定義註解類的標識是@interface,權限修飾符只有兩種default和public,在自定義註解類中你可以使用default關鍵字,給頂一個默認值,如圖1.7.2-1

    技術分享圖片

                      1.7.2-1

    1.7.3、如何使用註解類

      場景:在一個類A的方法中使用註解類B的方式調用另一個類C

      實現:1、首先你再註解類中定義相關方法,如下圖1.7.3-1;兩個分別代表類和類的目標方法

            技術分享圖片

                         1.7.3-1

         2、創建一個使用類B,在其屬性方法中通過註解綁定目標類C,如下圖所示,最終使用到的技術是通過反射進行調用(從堆棧中獲得加了註解的方法,通過方法獲得他加入的註解方法,最後進行invoke),如果方法是靜態非私有的,反射在調用invoke()的時候,可以傳入null。eq:method.invoke(null)。技術分享圖片

            技術分享圖片

  1.8、HTTP請求的GET和POST的區別

    參考博客>> https://www.cnblogs.com/doubleqsweet/p/7201099.html

  1.9、session與cookie的區別

    1.9.1、首先生命周期的不同,session是存在一次回話中的,當會話結束session被銷毀;cookie若是設置了到期時間,如果時間到了便會將數據保存在磁盤中,反之但瀏覽器關閉時cookie也就被銷毀了。

    1.9.2、session是存在服務器中的而cookie則存在於客戶端瀏覽器中,

    1.9.3、cookie相對於session來說不是很安全,所以一般用戶的登錄信息存放在session中其他信息則會存放在cookie中,單個cookie的大小不會超過4k,數量不超過2000個

    實際中,我認為淘寶那些相關推薦就是使用了與cookie類似的技術達到效果的。

    參考博客>>   https://www.cnblogs.com/endlessdream/p/4699273.html

  1.9.a、關於session分布式的處理

    1.9.a.1、基於這個問題目前我所知的有以下種方式

      1、使用session復制共享方式

      2、使用cache DB技術進行共享:msm(memcache-session-manager)技術,與基於redies緩存實現

    參考博文 >> https://www.cnblogs.com/scwanglijun/p/3763975.html

  1.9.b、JDBC的流程

         技術分享圖片

  1.9.c、MVC的設計思想

    1、為什麽會有MVC出現?

      在MVC模式出現之前,每一個web請求都是一個url,在配置文件中需要為每一個請求配置一個servlet,當你的請求很多時,這對於配置恩建來說簡直就是噩夢。而在在MVC模式中,設置一個總的過濾器類對所有的web請求進行過濾以及分發出去。

    2、設計思想:精髓就是 拆分,將之前整個流程拆分為3個部分,model-view-controller,model層主要是對數據的封裝,view是對數據的渲染,controller則是在這兩層中間進行交互的操作(將數據傳輸到view等等),使用mvc模式可以使程序更加松耦合,便於維護,模型也能復用

2、關於ConcurrentHashMap

    1、繼承了AbstractMap,實現了ConcurrentMap和Serializable

    2、在jdk1.8之前,是結合了hashtable來實現ConcurrentHashMap的,通過一個內部類Segment(繼承了ReentranLock類)和HashEntry進行同步與並發的處理,在bulllet中有多個Segment,Segment中有HashEntry進行存儲值,ConcurrentHashMap在除了讀數據之外都會給Sgment進行加鎖的操作。但是在jdk1.8開始,ConcurrentMap的實現方式變成通過對每一個鏈表頭結點進行加鎖的操作來支持並發的安全性,其中結合了cas、紅黑樹與使用synchornized來實現的,註意一個內部類ForwardingNode,在擴容中起關鍵作用,每個線程在擴容時會設置這個類的實例來控制擴容的安全。

      相比之下,後者性能更加優秀,雖然由可重入鎖換成了synchornized關鍵字,但是使用方式上使得後者的鎖粒度更細了。

    3、關於List、Set、Map的介紹

      三者都是接口,List和Set同樣繼承了Collection接口,Map則是單獨的

      List主要有ArrayList,LinkedList,Vector,SortedList等實現類,ArrayList是最常使用的,可以精確的控制插入元素的位置,在增加與刪除等變動上性能要優於LinkedList,LinkedList比較適用於元素進行檢索,也就是裏面元素波動率不大的場景下建議使用;而對於Vector是線程安全的,通過Synchornzied關鍵字實現,存儲數據則是利用數組進行實現的。

      Set主要有HashSet(可以放入null,但只能放入一個null),TreeSet(不允許放入null值)等實現類;HashSet是基於HashMap實現的,內部操作的是HashMap所以兩者很相似,但是Set是不允許有重復值的,它是為快速查找而設計的Set,我們通常都應該使用HashSet,在我們需要排序的功能時,我們才使用TreeSet;因為不管你存數據的順序是怎樣,他會去調用TreeMap中的put方法,在此方法中,插入後續的元素時會進行一個比較操作後再存放。所以是有序的。

      Map主要有HashMap,TreeMap,Hashtable等實現類,TreeMap是有序的(通過 Comparator 或者 Comparable 維護了一個排序順)上面以做出解釋,HashMap是具有高性能的訪問速度,但它是線程不安全的(TreeMap也是),HashMap裏你可以擁有隨意個 null 值但最多只能有一個 null 鍵,HashTable不允許出現null的值,它是線程安全的

3、線程的基本知識:(建議結合源碼對著看)

  1.9.d、transient修飾的字段生命周期僅存於調用者的內存中而不會寫到磁盤裏持久化。

  3.1、創建線程的方式以及實現:

    3.1.1、繼承Thread類,重寫run方法,

    3.1.2、實現Runnable接口,並實現其方法;

    3.1.3、實現Callable接口,實現其call方法,其中此方法是帶有返回值的。

    關於以上三種實現方式的聯系與差別:如果考慮到繼承的問題,建議不要使用第一種方式,因為在java中是單繼承的模式,特別指出其中Thread其實也是實現了Runnable的接口來進行線程的使用的。Callable對於前面兩種方式比較特殊,因為它是可以帶有返回值的線程調用。

  3.2、關於常見的sleep()、join()、yield()、wait()四個方法的區分

    3.2.1、sleep()方法需要指定等待的時間,它可以讓當前正在執行的線程在指定的時間內暫停執行,進入阻塞狀態,該方法既可以讓其他同優先級或者高優先級的線程得到執行的機會,也可以讓低優先級的線程得到執行機會。但是sleep()方法不會釋放“鎖標誌”,也就是說如果有synchronized同步塊,其他線程仍然不能訪問共享數據。

    3.2.2、wait()方法需要和notify()及notifyAll()兩個方法一起介紹,這三個方法用於協調多個線程對共享數據的存取,所以必須在synchronized語句塊內使用,也就是說,調用wait(),notify()和notifyAll()的任務在調用這些方法前必須擁有對象的鎖。註意,它們都是Object類的方法,而不是Thread類的方法。
  wait()方法與sleep()方法的不同之處在於,wait()方法會釋放對象的“鎖標誌”。當調用某一對象的wait()方法後,會使當前線程暫停執行,並將當前線程放入對象等待池中,直到調用了notify()方法後,將從對象等待池中移出任意一個線程並放入鎖標誌等待池中,只有鎖標誌等待池中的線程可以獲取鎖標誌,它們隨時準備爭奪鎖的擁有權。當調用了某個對象的notifyAll()方法,會將對象等待池中的所有線程都移動到該對象的鎖標誌等待池。
  除了使用notify()和notifyAll()方法,還可以使用帶毫秒參數的wait(long timeout)方法,效果是在延遲timeout毫秒後,被暫停的線程將被恢復到鎖標誌等待池。此外,wait(),notify()及notifyAll()只能在synchronized語句中使用,但是如果使用的是ReenTrantLock實現同步,該如何達到這三個方法的效果呢?解決方法是使用ReenTrantLock.newCondition()獲取一個Condition類對象,然後Condition的await(),signal()以及signalAll()分別對應上面的三個方法。你可以創建多個Condition來對線程進行不同的控制。

    3.2.3、yield()方法和sleep()方法類似,也不會釋放“鎖標誌”,區別在於,它沒有參數,即yield()方法只是使當前線程重新回到可執行狀態,所以執行yield()的線程有可能在進入到可執行狀態後馬上又被執行,另外yield()方法只能使同優先級或者高優先級的線程得到執行機會,這也和sleep()方法不同。

    3.2.4、join()方法會使當前線程等待調用join()方法的線程結束後才能繼續執行;

  3.3、關於CountDownLatch原理分析

    3.3.1、先嘗試對源碼進行分析:先看這個類的構造發現,他只有一個構造方法(默認構造函數不算在此範圍),參數是count,這個參數是這個類實現的比較重要的標識,在這個構造方法中初始化了他的一個私有的靜態final內部類Sync,將count作為參數傳入。接著分析主要的方法,調用其countDown()的方法:將count-1從共享線程池中提出一個線程;其中await()方法的實現(sync.acquireSharedInterruptibly(1);默認參數是1)是調用了CountDownLatch一個私有的靜態final內部類Sync,Sync繼承了AbstractQueuedSynchronizer(會用到這個父類的核心方法,稍後分析);在調用方法await後,會去Sync.tryAcquireShared(參數:1),方法邏輯是判斷count是否為 0 ?1:-1。如果count>0則將調用父類的doAcquireSharedInterruptibly(),其中主要實現目的判斷是否還有線程需要執行,如果狀態時signal,則將此線程剔除,喚醒下一個線程,若已經是頭結點,則停止調用;至此CountDownLatch中的線程調用完畢,執行後續線程;

    3.3.2、使用方式:創建這個類的實例(傳入count),在活動線程中調用countdown方法,最後調用await()方法;

  3.4、關於CyclicBarrier

    3.4.1、相對來說CyclicBarrier實現比較簡單,主要控制線程的方法是使用ReentrankLock來實現,這個類提供了兩種構造方法CyclicBarrier(int parties,, Runnable barrierAction)和CyclicBarrier(int parties),屬性有ReentrankLock(實現鎖的機制),parties(等待一起執行的線程數),int count(初始值為parties,在運行時動態標識活動的線程),未初始化的Runnable(其實在此類中傳入Runnable只是為了調用其中的run()方法,並不是以線程的形式調用的,我理解為算是一種另類的增強機制),一個私有靜態內部類Generation,只有一個boolean屬性broken且默認為false,表示是否跳出線程執行;主要提供外部的方法是await(),await(time,timeunit),內部內部均調用dowait()方法,具體區分我們從dowait()方法細講,方法初始ReentrankLock.lock()進行加鎖,int index = --count;賦值,第一種情況如果等於0,判斷runnable是否為空,不為空,調用run方法不是以線程的方式啟動;並且調用nextGeneration(),此方法調用condition的notifyall()方法,喚醒所有等待的線程,並new Generation(),作用是退出dowait()方法(會與之前的genneration做一個比較);如果index不為0進行叠代將每個線程進行await()狀態,並且釋放鎖

    3.4.2、使用方式:創建這個類的實例(傳入paties),在創建的線程中調用await()方法即可。

  3.5、關於Semaphore

    3.5.1、其實Semaphore和CountDownLatch是十分相似的,都有一個私有的靜態final類

        技術分享圖片

       而且都繼承了AQS抽象類,這裏不再贅述,但是Semaphore更加靈活,它提供兩種模式(公平鎖模式,不公平鎖模式)而且Semaphore是對一組資源的同步控制,核心思想根據憑證來進行調控,每個線程均可以獲取一個憑證,持有憑證時進行一些活動後再釋放憑證,憑證在沒有達到最大值時時都能獲取,但是若達到最大值接下來的線程就只能等待擁有憑證的線程釋放憑證後才能獲取。

   3.6、關於ThreaLocal

    ThreadLocal的實質就是裏面存在一個ThreadLocalMap,其中map的key值為當前線程,是弱索引所以存在內存泄露問題,value為這個線程對應存儲的數據,設置這個類是為了隔離每個線程的數據,並不是為了數據共享。

  3.7、關於線程池

    3.7.1線程池的實現原理參考博文 >> https://www.jianshu.com/p/87bff5cc8d8c >> https://www.cnblogs.com/dolphin0520/p/3932921.html

  3.8、關於CAS樂觀鎖(附帶悲觀鎖的自我理解)

    首先我們明白悲觀鎖與樂觀鎖的定義;悲觀鎖:顧名思義很悲觀,認為總會有人會改動自己的數據,就是說會有改動,所以取數據的時候會帶上一把鎖,當他在操作數據的時候其他人是阻塞狀態的,不能對數據做出任何行為比如volatile就是典型的應用。 樂觀鎖:非常樂觀,認為平時不會有人驅動這個數據,所以每次去取的時候不會加鎖,而是直接讀取,但是如果要對數據進行更新的操作的時候它會對數據進行判讀,比如CAS(compareAndSet),就回去比較內存的數據與期望的數據是否一致,若一致則將要更新的值放入內存中,其中數據校驗采用的是 數據偏移量 進行校驗的。

  3.9、關於ABA的問題

    ABA其實就是CAS存在的一個問題,其中關鍵就是(A->B->A),假設房間裏有個蘋果,第一個人進房間看了下知道是蘋果,第二個人進了房間看到是蘋果,並且吃掉了,換成了梨;後面良心發現不應該這麽做,又給換成了蘋果,在這期間第一個人沒有進來過房間;等第二個人操作完後才進房間查看,發現還是蘋果。這就是存在的問題;

    如何解決問題:從Java1.5開始JDK的atomic包裏提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSwap方法作用是首先檢查當前引用是否等於預期引用,並且當前標誌是否等於預期標誌,如果全部相等,則以原子方式將該引用和該標誌的值設置為給定的更新值。

java基礎知識總結