Java筆試知識點總結(基礎)
異常
異常分類
Java的異常分為兩種,一種是執行時異常(RuntimeException),一種是非執行異常也叫檢查式異常(CheckedException)。
對異常的處理只有兩種try catch捕獲或throws 宣告(丟擲)異常
1、執行時異常不需要程式設計師去顯式處理,當異常出現時,JVM會幫助處理。常見的執行時異常有:
NullPointerException
(
對null進行操作時產生,但是注意有個特例,
Test test=
null
;
test.hello();
假如hello是個靜態方法時,是可以正常編譯執行的,空指標異常必須是去引用堆物件了,才會有空指標。
)
ArrayStoreException(陣列儲存異常,即陣列儲存型別不一致)
ArithmeticException(所有和算數有關的都是這個異常,比如除數為0)
NumberFormatException(呼叫parseInt()方法時,如果輸入的字串不是int型或超過int範圍則會丟擲該異常)
2、非執行異常需要程式設計師手動去捕獲或者丟擲異常進行顯示的處理,因為Java認為Checked異常都是可以被修復的異常。常見的異常有:
IOException (輸入輸出流程式設計中,讀和寫時都要手動丟擲)
try—catch—finally執行順序
1、try中沒有丟擲異常,則catch語句不執行,如果有finally語句,則接著執行finally語句,繼而接著執行finally之後的語句;
2、try中丟擲異常,有匹配的catch語句,則catch語句捕獲,如果catch中有return語句,則要在finally執行後再執行;
注意:throw意味著丟擲之後,方法就到此為止了,相當於return。
注意:catch塊和finally塊不能同時省略
正則表示式
坑點:replaceAll方法的第一個引數是一個正則表示式。
元字元 |
描述 |
\ |
將下一個字元標記符、或一個向後引用、或一個八進位制轉義符。例如,“\\n”匹配\n。“\n”匹配換行符。序列“\\”匹配“\”而“\(”則匹配“(”。即相當於多種程式語言中都有的“轉義字元”的概念。 |
^ |
匹配輸入字串的開始位置。如果設定了RegExp物件的Multiline屬性,^也匹配“\n”或“\r”之後的位置。 |
$ |
匹配輸入字串的結束位置。如果設定了RegExp物件的Multiline屬性,$也匹配“\n”或“\r”之前的位置。 |
* |
匹配前面的子表示式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等價於o{0,} |
+ |
匹配前面的子表示式一次或多次(大於等於1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等價於{1,}。 |
? |
匹配前面的子表示式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等價於{0,1}。 |
{n} |
n是一個非負整數。匹配確定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的兩個o。 |
{n,} |
n是一個非負整數。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等價於“o+”。“o{0,}”則等價於“o*”。 |
{n,m} |
m和n均為非負整數,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”將匹配“fooooood”中的前三個o為一組,後三個o為一組。“o{0,1}”等價於“o?”。請注意在逗號和兩個數之間不能有空格。 |
? |
當該字元緊跟在任何一個其他限制符(*,+,?,{n},{n,},{n,m})後面時,匹配模式是非貪婪的。非貪婪模式儘可能少的匹配所搜尋的字串,而預設的貪婪模式則儘可能多的匹配所搜尋的字串。例如,對於字串“oooo”,“o+”將盡可能多的匹配“o”,得到結果[“oooo”],而“o+?”將盡可能少的匹配“o”,得到結果 ['o', 'o', 'o', 'o'] |
.點 |
匹配除“\r\n”之外的任何單個字元。要匹配包括“\r\n”在內的任何字元,請使用像“[\s\S]”的模式。 |
(pattern) |
匹配pattern並獲取這一匹配。所獲取的匹配可以從產生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中則使用$0…$9屬性。要匹配圓括號字元,請使用“\(”或“\)”。 |
(?:pattern) |
非獲取匹配,匹配pattern但不獲取匹配結果,不進行儲存供以後使用。這在使用或字元“(|)”來組合一個模式的各個部分時很有用。例如“industr(?:y|ies)”就是一個比“industry|industries”更簡略的表示式。 |
(?=pattern) |
非獲取匹配,正向肯定預查,在任何匹配pattern的字串開始處匹配查詢字串,該匹配不需要獲取供以後使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。預查不消耗字元,也就是說,在一個匹配發生後,在最後一次匹配之後立即開始下一次匹配的搜尋,而不是從包含預查的字元之後開始。 |
(?!pattern) |
非獲取匹配,正向否定預查,在任何不匹配pattern的字串開始處匹配查詢字串,該匹配不需要獲取供以後使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。 |
(?<=pattern) |
非獲取匹配,反向肯定預查,與正向肯定預查類似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。 |
(?<!pattern) |
非獲取匹配,反向否定預查,與正向否定預查類似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。這個地方不正確,有問題 此處用或任意一項都不能超過2位,如“(?<!95|98|NT|20)Windows正確,“(?<!95|980|NT|20)Windows 報錯,若是單獨使用則無限制,如(?<!2000)Windows 正確匹配 |
x|y |
匹配x或y。例如,“z|food”能匹配“z”或“food”(此處請謹慎)。“[zf]ood”則匹配“zood”或“food”。 |
[xyz] |
字元集合。匹配所包含的任意一個字元。例如,“[abc]”可以匹配“plain”中的“a”。 |
[^xyz] |
負值字元集合。匹配未包含的任意字元。例如,“[^abc]”可以匹配“plain”中的“plin”。 |
[a-z] |
字元範圍。匹配指定範圍內的任意字元。例如,“[a-z]”可以匹配“a”到“z”範圍內的任意小寫字母字元。 注意:只有連字元在字元組內部時,並且出現在兩個字元之間時,才能表示字元的範圍; 如果出字元組的開頭,則只能表示連字元本身. |
[^a-z] |
負值字元範圍。匹配任何不在指定範圍內的任意字元。例如,“[^a-z]”可以匹配任何不在“a”到“z”範圍內的任意字元。 |
\b |
匹配一個單詞邊界,也就是指單詞和空格間的位置(即正則表示式的“匹配”有兩種概念,一種是匹配字元,一種是匹配位置,這裡的\b就是匹配位置的)。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。 |
\B |
匹配非單詞邊界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。 |
\cx |
匹配由x指明的控制字元。例如,\cM匹配一個Control-M或回車符。x的值必須為A-Z或a-z之一。否則,將c視為一個原義的“c”字元。 |
\d |
匹配一個數字字元。等價於[0-9]。grep 要加上-P,perl正則支援 |
\D |
匹配一個非數字字元。等價於[^0-9]。grep要加上-P,perl正則支援 |
\f |
匹配一個換頁符。等價於\x0c和\cL。 |
\n |
匹配一個換行符。等價於\x0a和\cJ。 |
\r |
匹配一個回車符。等價於\x0d和\cM。 |
\s |
匹配任何不可見字元,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。 |
\S |
匹配任何可見字元。等價於[^ \f\n\r\t\v]。 |
\t |
匹配一個製表符。等價於\x09和\cI。 |
\v |
匹配一個垂直製表符。等價於\x0b和\cK。 |
\w |
匹配包括下劃線的任何單詞字元。類似但不等價於“[A-Za-z0-9_]”,這裡的"單詞"字元使用Unicode字符集。 |
\W |
匹配任何非單詞字元。等價於“[^A-Za-z0-9_]”。 |
繼承
子類能繼承父類的所有成員,所以子類物件是絕對大於父類物件的,可以繼承,只是無法訪問到而已,想訪問用反射!!
多型的三要素,繼承,重寫,父類引用指向子類物件(至於要不要把過載加進去,有爭議!!)
多型的最常見應用,向上轉型,但父類的引用無法訪問子類獨有的方法,
重寫
方法重寫應遵循“兩同兩小一大”原則:
- “兩同”:即方法名相同,形參列表相同;
- “兩小”:子類方法宣告丟擲的異常比父類的更小或者相等;子類返回值型別比父類的更小或者相等
- “一大”:子類方法的訪問修飾符應比父類方法更大或相等。(private和static方法不能被重寫)
重點在於要時刻記得若子類重寫了父類方法,父類呼叫時會呼叫子類重寫之後的方法
當然,這一切的前提都是 例項化子類物件
過載
方法重寫應遵循“一同一不同”原則:
- “一同”:即方法名相同;
- “一不同”:引數列表必須不同(引數型別,引數個數)
super()和this()
1)呼叫super()必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地呼叫super(),而且如果父類沒有這種形式的建構函式,那麼在編譯的時候就會報錯。
2)super()從子類中呼叫父類的構造方法,this()在同一類內呼叫其它過載的構造方法。
3)super()和this()均需放在構造方法內第一行。
4)this()或super()在一個構造器內只能出現一次,而且this()和super()不能同時出現在一個建構函式裡面,否則編譯器不通過。
6)this()和super()都指的是物件,所以,均不可以在static環境中使用。包括:static變數,static方法,static語句塊。
7)從本質上講,this是一個指向本物件的指標而不是類的引用, 然而super是一個Java關鍵字。
8)this.xxx和super.xxx可以引用本類或父類的成員變數(如果訪問許可權允許的話)。
9)可以使用super.fun()訪問父類被子類隱藏的變數或覆蓋的方法
構造器
初始化過程:
1. 初始化父類中的靜態成員變數和靜態程式碼塊 ;
2. 初始化子類中的靜態成員變數和靜態程式碼塊 ;
3.初始化父類的普通成員變數和程式碼塊,再執行父類的構造方法;
4.初始化子類的普通成員變數和程式碼塊,再執行子類的構造方法;
子類構造器的預設第一行就是super(),預設呼叫直接父類的無參構造。這也就是一旦一個子類的直接父類沒有無參的構造的情況下,必須在自己構造器的第一行顯式的指明呼叫父類或者自己的哪一個構造器。
其實 普通的類方法是可以和類名同名的,和構造方法唯一的區分就是,構造方法沒有返回值。
執行順序:
父類靜態域——》子類靜態域——》父類成員初始化——》父類構造塊——》父類構造方法——》子類成員初始化——》子類構造塊——》子類構造方法;
注:靜態初始化塊(靜態塊僅在類載入時執行一次),靜態變數這兩個是屬於同一級別的,是按程式碼寫得順序執行的
注2:只有執行完建構函式,物件才能完成初始化,屬性才能有值,不然都是null或0。
注3:並不是靜態塊最先初始化,而是靜態域.(BM:是靜態域!!!!!!!)
而靜態域中包含靜態變數、靜態塊和靜態方法,其中需要初始化的是靜態變數和靜態塊.而他們兩個的初始化順序是靠他們倆的位置決定的!
注4:
靜態塊:用static申明,JVM載入類時執行,僅執行一次
構造塊:類中直接用{}定義,每一次建立物件時執行
執行順序優先順序:靜態塊>main()>構造塊>構造方法
舉個例子,假如先執行public static B t1 = newB();該語句建立物件,其後會根據優先順序,緊跟著呼叫構造塊,輸出構造塊
匿名內部類
匿名內部類的建立格式為: new 父類構造器(引數列表)|實現介面(){
//匿名內部類的類體實現
}
- 使用匿名內部類時,必須繼承一個類或實現一個介面
- 匿名內部類由於沒有名字,因此不能定義建構函式
- 匿名內部類中不能含有靜態成員變數和靜態方法
執行緒
建立執行緒
建立執行緒的方法有很多種,下面是最常見三種:
注意:執行緒類光建立例項沒用,執行緒是不能自動執行的,必須通過start()啟動
(1)繼承Thread類,重寫run方法,main方法中用start()啟動;
(2)實現Runnable介面,重寫run方法,並將物件例項作為引數傳遞給Thread類的構造方法,Thread物件通過start使用;
(3)實現callable介面,重寫call方法,通過執行緒池的submit方法啟動,並且執行緒執行完畢後會有返回值。
執行緒狀態
執行緒呼叫start後並不保證執行緒啟動的順序,run則保證執行緒間順序執行。
修飾符和運算子
外部類修飾符
public(訪問控制符),將一個類宣告為公共類,他可以被任何物件訪問,一個程式的主類必須是公共類。
abstract,將一個類宣告為抽象類,沒有實現的方法,需要子類提供方法實現。
final,將一個類生命為最終(即非繼承類),表示他不能被其他類繼承。
friendly,預設的修飾符,只有在相同包中的物件才能使用這樣的類。
成員變數修飾符(包括內部類)
內部類,可理解為外部類的成員,所以修飾類成員的關鍵字都能使用
public(公共訪問控制符),指定該變數為公共的,他可以被任何物件的方法訪問。
private(私有訪問控制符)指定該變數只允許自己的類的方法訪問,其他任何類(包括子類)中的方法均不能訪問。
protected(保護訪問控制符)指定該變數可以別被自己的類和子類訪問。在子類中可以覆蓋此變數。
friendly ,在同一個包中的類可以訪問,其他包中的類不能訪問。
final,最終修飾符,指定此變數的值不能變。
static(靜態修飾符)指定變數被所有物件共享,即所有例項都可以使用該變數。變數屬於這個類。
transient(過度修飾符)指定該變數是系統保留,暫無特別作用的臨時性變數。
volatile(易失修飾符)指定該變數可以同時被幾個執行緒控制和修改。
方法修飾符
public(公共控制符)
private(私有控制符)指定此方法只能有自己類等方法訪問,其他的類不能訪問(包括子類)
protected(保護訪問控制符)指定該方法可以被它的類和子類進行訪問。
final,指定該方法不能被過載。
static,指定不需要例項化就可以啟用的一個方法。
synchronize,同步修飾符,在多個執行緒中,該修飾符用於在執行前,對他所屬的方法加鎖,以防止其他執行緒的訪問,執行結束後解鎖。
native,本地修飾符。指定此方法的方法體是用其他語言在程式外部編寫的。
介面修飾符
介面中欄位的修飾符:public static final(預設不寫),即必須是常量,且賦值。
介面中方法的修飾符:public abstract(預設不寫),可以是friendly abstract,1.8中可以有靜態方法了
介面的修飾符:public或什麼 都不寫(預設許可權,而且預設是什麼都不寫)
抽象類
特點:
1-抽象類和抽象方法必須用abstract關鍵字修飾。
2-抽象類中不一定都是抽象方法(沒有方法體,即必須沒有大括號{}),但是有抽象方法的類一定是抽象類。
3-抽象類不能直接例項化(可通過多型實現),因為它不是具體的類。
4-抽象類是有構造方法的,只是不能例項化,用於子類訪問父類資料的初始化。
抽象類的子類:
1- 不重寫抽象方法,抽象類的子類是一個抽象子類。
2-重寫父類所有抽象方法,子類才能不是抽象類。
成員變數:
既可以是變數(private等)也可以是常量(public static final)。
abstract關鍵字不可以與哪些關鍵字一起使用:
private 衝突;private修飾的成員不能被繼承,從而不可以被子類重寫,而abstract修飾的是要求被重寫的。
final 衝突;final修飾的成員是最終成員,不能被重寫,所以衝突,
static 無意義;static修飾成員用類名可以直接訪問,但是abstract修飾成員沒有方法體,所以訪問沒有方法體的成員無意義。
抽象類中注意的問題:
一個類如果沒有抽象方法,可以是抽象類,即抽象類中可以完全沒有抽象方法。
這樣類的主要目的就是不讓建立該類物件。
訪問許可權修飾符
( 1 )對於外部類而言,它也可以使用訪問控制符修飾,但外部類只能有兩種訪問控制級別: public 和預設。因為外部類沒有處於任何類的內部,也就沒有其所在類的內部、所在類的子類兩個範圍,因此 private 和 protected 訪問控制符對外部類沒有意義。
( 2 )內部類的上一級程式單元是外部類,它具有 4 個作用域:同一個類( private )、同一個包( protected )和任何位置( public),即有4種訪問許可權。所以,“一個檔案中只能有一個public class。”是錯的,還可以多個內部類
( 3 ) 因為區域性成員的作用域是所在方法,其他程式單元永遠不可能訪問另一個方法中的區域性變數,所以所有的區域性成員都不能使用訪問控制修飾符修飾。
運算子優先順序
小知識:<<=左移賦值 ,>>>= 右移賦值,>>帶符號右移(相當於除以2的n次方),>>>(無符號右移,左邊空缺補充為0)
小知識:-n=~n+1(按位取反公式)
口訣:淡雲一筆安洛三福 單目>算數運算子>移位>比較>按位>邏輯>三目>賦值
有個很有意思的例子i=i++;
這裡Java使用了中間快取變數機制:
i=i++;等同於:
temp=i; (等號右邊的i)
i=i+1; (等號右邊的i)
i=temp; (等號左邊的i)
而i=++i;則等同於:
i=i+1;
temp=i;
i=temp;
“==”和equals方法
equal :是用來比較兩個物件內部的內容是否相等的(因為String類重寫了equals()方法,Object類定義中,和==是相同效果的)。
==:是用來判斷兩個物件的地址是否相同,即是否是指相同一個物件。而基本資料型別是隻能用==比較數值是否相等。
Byte,Short,Integer,Long,Character這5種整型的包裝類也只是在對應值小於等於127並且大於等於-128時才可使用常量池,因為他們只佔用一個位元組(-128~127)。
例如Integer.valueOf原始碼方法中也有判斷,如果傳遞的整型變數>= -128並且小於127時會返回IntegerCache類中一個靜態陣列中的某一個物件, 否則會返回一個新的Integer物件
包裝類的“==”運算在不遇到算術運算的情況下不會自動拆箱
包裝類的equals()方法不處理資料轉型
JDK
程式設計
1.
javac.exe是編譯.java檔案
java.exe是執行編譯好的.class檔案
javadoc.exe是生成Java說明文件
jdb.exe是Java偵錯程式
javaprof.exe是剖析工具
2.
寫好的java檔案字尾名為text.java
編譯java檔案:輸入javac text.java回車,編譯會生成.class檔案
執行java檔案:java text;
一次編譯多個java檔案用javac *.java. 即可編譯當前目錄下的所有java檔案
3.
-s指定存放生成的原始檔的位置
-d即可設定系統屬性
4.
可以使用逗號的是變數初始化的語句,比如 int i=1,b=2;
如果是賦值語句,不能用逗號分隔,只能用分號。
舉例:只能是x=a; y=b;而不能是x=a, y=b;
命名規則
識別符號是不以數字開頭的字母數字序列:
數字是指0~9,字母指大小寫英文字母、下劃線(_)和美元符號($)
關鍵字
instanceof 用來在執行時指出物件是否是特定類的一個例項,instanceof通過返回一個布林值來指出,這個物件是否是這個特定類或者是它的子類的一個例項
在Java7之前,switch只能支援 byte、short、char、int或者其對應的封裝類以及Enum型別。在Java7中,呼籲很久的String支援也終於被加上了。
在根類Object中包含一下方法:
- clone();
- equals();
- finalize();
- getClass();
- notify(),notifyAll();
- hashCode();
- toString();
- wait();
五個基本原則
單一職責原則(Single-Resposibility Principle):一個類,最好只做一件事,只有一個引起它的變化。單一職責原則可以看做是低耦合、高內聚在面向物件原則上的引申,將職責定義為引起變化的原因,以提高內聚性來減少引起變化的原因。
開放封閉原則(Open-Closed principle):軟體實體應該是可擴充套件的,而不可修改的。也就是,對擴充套件開放,對修改封閉的。
Liskov替換原則(Liskov-Substituion Principle):子類必須能夠替換其基類。這一思想體現為對繼承機制的約束規範,只有子類能夠替換基類時,才能保證系統在執行期內識別子類,這是保證繼承複用的基礎。
依賴倒置原則(Dependecy-Inversion Principle):依賴於抽象。具體而言就是高層模組不依賴於底層模組,二者都同依賴於抽象;抽象不依賴於具體,具體依賴於抽象。
介面隔離原則(Interface-Segregation Principle):使用多個小的專門的介面,而不要使用一個大的總介面
常識
1、Java一律採用Unicode編碼方式,每個字元無論中文還是英文字元都佔用2個位元組。
Java虛擬機器中通常使用UTF-16的方式儲存一個字元
2、const和goto是保留關鍵字。true和false看起來像關鍵字,但嚴格來說,它們是boolean常量;null看起來也像關鍵字,但嚴格來說,它是null常量。
3、Java程式的種類有:
(a)內嵌於Web檔案中,由瀏覽器來觀看的_Applet
(b)可獨立執行的 Application
(c)伺服器端的 Servlets
4、想用轉義字元請用單引號!!!!!!!!!
5、
"c:\\my\\1.txt" "c:/my/1.txt" 都是正確的答案。 但"\"這個符號在中英文環境下是不一樣的顯示;而"/"在中英文環境下是相同的顯示。所以前者需要轉義。
./表示當前專案的路徑
../表示當前目錄的父目錄路徑
6、關於字串有個編譯器的優化問題,hotspot中 編譯時String a =
"tao"
+
"bao"
將直接變成"taobao";String b="tao"
;String c=
"bao"
;
(b+c)==MESSAGE則不會優化,因為不知道在之前的步驟中bc會不會發生改變,而針對b+c則是用語法糖,新建一個StringBuilder來處理
再舉個例子:String str1 = "hello";這裡的str1指的是方法區的字串常量池中的“hello”,編譯時期就知道的; String str2 = "he" + new String("llo");這裡的str2必須在執行時才知道str2是什麼,所以它是指向的是堆裡定義的字串“hello”,所以這兩個引用是不一樣的。
7、object的getClass()方法:返回當前執行時的類。然後再呼叫getName()方法返回:包名+類名(不加.class)
8、類似 java.io.OutputStreamWrite這樣已經是完整的類,無需在匯入,而單獨printWrite這個類,並不是呼叫完整的類名。則需要import匯入
8、記住:Math.round()是先加0.5,然後再向下取整。所以Math.round(-11.5) 的結果 就是-11
泛型
1、建立泛型物件的時候,一定要指出型別變數T的具體型別。爭取讓編譯器檢查出錯誤,而不是留給JVM執行的時候丟擲類不匹配的異常。
2、JVM如何理解泛型概念 —— 型別擦除。事實上,JVM並不知道泛型,所有的泛型在編譯階段就已經被處理成了普通類和方法。 處理方法很簡單,我們叫做型別變數T的擦除(erased) 。 總結:泛型程式碼與JVM ① 虛擬機器中沒有泛型,只有普通類和方法。 ② 在編譯階段,所有泛型類的型別引數都會被Object或者它們的限定邊界來替換。(型別擦除) ③ 在繼承泛型型別的時候,橋方法的合成是為了避免型別變數擦除所帶來的多型災難。 無論我們如何定義一個泛型型別,相應的都會有一個原始型別被自動提供。原始型別的名字就是擦除型別引數的泛型型別的名字。
3、“泛型的型別擦除機制意味著不能在執行時動態獲取List<T>中T的實際型別”是錯的,可以通過反射獲取
JVM
Java記憶體模型(JMM)
JMM通過控制主記憶體與每個執行緒的本地記憶體之間的互動,來保證可見性,原子性,有序性。
“volatile”關鍵字有如下兩個作用
-
保證被volatile修飾的共享變數對所有執行緒是可見的,也就是當一個執行緒修改了一個被volatile修飾共享變數的值,新值可以被其他執行緒立即得知。
-
禁止指令重排序優化。
簡單點說:保證對修飾的變數,執行緒讀寫前都會從主記憶體同步更新,保證了可見性。
“synchronized”關鍵字有如下兩個作用
-
關鍵字 synchronized可以保證在同一個時刻,只有一個執行緒可以執行某個方法或者某個程式碼塊(主要是對方法或者程式碼塊中存在共享資料的操作)
-
synchronized可保證一個執行緒的變化(主要是共享資料的變化)被其他正確的執行緒所看到(保證可見性,完全可以替代Volatile功能)
簡單點說:保證在塊開始時同步主記憶體的值到工作記憶體,而塊結束時將變數同步回主記憶體
“final”關鍵字的注意事項:
建立一個不可變物件 final Main x=new Main();
final修飾的只是引用,也就是說x只能指向這個物件的地址,但是物件本身可以改變。
所以在多執行緒中,這個物件依舊不是執行緒安全的,想要這個物件被其他執行緒正確的檢視,必須要用“synchronized”關鍵字修飾。
GC
年老代溢位原因有 迴圈上萬次的字串處理、建立上千萬個物件、在一段程式碼內申請上百M甚至上G的記憶體
持久代溢位原因 動態載入了大量Java類而導致溢位。
1,新生代:(1)所有物件建立在新生代的Eden區,當Eden區滿後觸發新生代的Minor GC,將Eden區和非空閒Survivor區存活的物件複製到另外一個空閒的Survivor區中。(2)保證一個Survivor區是空的,新生代Minor GC就是在兩個Survivor區之間相互複製存活物件,直到Survivor區滿為止。
2,老年代:當Survivor區也滿了之後就通過Minor GC將物件複製到老年代。老年代也滿了的話,就將觸發Full GC,針對整個堆(包括新生代、老年代、持久代)進行垃圾回收。
3,持久代:持久代如果滿了,將觸發Full GC。
ClassLoader
一個jvm中預設的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分別各司其職:
- Bootstrap ClassLoader 負責載入java基礎類,主要是 %JRE_HOME/lib/ 目錄下的rt.jar、resources.jar、charsets.jar和class等
- Extension ClassLoader 負責載入java擴充套件類,主要是 %JRE_HOME/lib/ext 目錄下的jar和class
- App ClassLoader 負責載入當前java應用的classpath中的所有類。
classloader 載入類用的是全盤負責委託機制。 所謂全盤負責,即是當一個classloader載入一個Class的時候,這個Class所依賴的和引用的所有 Class也由這個classloader負責載入,除非是顯式的使用另外一個classloader載入。
所以,當我們自定義的classlo ader載入成功了 com.company.MyClass以後,MyClass裡所有依賴的class都由這個classLoader來載入完成。
JVM載入類的實現方式,我們稱為 雙親委託模型:
如果一個類載入器收到了類載入的請求,他首先不會自己去嘗試載入這個類,而是把這個請求委託給自己的父載入器,每一層的類載入器都是如此,因此所有的類載入請求最終都應該傳送到頂層的Bootstrap ClassLoader中,只有當父載入器反饋自己無法完成載入請求時,子載入器才會嘗試自己載入。
雙親委託模型的重要用途是為了解決類載入過程中的安全性問題。
假設有一個開發者自己編寫了一個名為Java.lang.Object的類,想借此欺騙JVM。現在他要使用自定義ClassLoader來載入自己編寫的java.lang.Object類。然而幸運的是,雙親委託模型不會讓他成功。因為JVM會優先在Bootstrap ClassLoader的路徑下找到java.lang.Object類,並載入它
JDBC
ResultSet
- 表示資料庫結果集的資料表,通常通過執行查詢資料庫的語句生成。
- 當前行的第一列的索引是1,而不是0.
橋接模式
Java資料庫連線庫JDBC用了橋接模式,橋接模式的定義是將抽象部分與它的實現部分分離,使它們都可以獨立地變化。意圖是將抽象與實現解耦,JDBC連線 資料庫 的時候,在各個資料庫之間進行切換,基本不需要動太多的程式碼,甚至絲毫不動,原因就是JDBC提供了統一介面,每個資料庫提供各自的實現,用一個叫做資料庫驅動的程式來橋接就行了
載入驅動方法
1.Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
2. DriverManager.registerDriver(new com.mysql.jdbc.Driver());
3.System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");
資料型別
基本資料型別(原生類)
預設值 |
儲存需求(8位=1位元組) |
取值範圍 |
示例 |
|
byte |
0 |
1 |
-2^7—2^7-1 |
byte b=10; |
char |
‘ \u0000′ |
2 |
0—2^16-1 |
char c=’c’ ; |
short |
0 |
2 |
-2^15—2^15-1 |
short s=10; |
int |
0 |
4 |
-2^31—2^31-1 |
int i=10; |
long |
0 |
8 |
-2^63—2^63-1 |
long o=10L; |
float |
0.0f |
4 |
-2^31—2^31-1 |
float f=10.0F |
double |
0.0d |
8 |
-2^63—2^63-1 |
double d=10.0; |
boolean |
false |
1 |
true\false |
boolean flag=true; |
1)兩個數值進行二元操作時,會有如下的轉換操作:(byte-short-int-long-float-double)
如果兩個運算元其中有一個是double型別,另一個操作就會轉換為double型別。
否則,如果其中一個運算元是float型別,另一個將會轉換為float型別。
否則,如果其中一個運算元是long型別,另一個會轉換為long型別。
否則,兩個運算元都轉換為int型別。
多種混合計算時,自動將所有資料型別轉換為容量最大的一種資料型別,即自動向上轉型。向下轉型只能強轉,而強轉可能會出現丟失精度的問題。
被final修飾的變數是常量,參與計算時型別不會發生改變,但如果是無final修飾的byte型別變數,java中進行計算時候將他們提升為int型別,再進行計算,相加計算後結果已經是int型別,若再賦值給byte型別,那麼型別肯定不匹配,編譯不會通過,需要進行強制轉換。
Java中的byte,short,char進行計算時都會提升為int型別。
要注意:
float佔4個位元組比long佔8個位元組大,因為底層的實現方式不同。
浮點數的32位並不是簡單直接表示大小,而是按照一定標準分配的。
第1位,符號位,即S
接下來8位,指數域,即E。
剩下23位,小數域,即M,取值範圍為[1 ,2 ) 或[0 , 1)
然後按照公式: V=(-1)^s * M * 2^E
也就是說浮點數在記憶體中的32位不是簡單地轉換為十進位制,而是通過公式來計算而來,通過這個公式雖然,只有4個位元組,但浮點數最大值要比長整型的範圍要大。
2)整型預設為int,如果需要long,須加l或L。小數預設double,d或D可省略,但如果需要float,須加f或F,例如float = 0.1f
八進位制,以8為基數的演算法,逢8進1.所以8在八進位制就是010,前面那個0是為了和十進位制區分用的,也叫轉譯符。
3 )實現GBK編碼位元組流到UTF-8編碼位元組流的轉換
byte[] src,dst;
dst=new String(src,"GBK").getBytes("UTF-8")
引用型別
1.((TestClass)
null
).testMethod();這種寫法看似很奇葩,其實是可以的,
null可以被強制型別轉換成任意型別(不是任意型別物件),於是可以通過它來執行靜態方法。
2.列舉
變數與常量與方法
例項變數: 定義在類中的變數是類的成員變數,可以不進行初始化, java 會自動進行初始化。(如果是引用類預設初始化為 null, 如果是基本型別,預設初始化為 0或 false )
區域性變數 :定義在方法中的變數,必須進行初始化,否則不通過編譯。
類變數 :(也叫作靜態變數)是類中獨立於方法之外的變數,用 static 修飾,不用初始化,有預設初始值false。靜態變數只能在類主體中定義,不能在方法中定義。 靜態變數屬於類所有而不屬於方法。靜態變數被所有的物件所共享,在記憶體中只有一個副本,它當且僅當在類初次載入時會被初始化。
靜態變數的使用:1、如果是本類使用,可以直接就用靜態變數名。2、如果是其他類使用,可以使用類名來呼叫,也可以建立一個例項物件來呼叫。3、如果靜態變數所在的類是靜態類,那麼不管在本類裡或者在其他外部類,都可以直接使用靜態變數名。
類方法: 有如下限制 (1) 類方法中不能引用物件變數; (2) 類方法中不能呼叫類的物件方法; (3) 在類方法中不能使用super、this關鍵字。 (4)類方法不能被覆蓋。 (5)類方法中呼叫本類的類方法可直接呼叫
final 修飾的變數: 也稱為常量,只用final修飾可以在其定義時就初始化,也可以到類的構造方法裡面再對它進行初始化,但用static和final關鍵字同時修飾的常量就必須在定義時初始化。
JavaWeb
中介軟體
中介軟體是一種獨立的系統軟體,位於客戶機/伺服器的作業系統之上,中介軟體位於作業系統之上,應用軟體之下,而不是位於作業系統核心之中,管理計算機資源和網路通訊。是連線兩個獨立應用程式或獨立系統的軟體。相連線的系統,即使它們具有不同的介面,但通過中介軟體相互之間仍能交換資訊。執行中介軟體的一個關鍵途徑是資訊傳遞。通過中介軟體,應用程式可以工作於多平臺或OS環境。
(簡單來說,中介軟體並不能提高核心的效率,一般只是負責網路資訊的分發處理)
而Java常用中介軟體有jetty,apache,JBOSS,webloigc,tomcat
JSP
Servlet與JSP九大內建物件的關係
JSP物件 怎樣獲得
out->response.getWriter
request ->Service方法中的req引數
response ->Service方法中的resp引數
session ->request.getSession
application ->getServletContext
exception ->Throwable 當jsp標籤中isErrorPage ="false"時,只能用errorPage="error.jsp"(isErrorPage預設是false)
當isErrorPage ="true"時,頁面才會直接使用exception
page ->this
pageContext ->PageContext
Config ->getServletConfig
重定向
1.從位址列顯示來說
forward是伺服器請求資源,然後伺服器直接內部訪問目標地址的URL,把那個URL的響應內容讀取過來,然後把這些內容再發給瀏覽器.瀏覽器根本不知道伺服器傳送的內容從哪裡來的,所以它的位址列還是原來的地址.
注意:“forward是伺服器將控制權轉交給另外一個內部伺服器物件,由新的物件來全權負責響應使用者的請求”這句話是錯的,伺服器會直接訪問目標地址的URL,不會把控制權轉交!!
redirect是服務端根據邏輯,傳送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以位址列顯示的是新的URL.
2.從資料共享來說
forward:轉發頁面和轉發到的頁面可以共享request裡面的資料.
redirect:不能共享資料.
3.從運用地方來說
forward:一般用於使用者登陸的時候,根據角色轉發到相應的模組.
redirect:一般用於使用者登出登陸時返回主頁面和跳轉到其它的網站等.
4.從效率來說
forward:高.
redirect:低.
INCLUDE
動態 INCLUDE 用 jsp:include 動作實現 <jsp:include page="included.jsp" flush="true" /> 它總是會檢查所含檔案中的變化 , 適合用於包含動態頁面 , 並且可以帶引數。各個檔案分別先編譯,然後組合成一個檔案。
靜態 INCLUDE 用 include 偽碼實現 , 定不會檢查所含檔案的變化 , 適用於包含靜態頁面 <%@ include file="included.htm" %> 。先將檔案的程式碼被原封不動地加入到了主頁面從而合成一個檔案,然後再進行翻譯,此時不允許有相同的變數。
以下是對 include 兩種用法的區別 , 主要有兩個方面的不同 ;
一 : 執行時間上 :
<%@ include file="relativeURI"%> 是在翻譯階段執行
<jsp:include page="relativeURI" flush="true" /> 在請求處理階段執行 .
二 : 引入內容的不同 :
<%@ include file="relativeURI"%>
引入靜態文字 (html,jsp), 在 JSP 頁面被轉化成 servlet 之前和它融和到一起 .
<jsp:include page="relativeURI" flush="true" /> 引入執行頁面或 servlet 所生成的應答文字 .
分頁步驟
1、count(*)得到總記錄數
2、計算總頁數
3、獲取所有記錄
4、過濾顯示本頁資料
集合框架
Map
hashMap在單執行緒中使用大大提高效率,在多執行緒的情況下使用hashTable來確保安全。hashTable中使用synchronized關鍵字來實現安全機制,但是synchronized是對整張hash表進行鎖定即讓執行緒獨享整張hash表,在安全同時造成了浪費。concurrentHashMap採用分段加鎖的機制(使用segment來分段和管理鎖)來確保安全
List
Arraylist的記憶體結構是陣列,當超出陣列大小時建立一個新的陣列,將原陣列中元素拷貝過去。其本質是順序儲存的線性表,插入和刪除操作會引發後續元素移動,效率低,但是隨機訪問效率高
LinkedList的記憶體結構是用雙向連結串列儲存的,鏈式儲存結構插入和刪除效率高,不需要移動。但是隨機訪問效率低,需要從頭開始向後依次訪問
List的remove方法在刪除元素時總會保持下標連續,因此刪除第一個元素的時候後面的元素會依次向前覆蓋,舉個例子,你刪除了下標為0的元素後,下標為1的元素就會向前覆蓋,結果就是下標為0的元素成了開始時下標為1的元素,其他依次向前同理覆蓋,但是你現在遍歷的下標加1了啊!不就成了訪問之前的第三個元素了,那第二個元素不就被跳過了嘛
Set
hashset類的hashCode()值相等,equals()也相等,就確定為相等,即重複元素。因為預設hasncode根據記憶體地址計算,所以要重寫,保證equals時hashcode相等就是元素相等。