Java基礎知識總結(絕對經典)

寫代碼:java

1,明確需求。我要作什麼?linux

2,分析思路。我要怎麼作?1,2,3。web

3,肯定步驟。每個思路部分用到哪些語句,方法,和對象。算法

4,代碼實現。用具體的java語言代碼把思路體現出來。express

 

學習新技術的四點:編程

1,該技術是什麼?windows

2,該技術有什麼特色(使用注意):設計模式

3,該技術怎麼使用。demo數組

4,該技術何時用?test。緩存

-----------------------------------------------------------------------------------------------

一:java概述:

1991 年Sun公司的James Gosling(詹姆斯·高斯林)等人開始開發名稱爲 Oak 的語言,但願用於控制嵌入在有線電視交換盒、PDA等的微處理器;

1994年將Oak語言改名爲Java;

 

Java的三種技術架構:

JAVAEE:Java Platform Enterprise Edition,開發企業環境下的應用程序,主要針對web程序開發;

JAVASE:Java Platform Standard Edition,完成桌面應用程序的開發,是其它二者的基礎;

JAVAME:Java Platform Micro Edition,開發電子消費產品和嵌入式設備,如手機中的程序;

 

1,JDK:Java Development Kit,java的開發和運行環境,java的開發工具和jre。

2,JRE:Java Runtime Environment,java程序的運行環境,java運行的所需的類庫+JVM(java虛擬機)。

3,配置環境變量:讓java jdk\bin目錄下的工具,能夠在任意目錄下運行,緣由是,將該工具所在目錄告訴了系統,當使用該工具時,由系統幫咱們去找指定的目錄。

環境變量的配置:

    1):永久配置方式:JAVA_HOME=%安裝路徑%\Java\jdk

                      path=%JAVA_HOME%\bin

    2):臨時配置方式:set path=%path%;C:\Program Files\Java\jdk\bin

特色:系統默認先去當前路徑下找要執行的程序,若是沒有,再去path中設置的路徑下找。

classpath的配置:

    1):永久配置方式:classpath=.;c:\;e:\

    2):臨時配置方式:set classpath=.;c:\;e:\

 

注意:在定義classpath環境變量時,須要注意的狀況

若是沒有定義環境變量classpath,java啓動jvm後,會在當前目錄下查找要運行的類文件;

若是指定了classpath,那麼會在指定的目錄下查找要運行的類文件。

還會在當前目錄找嗎?兩種狀況:

    1):若是classpath的值結尾處有分號,在具體路徑中沒有找到運行的類,會默認在當前目錄再找一次。

    2):若是classpath的值結果出沒有分號,在具體的路徑中沒有找到運行的類,不會再當前目錄找。

    通常不指定分號,若是沒有在指定目錄下找到要運行的類文件,就報錯,這樣能夠調試程序。

 

4,javac命令和java命令作什麼事情呢?

    要知道java是分兩部分的:一個是編譯,一個是運行。

    javac:負責的是編譯的部分,當執行javac時,會啓動java的編譯器程序。對指定擴展名的.java文件進行編譯。 生成了jvm能夠識別的字節碼文件。也就是class文件,也就是java的運行程序。

    java:負責運行的部分.會啓動jvm.加載運行時所需的類庫,並對class文件進行執行.

    一個文件要被執行,必需要有一個執行的起始點,這個起始點就是main函數.

----------------------------------------------------------------------------------------------

二:java語法基礎:

 

1,關鍵字:其實就是某種語言賦予了特殊含義的單詞。

    保留字:其實就是尚未賦予特殊含義,可是準備往後要使用過的單詞。

2,標示符:其實就是在程序中自定義的名詞。好比類名,變量名,函數名。包含 0-九、a-z、$、_ ;

    注意:

    1),數字不能夠開頭。

    2),不可使用關鍵字。

3,常量:是在程序中的不會變化的數據。

4,變量:其實就是內存中的一個存儲空間,用於存儲常量數據。

    做用:方便於運算。由於有些數據不肯定。因此肯定該數據的名詞和存儲空間。

    特色:變量空間能夠重複使用。

何時定義變量?只要是數據不肯定的時候,就定義變量。

 

變量空間的開闢須要什麼要素呢?

    1,這個空間要存儲什麼數據?數據類型。

    2,這個空間叫什麼名字啊?變量名稱。

    3,這個空間的第一次的數據是什麼? 變量的初始化值。

 

變量的做用域和生存期:

變量的做用域:

    做用域從變量定義的位置開始,到該變量所在的那對大括號結束;

生命週期:

    變量從定義的位置開始就在內存中活了;

    變量到達它所在的做用域的時候就在內存中消失了;

 

數據類型:

    1):基本數據類型:byte、short、int、long、float、double、char、boolean

    2):引用數據類型: 數組、類、接口。

級別從低到高爲:byte,char,short(這三個平級)-->int-->float-->long-->double

自動類型轉換:從低級別到高級別,系統自動轉的;

強制類型轉換:什麼狀況下使用?把一個高級別的數賦給一個別該數的級別低的變量;

 

運算符號:

    1)、算術運算符。

        + - * / %   %:任何整數模2不是0就是1,因此只要改變被模數就能夠實現開關運算。

        +:鏈接符。

        ++,--

    2)、賦值運算符。

        =  += -= *= /= %=

    3)、比較運算符。

        特色:該運算符的特色是:運算完的結果,要麼是true,要麼是false。

    4)、邏輯運算符。

        &  |  ^  !   &&   ||

        邏輯運算符除了 !  外都是用於鏈接兩個boolean類型表達式。

        &: 只有兩邊都爲true結果是true。不然就是false。

        |:只要兩邊都爲false結果是false,不然就是true

        ^:異或:和或有點不同。

             兩邊結果同樣,就爲false。

             兩邊結果不同,就爲true.

        & 和 &&區別: & :不管左邊結果是什麼,右邊都參與運算。

                      &&:短路與,若是左邊爲false,那麼右邊不參數與運算。

        | 和|| 區別:|:兩邊都運算。

                    ||:短路或,若是左邊爲true,那麼右邊不參與運算。

    5)、位運算符:用於操做二進制位的運算符。

        &  |  ^

        <<  >>   >>>(無符號右移)

    練習:對兩個變量的數據進行互換。不須要第三方變量。

            int a  = 3,b = 5;-->b = 3,a = 5;

            a = a + b; a = 8;

            b = a - b; b = 3;

            a = a - b; a = 5;

            a = a ^ b;//

            b = a ^ b;//b = a ^ b ^ b = a

            a = a ^ b;//a = a ^ b ^ a = b;

        練習:高效的算出 2*8 = 2<<3;

5,語句。

    If  switch  do while   while  for

    這些語句何時用?

    1)、當判斷固定個數的值的時候,可使用if,也可使用switch。

    可是建議使用switch,效率相對較高。

switch(變量){

   case 值:要執行的語句;break;

   …

   default:要執行的語句;

}

 工做原理:用小括號中的變量的值依次和case後面的值進行對比,和哪一個case後面的值相同了

           就執行哪一個case後面的語句,若是沒有相同的則執行default後面的語句;

 細節:1):break是能夠省略的,若是省略了就一直執行到遇到break爲止;

       2):switch 後面的小括號中的變量應該是byte,char,short,int四種類型中的一種;

       3):default能夠寫在switch結構中的任意位置;若是將default語句放在了第一行,則無論expression與case中的value是否匹配,程序會從default開始執行直到第一個break出現。

    2)、當判斷數據範圍,獲取判斷運算結果boolean類型時,須要使用if。

    3)、當某些語句須要執行不少次時,就用循環結構。

    while和for能夠進行互換。

    區別在於:若是須要定義變量控制循環次數。建議使用for。由於for循環完畢,變量在內存中釋放。

 

break:做用於switch ,和循環語句,用於跳出,或者稱爲結束。

break語句單獨存在時,下面不要定義其餘語句,由於執行不到,編譯會失敗。當循環嵌套時,break只跳出當前所在循環。要跳出嵌套中的外部循環,只要給循環起名字便可,這個名字稱之爲標號。

 

continue:只做用於循環結構,繼續循環用的。

做用:結束本次循環,繼續下次循環。該語句單獨存在時,下面不能夠定義語句,執行不到。

 

6,函 數:爲了提升代碼的複用性,能夠將其定義成一個單獨的功能,該功能的體現就是java中的函數。函數就是體現之一。

java中的函數的定義格式:

    修飾符 返回值類型 函數名(參數類型 形式參數1,參數類型 形式參數1,…){

       執行語句;

       return 返回值;

    }

當函數沒有具體的返回值時,返回的返回值類型用void關鍵字表示。

若是函數的返回值類型是void時,return語句能夠省略不寫的,系統會幫你自動加上。

return的做用:結束函數。結束功能。

 

如何定義一個函數?

    函數其實就是一個功能,定義函數就是實現功能,經過兩個明確來完成:

    1)、明確該功能的運算完的結果,實際上是在明確這個函數的返回值類型。

    2)、在實現該功能的過程當中是否有未知內容參與了運算,其實就是在明確這個函數的參數列表(參數類型&參數個數)。

函數的做用:

1)、用於定義功能。

2)、用於封裝代碼提升代碼的複用性。

注意:函數中只能調用函數,不能定義函數。

主函數:

    1)、保證該類的獨立運行。

    2)、由於它是程序的入口。

    3)、由於它在被jvm調用。

 

函數定義名稱是爲何呢?

答:1)、爲了對該功能進行標示,方便於調用。

    2)、爲了經過名稱就能夠明確函數的功能,爲了增長代碼的閱讀性。

 

重載的定義是:在一個類中,若是出現了兩個或者兩個以上的同名函數,只要它們的參數的個數,或者參數的類型不一樣,便可稱之爲該函數重載了。

如何區分重載:當函數同名時,只看參數列表。和返回值類型不要緊。

 

7,數 組:用於存儲同一類型數據的一個容器。好處:能夠對該容器中的數據進行編號,從0開始。數組用於封裝數據,就是一個具體的實體。

如何在java中表現一個數組呢?兩種表現形式。

1)、元素類型[] 變量名 = new 元素類型[元素的個數];

2)、元素類型[] 變量名 = {元素1,元素2...};

元素類型[] 變量名 = new 元素類型[]{元素1,元素2...};

---------------------------------------------------------

//二分查找法。必須有前提:數組中的元素要有序。

    public static int halfSeach_2(int[] arr,int key){

        int min,max,mid;

        min = 0;

        max = arr.length-1;

        mid = (max+min)>>1; //(max+min)/2;

        while(arr[mid]!=key){

            if(key>arr[mid]){

                min = mid + 1;

            }

            else if(key<arr[mid])

                max = mid - 1;

            if(max<min)

                return -1;

            mid = (max+min)>>1;

        }

        return mid;

    }

---------------------------------------------------------

java分了5片內存。

1:寄存器。2:本地方法區。3:方法區。4:棧。5:堆。

棧:存儲的都是局部變量 ( 函數中定義的變量,函數上的參數,語句中的變量 );

    只要數據運算完成所在的區域結束,該數據就會被釋放。

堆:用於存儲數組和對象,也就是實體。啥是實體啊?就是用於封裝多個數據的。

1:每個實體都有內存首地址值。

2:堆內存中的變量都有默認初始化值。由於數據類型不一樣,值也不同。

3:垃圾回收機制。

----------------------------------------------------------------------------------------------

三:面向對象:★★★★★

特色:1:將複雜的事情簡單化。

2:面向對象將之前的過程當中的執行者,變成了指揮者。

3:面向對象這種思想是符合如今人們思考習慣的一種思想。

 

過程和對象在咱們的程序中是如何體現的呢?過程其實就是函數;對象是將函數等一些內容進行了封裝。

 

匿名對象使用場景:

1:當對方法只進行一次調用的時候,可使用匿名對象。

2:當對象對成員進行屢次調用時,不能使用匿名對象。必須給對象起名字。

 

在類中定義其實都稱之爲成員。成員有兩種:

1:成員變量:其實對應的就是事物的屬性。

2:成員函數:其實對應的就是事物的行爲。

 

因此,其實定義類,就是在定義成員變量和成員函數。可是在定義前,必須先要對事物進行屬性和行爲的分析,才能夠用代碼來體現。

 

private int age;//私有的訪問權限最低,只有在本類中的訪問有效。

注意:私有僅僅是封裝的一種體現形式而已。

 

私有的成員:其餘類不能直接建立對象訪問,因此只有經過本類對外提供具體的訪問方式來完成對私有的訪問,能夠經過對外提供函數的形式對其進行訪問。

好處:能夠在函數中加入邏輯判斷等操做,對數據進行判斷等操做。

 

總結:開發時,記住,屬性是用於存儲數據的,直接被訪問,容易出現安全隱患,因此,類中的屬性一般被私有化,並對外提供公共的訪問方法。

這個方法通常有兩個,規範寫法:對於屬性 xxx,可使用setXXX(),getXXX()對其進行操做。

 

類中怎麼沒有定義主函數呢?

注意:主函數的存在,僅爲該類是否須要獨立運行,若是不須要,主函數是不用定義的。

主函數的解釋:保證所在類的獨立運行,是程序的入口,被jvm調用。

 

成員變量和局部變量的區別:

1:成員變量直接定義在類中。

   局部變量定義在方法中,參數上,語句中。

2:成員變量在這個類中有效。

局部變量只在本身所屬的大括號內有效,大括號結束,局部變量失去做用域。

3:成員變量存在於堆內存中,隨着對象的產生而存在,消失而消失。

局部變量存在於棧內存中,隨着所屬區域的運行而存在,結束而釋放。

 

構造函數:用於給對象進行初始化,是給與之對應的對象進行初始化,它具備針對性,函數中的一種。

特色:

1:該函數的名稱和所在類的名稱相同。

2:不須要定義返回值類型。

3:該函數沒有具體的返回值。

記住:全部對象建立時,都須要初始化纔可使用。

 

注意事項:一個類在定義時,若是沒有定義過構造函數,那麼該類中會自動生成一個空參數的構造函數,爲了方便該類建立對象,完成初始化。若是在類中自定義了構造函數,那麼默認的構造函數就沒有了。

 

一個類中,能夠有多個構造函數,由於它們的函數名稱都相同,因此只能經過參數列表來區分。因此,一個類中若是出現多個構造函數。它們的存在是以重載體現的。

 

構造函數和通常函數有什麼區別呢?

1:兩個函數定義格式不一樣。

2:構造函數是在對象建立時,就被調用,用於初始化,並且初始化動做只執行一次。

    通常函數,是對象建立後,須要調用才執行,能夠被調用屢次。

  

何時使用構造函數呢?

分析事物時,發現具體事物一出現,就具有了一些特徵,那就將這些特徵定義到構造函數內。

 

構造代碼塊和構造函數有什麼區別?

構造代碼塊:是給全部的對象進行初始化,也就是說,全部的對象都會調用一個代碼塊,只要對象一創建,就會調用這個代碼塊。

構造函數:是給與之對應的對象進行初始化,它具備針對性。

 

「Person p = new Person();」

建立一個對象都在內存中作了什麼事情?

1:先將硬盤上指定位置的Person.class文件加載進內存。

2:執行main方法時,在棧內存中開闢了main方法的空間(壓棧-進棧),而後在main方法的棧區分配了一個變量p。

3:在堆內存中開闢一個實體空間,分配了一個內存首地址值。new

4:在該實體空間中進行屬性的空間分配,並進行了默認初始化。

5:對空間中的屬性進行顯示初始化。

6:進行實體的構造代碼塊初始化。

7:調用該實體對應的構造函數,進行構造函數初始化。()

8:將首地址賦值給p ,p變量就引用了該實體。(指向了該對象)

--------------------------------------------------------------------------------------------

封 裝(面向對象特徵之一):是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。

好處:將變化隔離;便於使用;提升重用性;安全性。

封裝原則:將不須要對外提供的內容都隱藏起來,把屬性都隱藏,提供公共方法對其訪問。

 

This:表明對象,就是所在函數所屬對象的引用。

this到底表明什麼呢?哪一個對象調用了this所在的函數,this就表明哪一個對象,就是哪一個對象的引用。

開發時,何時使用this呢?

在定義功能時,若是該功能內部使用到了調用該功能的對象,這時就用this來表示這個對象。

 

this 還能夠用於構造函數間的調用。

調用格式:this(實際參數);

this對象後面跟上 .  調用的是成員屬性和成員方法(通常方法);

this對象後面跟上 () 調用的是本類中的對應參數的構造函數。

 

注意:用this調用構造函數,必須定義在構造函數的第一行。由於構造函數是用於初始化的,因此初始化動做必定要執行。不然編譯失敗。

 

static:★★★ 關鍵字,是一個修飾符,用於修飾成員(成員變量和成員函數)。

特色:

1,想要實現對象中的共性數據的對象共享,能夠將這個數據進行靜態修飾。

2,被靜態修飾的成員,能夠直接被類名所調用。也就是說,靜態的成員多了一種調用方式。類名.靜態方式。

3,靜態隨着類的加載而加載,並且優先於對象存在。

 

弊端:

1,有些數據是對象特有的數據,是不能夠被靜態修飾的。由於那樣的話,特有數據會變成對象的共享數據。這樣對事物的描述就出了問題。因此,在定義靜態時,必需要明確,這個數據是不是被對象所共享的。

2,靜態方法只能訪問靜態成員,不能夠訪問非靜態成員。

由於靜態方法加載時,優先於對象存在,因此沒有辦法訪問對象中的成員。

3,靜態方法中不能使用this,super關鍵字。

由於this表明對象,而靜態在時,有可能沒有對象,因此this沒法使用。

4,主函數是靜態的。

 

何時定義靜態成員呢?或者說:定義成員時,到底需不須要被靜態修飾呢?

成員分兩種:

1,成員變量。(數據共享時靜態化)

該成員變量的數據是不是全部對象都同樣:

若是是,那麼該變量須要被靜態修飾,由於是共享的數據。

若是不是,那麼就說這是對象的特有數據,要存儲到對象中。

2,成員函數。(方法中沒有調用特有數據時就定義成靜態)

    若是判斷成員函數是否須要被靜態修飾呢?

    只要參考,該函數內是否訪問了對象中的特有數據:

    若是有訪問特有數據,那方法不能被靜態修飾。

    若是沒有訪問過特有數據,那麼這個方法須要被靜態修飾。

 

成員變量和靜態變量的區別:

1,成員變量所屬於對象,因此也稱爲實例變量。

靜態變量所屬於類,因此也稱爲類變量。

2,成員變量存在於堆內存中。

靜態變量存在於方法區中。

3,成員變量隨着對象建立而存在,隨着對象被回收而消失。

靜態變量隨着類的加載而存在,隨着類的消失而消失。

4,成員變量只能被對象所調用。

靜態變量能夠被對象調用,也能夠被類名調用。

因此,成員變量能夠稱爲對象的特有數據,靜態變量稱爲對象的共享數據。

 

靜態的注意:靜態的生命週期很長。

靜態代碼塊:就是一個有靜態關鍵字標示的一個代碼塊區域,定義在類中。

做用:能夠完成類的初始化,靜態代碼塊隨着類的加載而執行,並且只執行一次(new 多個對象就只執行一次)。若是和主函數在同一類中,優先於主函數執行。

 

Public:訪問權限最大。

static:不須要對象,直接類名便可。

void:主函數沒有返回值。

Main:主函數特定的名稱。

(String[] args):主函數的參數,是一個字符串數組類型的參數,jvm調用main方法時,傳遞的實際參數是 new String[0]。

 

jvm默認傳遞的是長度爲0的字符串數組,咱們在運行該類時,也能夠指定具體的參數進行傳遞。能夠在控制檯,運行該類時,在後面加入參數。參數之間經過空格隔開。jvm會自動將這些字符串參數做爲args數組中的元素,進行存儲。

 

靜態代碼塊、構造代碼塊、構造函數同時存在時的執行順序:靜態代碼塊 &agrave; 構造代碼塊 &agrave; 構造函數;

 

生成Java幫助文檔:命令格式:javadoc –d 文件夾名 –auther –version *.java

/**     //格式

*類描述

*@author 做者名

*@version 版本號

*/

/**

*方法描述

*@param  參數描述

*@return  返回值描述

*/

---------------------------------------------------------------------------------------------

設計模式:解決問題最行之有效的思想。是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。

 

java中有23種設計模式:

單例設計模式:★★★★★

解決的問題:保證一個類在內存中的對象惟一性。

好比:多程序讀取一個配置文件時,建議配置文件封裝成對象。會方便操做其中數據,又要保證多個程序讀到的是同一個配置文件對象,就須要該配置文件對象在內存中是惟一的。

 

Runtime()方法就是單例設計模式進行設計的。

 

如何保證對象惟一性呢?

思想:

1,不讓其餘程序建立該類對象。

2,在本類中建立一個本類對象。

3,對外提供方法,讓其餘程序獲取這個對象。

 

步驟:

1,由於建立對象都須要構造函數初始化,只要將本類中的構造函數私有化,其餘程序就沒法再建立該類對象;

2,就在類中建立一個本類的對象;

3,定義一個方法,返回該對象,讓其餘程序能夠經過方法就獲得本類對象。(做用:可控)

 

代碼體現:

1,私有化構造函數;

2,建立私有並靜態的本類對象;

3,定義公有並靜態的方法,返回該對象。

---------------------------------------------

//餓漢式

class Single{

    private Single(){} //私有化構造函數。

private static Single s = new Single(); //建立私有並靜態的本類對象。

    public static Single getInstance(){ //定義公有並靜態的方法,返回該對象。

        return s;

    }

}

---------------------------------------------

//懶漢式:延遲加載方式。

class Single2{

    private Single2(){}

private static Single2 s = null;

    public static Single2 getInstance(){

        if(s==null)

            s = new Single2();

        return s;

    }

}

-------------------------------------------------------------------------------------------------

繼 承(面向對象特徵之一)

好處:

1:提升了代碼的複用性。

2:讓類與類之間產生了關係,提供了另外一個特徵多態的前提。

 

父類的由來:實際上是由多個類不斷向上抽取共性內容而來的。

java中對於繼承,java只支持單繼承。java雖然不直接支持多繼承,可是保留了這種多繼承機制,進行改良。

 

單繼承:一個類只能有一個父類。

多繼承:一個類能夠有多個父類。

 

爲何不支持多繼承呢?

由於當一個類同時繼承兩個父類時,兩個父類中有相同的功能,那麼子類對象調用該功能時,運行哪個呢?由於父類中的方法中存在方法體。

可是java支持多重繼承。A繼承B  B繼承C  C繼承D。

多重繼承的出現,就有了繼承體系。體系中的頂層父類是經過不斷向上抽取而來的。它裏面定義的該體系最基本最共性內容的功能。

因此,一個體系要想被使用,直接查閱該系統中的父類的功能便可知道該體系的基本用法。那麼想要使用一個體系時,須要創建對象。建議創建最子類對象,由於最子類不只可使用父類中的功能。還可使用子類特有的一些功能。

 

簡單說:對於一個繼承體系的使用,查閱頂層父類中的內容,建立最底層子類的對象。

 

子父類出現後,類中的成員都有了哪些特色:

1:成員變量。

     當子父類中出現同樣的屬性時,子類類型的對象,調用該屬性,值是子類的屬性值。

     若是想要調用父類中的屬性值,須要使用一個關鍵字:super

     This:表明是本類類型的對象引用。

     Super:表明是子類所屬的父類中的內存空間引用。

     注意:子父類中一般是不會出現同名成員變量的,由於父類中只要定義了,子類就不用在定義了,直接繼承過來用就能夠了。

2:成員函數。

當子父類中出現瞭如出一轍的方法時,創建子類對象會運行子類中的方法。好像父類中的方法被覆蓋掉同樣。因此這種狀況,是函數的另外一個特性:覆蓋(複寫,重寫)

何時使用覆蓋呢?當一個類的功能內容須要修改時,能夠經過覆蓋來實現。

3:構造函數。

發現子類構造函數運行時,先運行了父類的構造函數。爲何呢?

緣由:子類的全部構造函數中的第一行,其實都有一條隱身的語句super();

super(): 表示父類的構造函數,並會調用於參數相對應的父類中的構造函數。而super():是在調用父類中空參數的構造函數。

爲何子類對象初始化時,都須要調用父類中的函數?(爲何要在子類構造函數的第一行加入這個super()?)

由於子類繼承父類,會繼承到父類中的數據,因此必需要看父類是如何對本身的數據進行初始化的。因此子類在進行對象初始化時,先調用父類的構造函數,這就是子類的實例化過程。

 

注意:子類中全部的構造函數都會默認訪問父類中的空參數的構造函數,由於每個子類構造內第一行都有默認的語句super();

若是父類中沒有空參數的構造函數,那麼子類的構造函數內,必須經過super語句指定要訪問的父類中的構造函數。

若是子類構造函數中用this來指定調用子類本身的構造函數,那麼被調用的構造函數也同樣會訪問父類中的構造函數。

 

問題:super()和this()是否能夠同時出現的構造函數中。

兩個語句只能有一個定義在第一行,因此只能出現其中一個。

 

super()或者this():爲何必定要定義在第一行?

由於super()或者this()都是調用構造函數,構造函數用於初始化,因此初始化的動做要先完成。

 

繼承的細節:

何時使用繼承呢?

當類與類之間存在着所屬關係時,才具有了繼承的前提。a是b中的一種。a繼承b。狼是犬科中的一種。

英文書中,所屬關係:" is a "

注意:不要僅僅爲了獲取其餘類中的已有成員進行繼承。

 

因此判斷所屬關係,能夠簡單看,若是繼承後,被繼承的類中的功能,均可以被該子類所具有,那麼繼承成立。若是不是,不能夠繼承。

 

細節二:

在方法覆蓋時,注意兩點:

1:子類覆蓋父類時,必需要保證,子類方法的權限必須大於等於父類方法權限能夠實現繼承。不然,編譯失敗。

2:覆蓋時,要麼都靜態,要麼都不靜態。 (靜態只能覆蓋靜態,或者被靜態覆蓋)

 

繼承的一個弊端:打破了封裝性。對於一些類,或者類中功能,是須要被繼承,或者複寫的。

這時如何解決問題呢?介紹一個關鍵字,final:最終。

 

final特色:

1:這個關鍵字是一個修飾符,能夠修飾類,方法,變量。

2:被final修飾的類是一個最終類,不能夠被繼承。

3:被final修飾的方法是一個最終方法,不能夠被覆蓋。

4:被final修飾的變量是一個常量,只能賦值一次。

 

    其實這樣的緣由的就是給一些固定的數據起個閱讀性較強的名稱。

    不加final修飾不是也可使用嗎?那麼這個值是一個變量,是能夠更改的。加了final,程序更爲嚴謹。常量名稱定義時,有規範,全部字母都大寫,若是由多個單詞組成,中間用 _ 鏈接。

 

抽象類: abstract

抽象:不具體,看不明白。抽象類表象體現。

在不斷抽取過程當中,將共性內容中的方法聲明抽取,可是方法不同,沒有抽取,這時抽取到的方法,並不具體,須要被指定關鍵字abstract所標示,聲明爲抽象方法。

抽象方法所在類必定要標示爲抽象類,也就是說該類須要被abstract關鍵字所修飾。

 

抽象類的特色:

1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關鍵字修飾(能夠描述類和方法,不能夠描述變量)。

2:抽象方法只定義方法聲明,並不定義方法實現。

3:抽象類不能夠被建立對象(實例化)。

4:只有經過子類繼承抽象類並覆蓋了抽象類中的全部抽象方法後,該子類才能夠實例化。不然,該子類仍是一個抽象類。

 

抽象類的細節:

1:抽象類中是否有構造函數?有,用於給子類對象進行初始化。

2:抽象類中是否能夠定義非抽象方法?

    能夠。其實,抽象類和通常類沒有太大的區別,都是在描述事物,只不過抽象類在描述事物時,有些功能不具體。因此抽象類和通常類在定義上,都是須要定義屬性和行爲的。只不過,比通常類多了一個抽象函數。並且比通常類少了一個建立對象的部分。

3:抽象關鍵字abstract和哪些不能夠共存?final , private , static

4:抽象類中可不能夠不定義抽象方法?能夠。抽象方法目的僅僅爲了避免讓該類建立對象。

-----------------------------------------------------------------------------------------------

模板方法設計模式:

解決的問題:當功能內部一部分實現時肯定,一部分實現是不肯定的。這時能夠把不肯定的部分暴露出去,讓子類去實現。

abstract class GetTime{

    public final void getTime(){ //此功能若是不須要複寫,可加final限定

        long start = System.currentTimeMillis();

        code(); //不肯定的功能部分,提取出來,經過抽象方法實現

        long end = System.currentTimeMillis();

        System.out.println("毫秒是:"+(end-start));

    }

    public abstract void code(); //抽象不肯定的功能,讓子類複寫實現

}

class SubDemo extends GetTime{

    public void code(){ //子類複寫功能方法

        for(int y=0; y<1000; y++){

            System.out.println("y");

        }

    }

}

 

一:對象模塊。

一.初始化

1.對this.super,構造函數,構造代碼塊,靜態代碼塊總結。

this:表明當前對象,也就是所在函數所屬對象的引用。

this對象後面加.調用的是對象的成員變量和方法。(this.say());

this對象後面加(),調用的是本類中對應參數的構造函數。

 

super:表明父類,也就是當前類的父類。

使用方式與this相似。

 

構造函數:用於當對對象初始化時調用的特殊函數,只在執行一次。

在構造函數中使用this或者super,必須定義在構造函數的第一行。若是沒有用到,那麼構造函數的第一句會默認的加上super();

構造代碼塊:是給全部的對象進行初始化,也就是,全部的對象都會調用的一個代碼塊,只要對象一建,就會調用這個代碼塊,用於給不一樣對象的共性初始化,優先於構造函數執行。

格式:{

代碼。。。。。。

}

靜態代碼塊:一個用static關鍵字標示的一個代碼塊區域,定義在類中。能夠完成類的初始化,靜態代碼塊會隨着類的加載而執行一次(new多個對象也是隻執行一次)。若是和主函數在同一個類中,優先於主函數執行。

格式:static{

代碼。。。。。

}

三種初始化的執行順序: 靜態代碼塊--->構造代碼塊------>構造函數。

 

二.繼承(extends):

1.重寫和重載

重寫:覆蓋父類已有的方法,子父類方法必須如出一轍。(包括返回值,子類複寫父類方法時訪問權限必須比父類大或者同級。方法要麼都靜態,要麼都不靜態)。

重載:只在本類中的多個方法,只看同名函數的參數列表。

子類初始化時,先初始化父類的方法和變量,在初始化本身的。

三.接口(implements)

1.實現

接口能夠被多實現,類繼承只能單繼承。

接口與接口之間存在着繼承關係,接口能夠多繼承接口。

 

四.多態

體現:父類或者接口的引用指向本身的子類對象。(注意:在使用多態時,要訪問子類的方法,要求父類中必須對該方法進行了聲明或者定義)。

多態在子父類中的成員上的體現的特色:

成員變量:

編譯時期:參考的引用類型變量所屬的類中是否有調用的成員。(編譯時期不產生對象,只檢查語法錯誤)。

運行時期:也是參考引用類型變量所屬的類中是否有調用的成員。

簡單總結:成員變量——編譯運行都看 = 左邊。

 

非靜態成員函數:

編譯時期:參考引用類型變量所屬的類中是否有調用的方法。

運行時期:參考的是對象所屬的類中是否有調用的方法。

緣由:由於在子父類的非晶態成員函數中有一個特性:重寫(覆蓋)。

簡單總結:成員函數——編譯看 = 左邊,  運行看 = 右邊。 

靜態函數:

編譯時期:參考引用類型變量所屬的類中是否有調用的方法。

運行時期:參考的是引用類型所屬的類中是否有調用的方法。

緣由:由於是靜態方法,因此是不屬於對象的,而是屬於該方法所在的類。

簡單總結:成員函數——編譯運行看 = 左邊,

 

 

五:內部類。

特色:內部類能夠直接訪問外部類中的成員,而外部類想要訪問內部類,必需要創建內部類的對象。

-------------------------------------------------------------------------------------------------------------------------------

class Outer{

int num = 4;

class Inner {

void show(){

System.out.println("inner show run" + num);

}

}

public void method(){

Inner in = new Inner();//建立內部類的對象

in.show();//調用內部類的方法

}

-------------------------------------------------------------------------------------------------------------------------------

當內部類定義在外部類的成員變量位置。可使用一些成員修飾符進行修飾默認,private,static.


1.默認修飾符。

直接訪問內部類格式:外部類名.內部類名 變量名 =  new 外部類對象.內部類對象;

Outer.Inner in = new Quter.new Inner();

上面這種方式比較少見,由於內部類原本就是爲了封裝,想要獲取內部類對象一般都是經過外部類的方法來獲取,這樣能夠對內部類對象進行控制。

 

2.private修飾符。

一般內部類被封裝,都會被私有化。

 

3.靜態修飾符。

若是內部類被靜態修飾,至關於外部類,會出現訪問侷限性,只能訪問外部類中的靜態成員。

 

注意:若是內部類中定義了靜態成員,那麼該內部類必須是靜態的。
     當外部類的靜態方法訪問內部類時,內部類也必須是靜態的。

外部其餘類中,直接訪問static內部類的非靜態成員:New Outer.Inner().show();

外部其餘類中,直接訪問static內部類的靜態成員:Outer.Inner.show();

 

通常內部類通過編譯後文件名爲:「外部類名$內部類名.class」;

 

當內部類被定義在局部位置上時。

1.不能夠被成員修飾符修飾(例如:static,static是修飾成員的)

 

2.能夠訪問外部類中成員,由於還持有外部類中的引用,(外部內.this),但不能夠訪問它所在的局部中的變量,只能訪問被final修飾的局部變量。

 

匿名內部類:

意義:沒有名字的內部類,是內部類的簡化形式,通常內部類只用一次的話就能夠用這種形式。匿名內部類其實就是一個匿名子類對象,想要定義匿名內部類:須要前提,內部類必須實現一個接口或者繼承一個類。

匿名內部類的格式:new 父類名&接口名(){定義子類成員或者覆蓋父類方法}.方法

case:

new Object(){

void show(){

System.out.prinlt("show run");

}

} .show();

六:異常。

1.使用throws來在方法上標識(聲明),方法可能會出現異常,當調用者檢查到有標識時有必需要進行處理,要麼接着拋,要麼try。不然會出現編譯失敗

聲明格式:throws 異常類,異常類。。。。。並非全部的異常都須要聲明,RuntimeException(運行時異常)類及其子類能夠不用聲明。

 

2.捕獲異常try{}catch(){}塊來捕捉時,要注意有多個catch時,若是有父類的Exception語句塊,必定要放在下面.

 

3.throw用於拋出異常對象。

 

異常,在子父類進行覆蓋時,有如下特色:

1.當子類覆蓋父類的方法時,若是父類的方法拋出了異常,那麼子類的方法要麼不拋出異常,要麼就拋出父類異常或者該異常的子類,不能拋出其餘異常。若是父類沒有拋出異常,那麼子類只能try不能throws.

2.若是父類拋出了多個異常,那麼子類在覆蓋時只能拋出父類異常的子集。

3.若是這個異常子類沒法處理,已經影響了子類方法的具體運算,這時能夠在子類方法中,經過throw拋出RuntimeException異常或者其子類,這樣,子類方法就不須要throws進行聲明。

注意:throw下面不能寫語句,由於執行不到(會出現編譯錯誤,和return,break後面不能寫代碼相似),可是注意若是是分支結構,也就是說if語句內寫是能夠的。

七:多線程。

1.相關概念。

進程:正在進行中的程序,就是一個應用程序運行時的內存分配空間

線程:進程中一個程序的執行控制單元,一條執行路徑。

進程負責的是應用程序的空間的標示,線程負責的是應用程序的執行順序。

 

cpu隨機性原理:由於cpu的快速切換形成,那個線程獲取到了CPU的執行權,那個線程就執行。

 

2.線程的幾種狀態:

被建立:start()。

運行:具有執行資格,同時具有執行權。

凍結:sleep(time),wait()-----notify()喚醒,線程凍結(沉睡),釋放了執行權,同時釋放了執行資格。

臨時阻塞狀態:線程具有cpu的執行資格,沒有cpu的執行權。

消亡:stop();

3.兩種線程的建立方式

第一種方式:繼承Thread,由子類複寫run方法。

步驟:1.定義類繼承Thread類。

2.目的是複寫run方法,將要讓線程運行的代碼都存儲到run方法中。

3.經過建立Thread類的子類對象,建立線程對象。

4.調用線程的start方法,開啓線程,並執行run方法。

 

第二種方式:實現一個Runable接口。

步驟:1.定義類實現Runnable接口。

2.覆蓋接口中的run方法。(用於封裝線程要運行的代碼)。

3.經過Thread類建立線程對象。

4.將實現了Runnable接口的子類做爲實際參數傳遞給Thread類中的構造函數。(爲何要這麼作?是爲了讓線程對象明確要運行的run方法所屬的對象)。

5.調用Thread對象的start方法。開啓線程,並運行Runnable接口子類中的run方法。

 

通常狀況推薦使用第二種方式,能夠避免單繼承。

 

4.線程安全問題

經過圖能夠發現一個線程在執行多條語句時,並運算同一個數據時,在執行過程當中,其餘線程參與進來,並操做了這個數據,那麼會致使錯誤數據產生。

產生的兩個因素:1.多條線程在操做共享數據。2.有多條語句對共享數據進行運算。

緣由:這多條語句,在某一個時刻被一個線程執行是,還沒執行完,cpu時間片到了,被其餘線程執行了。

 

八:同步(鎖)。

爲了解決上面所說的線程安全問題而產生的技術,解決的思路就是:加同步,加鎖,將要操做共享數據的語句在某一時段讓一個線程執行完,在線程執行過程當中,其餘線程不能進來執行。

 

1.Java中提供了一個解決方式,就是同步代碼塊。也就是鎖。

格式:

synchronized (對象){ //任意對象均可以,這個對象就是鎖

//須要被同步的代碼

}

 

定義同步的前提:

1.必需要有兩個或者兩個以上的線程,才須要同步。

2.多個線程必須保證使用的是同一個鎖

 

2.另外一種表現形式就是同步函數:就是將同步關鍵字定義在函數上,讓函數具有了同步性。

1.同步函數所使用的鎖是this對象。

2.當同步函數被static修飾時,因爲此時的函數是屬於類的,這時可能尚未產生該類的對象,可是該類的字節碼文件加載進了內存就已經被封裝成了對象,因此此時的鎖就是字節碼文件對象,也就是類名.class對象。

 

 

3.關於同步代碼塊和同步函數的區別?

同步代碼塊使用的鎖能夠是任意對象。

同步函數使用的鎖是this,靜態同步函數的鎖是該類的字節碼文件對象。

 

4.死鎖。多個同步進行嵌套致使,相互等待。

避免死鎖:線程通訊→等待喚醒機制,涉及的方法:

wait:將同步中的線程處理爲凍結狀態。釋放了執行權,釋放了資格。同時將線程對象存儲到線程池中。

notify:喚醒線程池中某一個線程。

notifyAll:喚醒線程池中全部的線程。

 

注意:1.這些方法都須要定義在同步中。2.由於這些方法都必需要標示所屬的鎖。由於A鎖上的wait只能,讓A鎖去喚醒notify。(A.wait()----->A.notify)。

 

wait和sleep區別:分析這兩個方法。從執行權和鎖角度來分析。

wait:能夠指定時間,也能夠不指定時間,若是不指定時間,只能由對應的notify或者notifyAll來喚醒。  線程會釋放執行權,並且線程也會釋放鎖。

sleep:必須指定時間,時間到線程自動由凍結狀態轉爲運行狀態(或者臨時阻塞狀態)。  線程會釋放執行權,可是不會釋放鎖。

 

九:字符串,字符容器。

1.關於字符串的方法就不過多提了,就簡單的說下這裏容易出錯的幾個概念。

字符串特色:字符串一旦被初始化,就不能夠改變,存放在方法區的常量池中。只要出現了「 」(雙引號)的數據那麼就是字符串對象。關於

這裏簡單說一下關於Java的內存分佈:1:寄存器 2:本地方法區 (靜態方法,常量)3:方法區  4:棧(局部變量)  5:堆(實體,就是對象和數組)。

 

2.字符容器:StringBuffer 和  StringBuilder。

StringBuffer特色:1.初始容量爲16個字符。

2.能夠對字符串內容進行修改。

3.可變長度。

4.緩存區中能夠存儲任意類型的數據。

5.最終須要變成字符串。

6.最重要的線程安全的。

 

StringBuilder:與buffer如出一轍,只是它是線程不安全的。

 

總結:多線程操做,使用StringBuffer安全。單線程使用StringBuilder效率高。

 

十:集合框架:用於存儲數據的容器。

特色:

1.對象封裝數據,對象多了也須要存儲。集合用於存儲對象。

2.對象的個數肯定可使用數組,但不肯定個數怎麼辦,可使用集合,由於集合時可變長度

 

集合與數組的區別:

1.數組是固定長度:集合可變長度的。

2.數組能夠存儲基本數據類型,也能夠存儲引用數據類型。集合只能存儲引用數據類型。

3.數組存儲的元素必須是同一個數據類型;集合存儲的對象能夠是不一樣數據類型。

--< java.util >-- Collection接口:

Collection:

|--List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素能夠重複。

|--Set:無序(存入和取出順序有可能不一致),不能夠存儲重複元素。必須保證元素惟一性。

 

--< java.util >-- Iterator接口:

迭代器:是一個接口。做用:用於取集合中的元素。

 boolean

hasNext()  若是仍有元素能夠迭代,則返回 true。

 E

next()   返回迭代的下一個元素。

 void

remove()  從迭代器指向的 collection 中移除迭代器返回的最後一個元素(可選操做)。

每個集合都有本身的數據結構,都有特定的取出本身內部元素的方式。爲了便於操做全部的容器,取出元素。將容器內部的取出方式按照一個統一的規則向外提供,這個規則就是Iterator接口。

也就說,只要經過該接口就能夠取出Collection集合中的元素,至於每個具體的容器依據本身的數據結構,如何實現的具體取出細節,這個不用關心,這樣就下降了取出元素和具體集合的耦合性。

 

-< java.util >-- List接口:

List自己是Collection接口的子接口,具有了Collection的全部方法。如今學習List體系特有的共性方法,查閱方法發現List的特有方法都有索引,這是該集合最大的特色。

List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素能夠重複。

|--ArrayList:底層的數據結構是數組,線程不一樣步,ArrayList替代了Vector,查詢元素的速度很是快。

|--LinkedList:底層的數據結構是鏈表,線程不一樣步,增刪元素的速度很是快。

|--Vector:底層的數據結構就是數組,線程同步的,Vector不管查詢和增刪都巨慢。

對於List的遍歷,不只可使用Iterator接口,也可使用下表(索引)來遍歷,list.get(index);

--< java.util >-- Set接口:

Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一種,迭代器。

|--HashSet:底層數據結構是哈希表,線程是不一樣步的。無序,高效;

HashSet集合保證元素惟一性:經過元素的hashCode方法,和equals方法完成的。

當元素的hashCode值相同時,才繼續判斷元素的equals是否爲true。

若是爲true,那麼視爲相同元素,不存。若是爲false,那麼存儲。

若是hashCode值不一樣,那麼不判斷equals,從而提升對象比較的速度。

       |--LinkedHashSet:有序,hashset的子類。

|--TreeSet:對Set集合中的元素的進行指定順序的排序。不一樣步。TreeSet底層的數據結構就是二叉樹。

 

哈希表的原理:

1,對對象元素中的關鍵字(對象中的特有數據),進行哈希算法的運算,並得出一個具體的算法值,這個值 稱爲哈希值。

2,哈希值就是這個元素的位置。

3,若是哈希值出現衝突,再次判斷這個關鍵字對應的對象是否相同。若是對象相同,就不存儲,由於元素重複。若是對象不一樣,就存儲,在原來對象的哈希值基礎 +1順延。

4,存儲哈希值的結構,咱們稱爲哈希表。

5,既然哈希表是根據哈希值存儲的,爲了提升效率,最好保證對象的關鍵字是惟一的。

這樣能夠儘可能少的判斷關鍵字對應的對象是否相同,提升了哈希表的操做效率。

 6.在HashSet中儘可能不要改變參與運算hashCode值的變量,以防止內存泄露。。

對於ArrayList集合,判斷元素是否存在,或者刪元素底層依據都是equals方法。

對於HashSet集合,判斷元素是否存在,或者刪除元素,底層依據的是hashCode方法和equals方法。

 

TreeSet:

用於對Set集合進行元素的指定順序排序,排序須要依據元素自身具有的比較性。

若是元素不具有比較性,在運行時會發生ClassCastException異常。

因此須要元素實現Comparable接口,強制讓元素具有比較性,複寫compareTo方法。

依據compareTo方法的返回值,肯定元素在TreeSet數據結構中的位置。

TreeSet方法保證元素惟一性的方式:就是參考比較方法的結果是否爲0,若是return 0,視爲兩個對象重複,不存。

 

注意:在進行比較時,若是判斷元素不惟一,好比,同姓名,同年齡,才視爲同一我的。

在判斷時,須要分主要條件和次要條件,當主要條件相同時,再判斷次要條件,按照次要條件排序。

 

TreeSet集合排序有兩種方式,Comparable和Comparator區別:

1:讓元素自身具有比較性,須要元素對象實現Comparable接口,覆蓋compareTo方法。

2:讓集合自身具有比較性,須要定義一個實現了Comparator接口的比較器,並覆蓋compare方法,並將該類對象做爲實際參數傳遞給TreeSet集合的構造函數。

第二種方式較爲靈活。

 

Map集合:

|--Hashtable:底層是哈希表數據結構,是線程同步的。不能夠存儲null鍵,null值。

|--HashMap:底層是哈希表數據結構,是線程不一樣步的。能夠存儲null鍵,null值。替代了Hashtable.

|--TreeMap:底層是二叉樹結構,能夠對map集合中的鍵進行指定順序的排序。

 

Map集合存儲和Collection有着很大不一樣:

Collection一次存一個元素;Map一次存一對元素。

Collection是單列集合;Map是雙列集合。

Map中的存儲的一對元素:一個是鍵,一個是值,鍵與值之間有對應(映射)關係。

特色:要保證map集合中鍵的惟一性。

 

想要獲取map中的全部元素:

原理:map中是沒有迭代器的,collection具有迭代器,只要將map集合轉成Set集合,可使用迭代器了。之因此轉成set,是由於map集合具有着鍵的惟一性,其實set集合就來自於map,set集合底層其實用的就是map的方法。

★ 把map集合轉成set的方法:

Set keySet();

Set entrySet();//取的是鍵和值的映射關係。

Entry就是Map接口中的內部接口;

爲何要定義在map內部呢?entry是訪問鍵值關係的入口,是map的入口,訪問的是map中的鍵值對。

---------------------------------------------------------

取出map集合中全部元素的方式一:keySet()方法。

能夠將map集合中的鍵都取出存放到set集合中。對set集合進行迭代。迭代完成,再經過get方法對獲取到的鍵進行值的獲取。

Set keySet = map.keySet();

Iterator it = keySet.iterator();

while(it.hasNext()) {

Object key = it.next();

Object value = map.get(key);

System.out.println(key+":"+value);

}

-------------------------------------------------------

取出map集合中全部元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();

Iterator it = entrySet.iterator();

while(it.hasNext()) {

Map.Entry  me = (Map.Entry)it.next();

System.out.println(me.getKey()+"::::"+me.getValue());

}

--------------------------------------------------------

使用集合的技巧:

看到Array就是數組結構,有角標,查詢速度很快。

看到link就是鏈表結構:增刪速度快,並且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();

看到hash就是哈希表,就要想要哈希值,就要想到惟一性,就要想到存入到該結構的中的元素必須覆蓋hashCode,equals方法。

看到tree就是二叉樹,就要想到排序,就想要用到比較。

比較的兩種方式:

一個是Comparable:覆蓋compareTo方法;

一個是Comparator:覆蓋compare方法。

LinkedHashSet,LinkedHashMap:這兩個集合能夠保證哈希表有存入順序和取出順序一致,保證哈希表有序。

 

集合何時用?

當存儲的是一個元素時,就用Collection。當存儲對象之間存在着映射關係時,就使用Map集合。

保證惟一,就用Set。不保證惟一,就用List。

 

Collections:它的出現給集合操做提供了更多的功能。這個類不須要建立對象,內部提供的都是靜態方法。

 

Collection 和 Collections的區別:

Collections是個java.util下的類,是針對集合類的一個工具類,提供一系列靜態方法,實現對集合的查找、排序、替換、線程安全化(將非同步的集合轉換成同步的)等操做。

Collection是個java.util下的接口,它是各類集合結構的父接口,繼承於它的接口主要有Set和List,提供了關於集合的一些操做,如插入、刪除、判斷一個元素是否其成員、遍歷等。

Arrays:

用於操做數組對象的工具類,裏面都是靜態方法。

關於集合內部的方法,這裏就不介紹了,API中都有。

十一:IO流:用於處理設備上的數據。

相關概念:

1.流:能夠理解爲數據的流動,就是數據流。IO流最終要以對象來體現,對象都存在IO包中。流的操做只要兩種,讀和寫。

2.流也能夠進行分類:1.輸入流(讀)和輸出流(寫)。2.由於處理的的數據不一樣,分爲字符流(Reader  Writer)和字節流(InputStream  OutputStream)。

字節流:處理字節數據的流對象。計算機底層的數據都是二進制格式字節,因此字節流的數據能夠是音頻,圖片,文字等計算機中能夠儲存的數據。

字符流:爲何要有字符流?字節流不是能夠操做一切數據?由於字符每一個國家都不同,因此涉及到了字符編碼問題,像若是咱們的使用GBK的編碼,卻按照ISO8859-1去解碼是有問題的,因此須要咱們在獲取文字字節數據的同時+制定的編碼表才能夠正確解析數據。於是將字節流和編碼表封裝爲對象,就是字符流,只要操做字符數據,那麼清閒考慮使用字符流體系。

重要知識點:

1.close()方法和flush()的區別:

flush():將緩存區的數據刷到目的地中後,流能夠繼續使用。

close():將緩衝區數據刷到目的地中後,流就關閉了,該方法主要用於結束調用的底層資源,這個動做在使用完畢流後必定要作。

2.FileWriter寫入數據的細節:

windows中的換行符:\r\n 兩個符號組成。  linux:\n。

在原數據上續寫數據,只要在new 流對象的構造函數中傳入新的參數true。

目錄分割符: windows \\  /。

 

流的兩種讀取數據方法:1.不帶緩衝區,每次讀取一個(fr.read())。2.自定義緩衝區(fr.read(buff))

case  1:核心代碼

[java] view plain copy

  1. FileReader fr = new FileReader("demo.txt");  
  2.   int ch = 0;  
  3.   while((ch=fr.read)!=-1){  
  4.   System.out,println((cahr)ch);   
  5.   }  
  6.   fr.close();  

case 2:

[java] view plain copy

  1. FileReader fr = new FileReader("demo.txt")  
  2. char[] buff = new char[1024]; //自定義的緩衝區  
  3. int len = 0;  
  4.    while((len=fr.read(buff))!=-1){  
  5.    System.out.println(buff,0,len);  
  6.   }  
  7. fr.close();  



 

IO流體系:

字符流:

Reader:用於讀取字符流的抽象類。子類必須實現的方法只有 read(char[], int, int) 和 close()。

     |---BufferedReader:從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。 能夠指定緩衝區的大小,或者可以使用默認的大小。大多數狀況下,默認值就足夠大了。

        |---LineNumberReader:跟蹤行號的緩衝字符輸入流。此類定義了方法 setLineNumber(int) 和 getLineNumber(),它們可分別用於設置和獲取當前行號。

     |---InputStreamReader:是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集能夠由名稱指定或顯式給定,或者能夠接受平臺默認的字符集。

        |---FileReader:用來讀取字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是適當的。要本身指定這些值,能夠先在 FileInputStream 上構造一個 InputStreamReader。

     |---CharArrayReader:

     |---StringReader:

-------------------------------------------------

Writer:寫入字符流的抽象類。子類必須實現的方法僅有 write(char[], int, int)、flush() 和 close()。

     |---BufferedWriter:將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。

     |---OutputStreamWriter:是字符流通向字節流的橋樑:可以使用指定的 charset 將要寫入流中的字符編碼成字節。它使用的字符集能夠由名稱指定或顯式給定,不然將接受平臺默認的字符集。

        |---FileWriter:用來寫入字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是可接受的。要本身指定這些值,能夠先在 FileOutputStream 上構造一個 OutputStreamWriter。

     |---PrintWriter:

     |---CharArrayWriter:

     |---StringWriter:

---------------------------------

字節流:

InputStream:是表示字節輸入流的全部類的超類。

     |--- FileInputStream:從文件系統中的某個文件中得到輸入字節。哪些文件可用取決於主機環境。FileInputStream 用於讀取諸如圖像數據之類的原始字節流。要讀取字符流,請考慮使用 FileReader。

     |--- FilterInputStream:包含其餘一些輸入流,它將這些流用做其基本數據源,它能夠直接傳輸數據或提供一些額外的功能。

        |--- BufferedInputStream:該類實現緩衝的輸入流。

     |--- ObjectInputStream:

     |--- PipedInputStream:

-----------------------------------------------

OutputStream:此抽象類是表示輸出字節流的全部類的超類。

     |--- FileOutputStream:文件輸出流是用於將數據寫入 File 或 FileDescriptor 的輸出流。

     |--- FilterOutputStream:此類是過濾輸出流的全部類的超類。

        |--- BufferedOutputStream:該類實現緩衝的輸出流。

        |--- PrintStream:

        |--- DataOutputStream:

     |--- ObjectOutputStream:

     |--- PipedOutputStream:

--------------------------------

緩衝區是提升效率用的,給誰提升呢?

BufferedWriter:是給字符輸出流提升效率用的,那就意味着,緩衝區對象創建時,必需要先有流對象。明確要提升具體的流對象的效率。

 

[java] view plain copy

  1. FileWriter fw = new FileWriter("bufdemo.txt");  
  2. BufferedWriter bufw = new BufferedWriter(fw);//讓緩衝區和指定流相關聯。  
  3. for(int x=0; x<4; x++){  
  4. bufw.write(x+"abc");  
  5. bufw.newLine(); //寫入一個換行符,這個換行符能夠依據平臺的不一樣寫入不一樣的換行符。  
  6. bufw.flush();//對緩衝區進行刷新,可讓數據到目的地中。  
  7. }  
  8. bufw.close();//關閉緩衝區,其實就是在關閉具體的流。  


 

 

-----------------------------

BufferedReader:

 

[java] view plain copy

  1. FileReader fr = new FileReader("bufdemo.txt");  
  2. BufferedReader bufr  = new BufferedReader(fr);  
  3. String line = null;  
  4. while((line=bufr.readLine())!=null){  //readLine方法返回的時候是不帶換行符的。  
  5. System.out.println(line);  
  6. }  
  7. bufr.close();  


 

 

流一些總結:

流對象:其實很簡單,就是讀取和寫入。可是由於功能的不一樣,流的體系中提供N多的對象。那麼開始時,到底該用哪一個對象更爲合適呢?這就須要明確流的操做規律。

流的操做規律:

1,明確源和目的。

數據源:就是須要讀取,可使用兩個體系:InputStream、Reader;

數據匯:就是須要寫入,可使用兩個體系:OutputStream、Writer;

2,操做的數據是不是純文本數據?

若是是:數據源:Reader

    數據匯:Writer 

若是不是:數據源:InputStream

      數據匯:OutputStream

3,雖然肯定了一個體系,可是該體系中有太多的對象,到底用哪一個呢?

明確操做的數據設備。

數據源對應的設備:硬盤(File),內存(數組),鍵盤(System.in)

數據匯對應的設備:硬盤(File),內存(數組),控制檯(System.out)。

4,須要在基本操做上附加其餘功能嗎?好比緩衝。

若是須要就進行裝飾。

 

轉換流特有功能:轉換流能夠將字節轉成字符,緣由在於,將獲取到的字節經過查編碼表獲取到指定對應字符。

轉換流的最強功能就是基於 字節流 + 編碼表 。沒有轉換,沒有字符流。

 

發現轉換流有一個子類就是操做文件的字符流對象:

InputStreamReader

|--FileReader

OutputStreamWriter

|--FileWrier

 

想要操做文本文件,必需要進行編碼轉換,而編碼轉換動做轉換流都完成了。因此操做文件的流對象只要繼承自轉換流就能夠讀取一個字符了。

可是子類有一個侷限性,就是子類中使用的編碼是固定的,是本機默認的編碼表,對於簡體中文版的系統默認碼錶是GBK。

FileReader fr = new FileReader("a.txt");

InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"gbk");

以上兩句代碼功能一致,

若是僅僅使用平臺默認碼錶,就使用FileReader fr = new FileReader("a.txt"); //由於簡化。

若是須要制定碼錶,必須用轉換流。

轉換流 = 字節流+編碼表。

轉換流的子類File = 字節流 + 默認編碼表。

 

轉換流使用格式:轉換流  fr =  new 轉換流(包裝的流,指定的編碼集);

InputStreamReader fr = new InputStreamReaderfr (new FileInputStream("a.txt"),"GBK")

 

十二:網絡編程。

相關概念:

1.邏輯端口:用於表示進程的邏輯地址,不一樣的進程的標識;有效進程:0~65535,其中0~1024是系統使用或者保留端口
2.物理端口:指的是主機或者其餘設備上提供的外接接口。

Java中的IP對象 InetAddress.
Socket套接字,通訊的端點:就是爲網絡服務提供的一種機制,通訊兩端都有Socket,網絡通訊其實就是端口Socket間的通訊,數據在兩個Socket之間經過IO傳輸

 

應用層的主要協議和方式有兩張:UDP 和 TCP 兩種.

1.UDP:面向數據包的傳輸,是面向無鏈接的方式.

 UDP傳輸:
 1.只要進行網絡傳輸,必須須要Socket套接字。
 2.數據必定要封裝到數據包中,數據包中包含IP地址,端口號,數據等信息。
 Java中封裝操做UDP來進行網絡通訊的主要類是DatagramSocket對象以及DatagramPacket(數據包)。
 DatagramSocket:具有接受和發送功能,但進行傳輸時,須要明確發送端和接收端。
 DatagramPacket:數據包對象,用於操做數據包中的各類信息。
 
 UDP傳輸發送端的步驟:
 1.創建UDP的Socket服務,建立對象時若是沒有聲明端口,那麼系統會自動分配給其一個未使用的端口號。
 2.明確要發送的數據。
 3.將數據封裝到數據包對象中。
 4.用Socket的Send方法將數據包發送出去。
 5.關閉資源(必須記得作)
 
 下面給出一個例子做爲參考:
[java] view plain copy

  1. class UdpSend{  
  2.    public static void main (String[] args){  
  3.       //1.使用DatagramSocket來創建UDP的Socket服務  
  4.       DatagramSocket ds = new DatagramSocket(8088);//指定發送端的端口8088,若是不指定自動默認分配  
  5.       //2.明確要發送的具體數據   
  6.       String context = "發送一段UDP信息。";  
  7.       byte[] buff = context.getBytes();  
  8.       //3.將數據封裝到要發送的數據包中  
  9.       DatagramPacket dp = new DatapramPacket(buff,buff.length,InetAddress.getName("192.168.0.112"),10000);//要將該信息發往指定主機的10000端口上  
  10.       //4.使用Socket的send方法,將數據包發送出去。  
  11.       ds.send(dp);  
  12.       //5.關閉資源  
  13.       ds.close();  
  14.    }  
  15. }  



UDP傳輸接受端的步驟:
1.創建UDP的Socket服務,明確一個端口,做用在於,只有發送到這個端口的數據纔是這個接受端能夠接受處理的數據
2.建立數據包對象用於接受(存儲)數據包。
3.利用Socket服務的接受方法將收到的數據存儲到數據包中。
4.經過數據包對象獲取數據包中的具體內容,如ip地址,端口,數據等。
5.關閉資源(必須作)


接受端的例子:
[java] view plain copy

  1. class UdpReceive{  
  2.   public static void main(String[] args){  
  3.     //1.使用DatagramSocket創建UDP的Socket服務。  
  4.     DatagramSocket ds = new DatagramSocket(10000);//設置端口,聲明接受該端口的數據  
  5.     //2.建立數據包對象,建立接受存收到的數據。(須要先定義字節數組,數據包會將接受到的數據存入到字節數組中)  
  6.     byte[] buff = new byte[1024];  
  7.     DatagramPacket dp = new DatagramPacket(buff,buff.length);  
  8.     //3.利用Socket服務,接受發送過來的數據包  
  9.     ds.receive(dp);//該方法是阻塞式方法,沒有監聽到有數據發送過來的時候,會一直等待。  
  10.     //4.經過數據包對象的方法獲取數據包中信息  
  11.     String ip = dp.getAddress.getHostAddress();  
  12.     int port = dp.getPort();  
  13.     String context = new String(dp.getData(),0,dp.length);  
  14.     System.out.println("ip:"+ip+" port:"+port+" context:"+context);  
  15.     //5.關閉資源  
  16.     ds.close();  
  17.   }  
  18. }  

TCP傳輸:兩個端點創建鏈接後會有一個傳輸數據的通道,這通道成爲流,並且是創建在網絡基礎之上的流,稱之爲Socket流,該流中既有讀取,也有寫入。

相關概念:TCP中的兩個端點須要嚴格區分:一個是服務端,一個是客戶端。

客戶端:對應的對象,Socket

服務端:對應的對象,ServerSocket

 

TCP客戶端:

1.創建TCPde Socket服務,最好明確具體的地址和端口,這個對象在建立時,就已經能夠對指定ip和端口進行鏈接(三次握手)。

2.若是鏈接成功,就意味通道創建了,Socket流已經產生了。只要獲取到Socket流中的讀取流和寫入流便可,只要通getInputStream和getOutputStream就能夠獲取到兩個流對象。

3關閉資源。

 

case 1 :

[java] view plain copy

  1. class TcpClient{  
  2.     public static void main(String[] args){  
  3.          Socket s = new Socket("192.168.1.112",10002);  
  4.          OutputStream out = s.getOutputStream();               //獲取了Socket流中的輸出流對象。  
  5.          out.write("TCP鏈接。。。".getBytes());  
  6.          s.close();  
  7.    }  
  8. }  

TCP服務端:

1.建立Socket服務,並監聽一個指定的端口。

2.服務端爲了客戶端提供服務,獲取客戶端的內容,能夠經過accept方法獲取鏈接過來的客戶端對象。

3.能夠經過獲取到的Socket對象中的Socket流和具體的客戶端進行通信。

4.若是通信結束,關閉資源。注意:要先關客戶端,再關服務端。

case 2:

 

[java] view plain copy

  1. class TcpServer{  
  2.      public static void main(String[] args) throws Exception{  
  3.             ServerSocket ss = new ServerSocket(10002);    //創建服務端的Socket服務  
  4.             Socket s = ss.accept();      //獲取客戶端對象  
  5.             String ip = s.getInetAddress().getHostAddress();  
  6.             System.out.println(ip+「.....connection」);  
  7.             //能夠經過獲取到的Socket對象中的Socket流和具體的客戶端進行通信  
  8.             InputStream in = s.getInputStream();     //讀取客戶端的數據,使用客戶端對象的Socket讀取流  
  9.             byte[] buff = new byte[1024];  
  10.             int  len =  in,read(buff);  
  11.             String text = new String(buff,0,len);  
  12.             System.out.println(text);  
  13.             //關閉資源,注意必定是先關客戶端,再關閉服務端  
  14.             s.close();  
  15.             ss.close();  
  16.      }  
  17. }  

 

網絡編程中的URLEncoder和URLDecoder.

URLEncoder類的encode()靜態方法:是將一個普通的字符串轉化爲一個百分號編碼格式字符串。

URLDecoder類的decode()靜態方法:是將百分號編碼格式字符串轉化爲一個普通的字符串。

URL與URLConnection對象:前者是表示應用程序和URL之間的通訊鏈接,後者表示與URL之間的HTTP鏈接。程序能夠經過URLConnection實例向該URL發生請求,讀取URL引用的資源。

 

 

 

 

未完待續。。。。。持續更新

相關文章
相關標籤/搜索