JavaSE知識點總結(力推萌新學習!!!)
磨刀不誤砍柴工,下面是我作為初學者,到學完Java基礎的感悟,特分享給大家,
在B站官看動力節點視頻,最后做出總結,為Java萌新推波助瀾,更上一層樓!希望大家在編程的道路上越走越遠,愈戰愈強!!!,遇到困難,善于分析;解決問題,勤于總結,耐心和堅持是我們非常關鍵的,大家分享,攜手解決遇到的困難,每個人都會得到極大的進步,加油!!!
知識點的最后部分,沒有過多的講解,不是我懶了,而是不想以其昏昏,使其昭昭,把好的學習環境,學習氛圍破壞了,最后的時候,希望大家都有一份屬于自己的總結,當自己學習其他的內容時,把原來的忘記,溫故而知新,所以有一份自己的知識總結,不失為明智之舉,在學習我的總結的時候,更多的是希望大家參照我的學習規劃來,框架擺在那兒,而內容需要自己去補充,覺得一個知識點需要動手實踐多少次,可以靈活運用,編程,是靠實踐積累起來的,只看而不屑于做練習,敲代碼的人,請止步于此,
強制交易如果大家學到,覺得有幫助的話,請大家要么分享自己的知識總結,要么轉發這篇文章,為后面的萌新提供一絲絲便利,另外如果文章的知識點哪里不對,或者有疑義,請大家不吝賜教,發表在評論區,或者留言給我,我及時修改以免更多人被誤導,衷心感謝!!!
在此,也動力節點的免費分享學習資料由衷的感謝,
學習視頻(萬分鐘,學到就是賺到!)(https://www.bilibili.com/video/BV1Rx411876f)
1.第一章:Java開發環境的搭建
【1】軟體開發介紹
·軟體開發
軟體:一系列按照特定順序組織的計算機資料和指令的集合,有系統軟體和應用軟體之分,
系統軟體----作業系統
·人機互動方式
圖形化界面(GUI):簡單直觀、使用者易接受,
命令列方式(CLI):需要有一個控制臺,輸入特定的指令,需要記住指令,較為麻煩, DOS
·常用的DOS命令
》dir: 列出當前目錄的檔案以及檔案夾
》md: 創建目錄
》rd: 洗掉目錄
》cd: 進入指定目錄
》cd…: 退回到上一級目錄
》cd: 退回到根目錄
》del: 洗掉檔案
》exit: 退出dos命令列
【2】計算機編程語言介紹
計算機語言:人與計算機交流的方式,
C C++ Java PHP Kotlin Python Scala等
機器語言 :指令以二進制代碼形式存在,
匯編語言:使用助記符表示一潭訓器指令,
高級語言:面向程序、面向物件
【3】Java語言
SUN公司1995年推出的一門高級編程語言,
09年Oracle收購,
Java SE 標準版 桌面級應用
Java EE 企業版 企業級應用
Java ME 小型版 移動終端上
Java Card
Java之父 James Gosling
【4】運行機制及運行程序
Java語言特點:
1、面向物件
2、健壯性
3、跨平臺性
通過Java語言撰寫的代碼可以在任何作業系統上運行
核心機制--垃圾回收
垃圾回收在Java程式運行程序中自動進行,程式員無法精確控制和干預
【5】Java的環境搭建
JDK(Java Development Kit Java開發工具包)
JRE(Java Runtime Environment Java運行環境)
JDK =JRE+開發工具集(例如javac編譯工具等)
JRE=JVM+JavaSE標準類別庫
安裝路徑:
不能包含空格和漢字,保留版本號
環境變數:配置路徑 系統變數:JDK的bin目錄放到path路徑下
1、(多個版本JDK)環境變數配置的哪個JDK就用哪個JDK
2、(想配置到用戶變數 )新建一個path
3、將新建的path上移到最上面
【6】EditPlus
【7】將寫好的代碼以 .java 的檔案型別保存
cmd Javac 編譯 之后 Java 運行
【8】常用的開發工具
2.第二章:Java基礎語法
【1】關鍵字和保留字
·關鍵字 【圖】
·保留字:現有版本尚未使用,以后可能會使用
自己命名時,避開
goto、const
【2】識別符號(Identifier)
·識別符號:
Java對各種變數、方法和類等要素命名時使用的字符序列
稱為識別符號,
·技巧:凡是可以自己起名的地方都叫識別符號,
·定義合法的識別符號規則:
》由26個英文字母大小寫,0-9,$或_組成
》數字不可以開頭
》不可以使用關鍵字和保留字、但能包含關鍵字和保留字,
》Java中嚴格區分大小寫,長度無限制
》識別符號不能包含空格,
·Java中的名稱命名規范
》包名:多單詞組成時所有字母都小寫 xxxyyyzzz
》類名、介面名:多單詞組成時,所有單詞的首字母都大寫:XxxYyyZzz
》變數名、方法名:多單詞組成時,第一個首字母小寫,后邊的首字母大寫: xxxYyyZzz
》常量名:所有字母都大寫、多單詞時每個單詞用下劃線連接 :XXX_YYY_ZZZ
【3】變數
變數怎么定義
變數怎么賦值
變數的作用域
變數的分類
》基本資料型別
12488412 byte short int long float double boolean char
整型 :byte 【1】、short 【2】 、int 【4】、long【8】
浮點型:float 【4】、double【8】
字符型:char 【2】
布爾型:boolean【1】
byte :-128~127
long型變數 以L或l結尾,不加的時候認為是int型
float 定義的變數需要加f
字符編碼方式(理解字符編碼):DBK,UTF-8,ASCLL ISO-8859-1…
》參考資料型別
類(class)
介面(interface)
陣列(array)
》基本資料型別轉換
·自動型別提升(容量大小區分)
byte、char、 short -->int long float double
byte char short 運算結果是int
·強制型別轉換
1、可能導致精度丟失
2、需要使用強轉符
》基本資料型別與String轉換
String不是基本資料型別,是參考資料型別
基本資料型別與String + :連接運算,
int Integer.parseInt(str)
double Double.parseDouble(str)
》進制與進制間轉換
二進制(binayr) 以0b或者0B開頭
八進制(decimal) 以數字0開頭表示
十進制 (octal)
十六進制(hex) 0-9以及A-F 以0x或者0X開頭
1、識別符號的命名規則有哪些?
2、識別符號的命名規范有哪些?
3、Java變數按照資料型別怎么劃分?并指出Java的基本資料型別有哪8種?
,并指出各自占用的空間大小,
short byte int long float double boolen char
2 1 4 8 4 8 1 2
4、說明基本資料型別變數之間自動型別提升的運算規則,
5、說明基本資料型別變數之間強制型別轉換的使用規則和強轉可能出現的問題,
1、float 定義變數
2、long 定義變數
【4】運算子
·算術運算子
·+ - * / %
·++(a=2;b=++a; a=3;b=3) ++(a=2;b=a++; a=3;b=2)
·–(a=2;b=–a; a=1;b=1) --(a=2;b=a–;a=1;b=2)
·+(“He”+“llo”) ;“Hello”)
·賦值運算子
· = += -= *= /= %=
·比較運算子(關系運算子)
·== != < > <= >= instanceof(檢查是否是類的物件 “Hello” instanceof String 結果 true)
·邏輯運算子
&–邏輯與 |–邏輯或 !–邏輯非
&&–短路與 ||–短路或 ^–邏輯異或
邏輯與:第一個判斷合格不合格 后邊的代碼都要進行判斷
短路與:第一個判斷不合格 后邊的代碼不在執行
邏輯異或:判斷兩個是否是一樣的 一樣為假 不一樣為真
a b a&b a&&b a|b a||b !a a^b
1 1 1 1 1 1 0 0
1 0 0 0 1 1 0 1
0 1 0 0 1 1 1 1
0 0 0 0 0 0 1 0
·位運算子(系統原始碼會用到,實際開發用到的少)
<< 左移 3<<2=12-->3*2*2=12(在一定范圍內)
>> 右移 3>>1=1-->3/2=1(在一定范圍內)
>>> 無符號右移 3>>>1=1-->3/2=1
& 與運算 6&3=2
| 或運算 6|3=7
^ 異或運算 6^3=5
~ 取反運算 ~6=-7
左移割去多出來的部分、右移看符號
無符號右移空缺位都用00補
面試題:最高效的方式計算 2*8 2<<3 8<<1
·三元運算子
(條件運算式)?運算式1:運算式2
運算子優先級 想要先用的加括號
【5】流程控制
順序結構
分支結構
回圈結構
控制陳述句
if
switch
回圈陳述句
for
while
do while
轉向陳述句
break
continue
return
【方法】(函式)
- 方法怎么定義
- 方法怎么呼叫
- 對方法回傳值的理解
- 一個方法怎么回傳值的
- 一個方法執行結束之后回傳值怎么接收
- 方法的多載overload
·方法遞回(遞回演算法)
3.第三章:面向物件
·面向物件怎么理解?
·類和物件
- 什么是類
- 什么是物件
·類怎么定義
·物件怎么創建
·屬性怎么訪問
·方法怎么訪問
·理解JVM的記憶體管理
·new出來的物件存盤在哪里
·空指標例外
·【封裝】:屬性私有化,對外提供公開的setter和getter放法,
·構造方法:conatructor
·【this關鍵字】
1、this是個關鍵字,翻譯成:這個
2、this是一個參考,this是一個變數,this變數保存了記憶體地址指向了自身,存盤在堆記憶體Java物件內部,
3、每個Java物件都有自身對應的this
4、this可以出現在實體方法當中(this代表當前物件),實體方法(不帶static)
5、多數情況下this可以省略不寫
6、this不能使用在帶有static的方法中
7、靜態方法==>靜態變數
8、main方法中沒有this
實體變數、實體方法的參考都需要物件,
修飾符串列上有static
采用“類名.“的方式訪問,顯然這個方法在執行的時候不需要物件的參加,
static的方法呼叫不需要物件,直接使用類名,所以執行程序中沒有當前物件,所以不能使用this
·【static關鍵字】
1、static關鍵字可以修飾成員變數和成員方法
- 特點:
被static修飾的成員變數會變成靜態變數,靜態變數不單單僅僅只是屬于某一個物件的,
而是屬于類的,所以靜態變數會被該類的所有物件共享,也就是說所有該類的物件使用的是同一份資料,
2、實體方法和靜態方法的訪問
靜態方法只能訪問靜態成員,
實體方法可以訪問靜態和實體成員,
之所以不允許靜態方法訪問實體成員變數,
是因為實體成員變數是屬于某個物件的,
而靜態方法在執行時,并不一定存在物件,
同樣,因為實體方法可以訪問實體成員變數,
如果允許靜態方法呼叫實體方法,將間接地允許它使用實體成員變數,
所以它也不能呼叫實體方法,基于同樣的道理,靜態方法中也不能使用關鍵字this,
3、static代碼塊(類構造的時候執行,多個代碼塊時,按照順序依次執行)
static關鍵字還有一個比較關鍵的作用就是
用來形成靜態代碼塊以優化程式性能,
static塊可以置于類中的任何地方,
類中可以有多個static塊,
在類初次被加載的時候,
會按照static塊的順序來執行每個static塊,
并且只會執行一次,
(JDBC class.format()處有用到靜態代碼塊)
4、Java中規定:static不允許修飾區域變數,
·【super關鍵字】
1、用法:
- super可以用來參考直接父類的實體變數,
- super可以用來呼叫直接父類方法,
- super()可以用于呼叫直接父類建構式
2、注意:
如果我們沒有顯式呼叫super來初始化父類的話,
那么Java會隱式的呼叫super();
來呼叫父類無參建構式并把它放在建構式的第一行
·【final】
1、final 修飾類,表示這個類不能被繼承
final 類中的所有成員方法都會被隱式的指定為final方法
(在使用final修飾類的時候,要注意謹慎選擇,除非這個類真的在以后不會用來繼承或者出于安全的考慮,盡量不要將類設計為final類,)
2、final修飾方法
“使用final方法的原因有兩個,第一個原因是把方法鎖定,以防任何繼承類修改它的含義;第二個原因是效率,在早期的Java實作版本中,會將final方法轉為內嵌呼叫,但是如果方法過于龐大,可能看不到內嵌呼叫帶來的任何性能提升,
在最近的Java版本中,不需要使用final方法進行這些優化了,“
因此,如果只有在想明確禁止 該方法在子類中被覆寫的情況下才將方法設定為final的,
( 注:類的private方法會隱式地被指定為final方法,)
3、修飾變數
修飾變數是final用的最多的地方
對于一個final變數,如果是基本資料型別的變數,則其數值一旦在初始化之后便不能更改;如果是參考型別的變數,則在對其初始化之后便不能再讓其指向另一個物件,
public static void main(String[] args) {
final int i= 1;
// i =20;
//java: 無法為最終變數i分配值
final Object obj =new Object();
obj =new Object();
//java: 無法為最終變數obj分配值
}
·【繼承】
·方法的覆寫
1、什么時候進行方法重寫?
如果父類中的方法已經無法滿足當前子類的業務需求,需要將父類中的方法進行重新寫一遍,就是要改變父類的行為,
注意如果重寫父類中的方法之后,子類物件呼叫的一定是重寫之后的方法,
2、發生方法覆寫的條件
- 發生在具有繼承關系的兩個類之間
- 必須具有相同的方法名,相同的回傳值型別,相同的引數串列
- 重寫的方法不能比被重寫的方法擁有更低的訪問權限
- 重寫的方法不能比被重寫的方法拋出更寬泛的例外
- 私有的方法不能被覆寫
- 構造方法無法被覆寫,因為構造方法無法被繼承
- 靜態方法不存在覆寫
- 覆寫指的是成員方法,和成員變數無關,
繼承最基本的作用是:代碼重用,繼承最重要的作用:方法可以重寫,
【方法多載】
- 方法名稱相同
- 方法引數型別、個數、順序至少有一個不同
- 方法的回傳值型別可以不同
- 方法的修飾符可以不同
- 方法多載只能出現同一個類中
·【多型】:多型的基礎語法+多型的作用(OCP開閉原則)
1、多型使用的好處:
- 消除了類之間的耦合關系
- 大大提高了程式的簡潔性和可拓展性
2、子類物件的多型性,并不適用于屬性
3、OCP開閉原則是指一個軟體物體如類、模板和函式應該對擴展開放,對修改關閉,
強調的是用抽象構建框架,用實作擴展細節,
開閉原則是面向物件設計中最基礎的設計原則,它指導我們應該如何建立穩定靈活的系統,
例如:我們版本更新,盡可能不修改源代碼,但是可以增加新功能,
·【抽象類】
1、抽象類是指在普通類的結構里面增加抽象方法的組成部分
2、抽象方法:普通方法上面會有{},這個表示方法體,有方法體的方法一定可以被物件直接呼叫,而抽象方法是指沒有方法體的方法,
同時抽象方法還必須使用關鍵字abstract做修飾,
而擁有抽象方法的類就是抽象類,抽象類要使用abstract關鍵字宣告,
3、抽象方法的使用原則如下:
- 抽象方法必須為public 或者protected(因為如果為private,則不能被子類繼承,子類邊無法實作該方法),預設情況下默認為public
- 抽象類不能直接實體化,需要依靠子類采用向上轉型的方式處理
- 抽象類必須有子類,使用extends繼承,一個子類只能繼承一個抽象類
- 子類(如果不是抽象類)則必須覆寫抽象類中的所有抽象方法,(如果子類沒有實作父類的抽象方法,則必須將子類也定義為abstract類)
4、抽象類的使用限制
(1)抽象類中有構造方法么?
由于抽象類里會存在一些屬性,那么抽象類中一定存在構造方法,其存在目的是為了屬性的初始化,
并且子類物件實體化的時候,依然滿足先執行父類構造,再執行子類構造的順序,
(2)抽象類可以用final宣告么?
不能,因為抽象類必須有子類,而final定義的類不能有子類;
(3)抽象類能否使用static宣告?
外部抽象類不允許使用static宣告,而內部的抽象類運行使用static宣告,使用static宣告的內部抽象類相當于一個外部抽象類,繼承的時候使用“外部類.內部類”的形式表示類名稱,
·【介面】
- 介面的定義:介面是一系列方法的宣告,是一些方法特征的集合,一個介面只有方法的特征沒有方法的實作,因此這些方法可以在不同的地方被不同的類實作,而這些實作可以具有不同的行為(功能),
- 介面的特點:
1、Java介面中的成員變數默認都是public 、static、final型別的(都可以省略),必須被顯示初始化,即介面中的成員變數為常量,
2、Java介面的方法默認都是public、abstract型別的(都可省略),沒有方法體,不能被實體化
3、Java介面中的方法只能包含public static final 型別的成員變數和public abstract 型別的成員方法
4、介面中沒有構造方法,不能被實體化
5、一個介面不能實作(implement)另一個介面,但是它可以繼承多個其他介面
6、Java介面必須通過類來實作它的抽象方法
7、當類實作某個Java介面時,它必須實作介面中的所有抽象方法,否則這個類必須宣告為抽象類
8、不允許創建介面的實體,但允許定義介面型別的參考變數,該參考變數參考實作了這個介面的類的實體
9、一個類只能繼承一個直接的父類,但可以實作多個介面,間接的實作了多繼承,
- 介面的用法
兩個及以上的類擁有相同的方法,但是實作功能不一樣,就可以定義一個介面,將這個方法提煉出來,在需要使用該方法的類中去實作,就免去了定義系統方法的麻煩,
·例如:人會吃飯,睡覺
人有三個身份 學生、 教師 、校領導
吃的不一樣,住的不一樣
但是都會吃、住,
此時定義一個介面
interface Peron{
void eat();
void sleep();
}
·【Object類中的常用方法】
equals hashCode toString finalize clone..
·【內部類】:重點掌握匿名內部類,
內部類:
1.什么是內部類?
內部類:在類的內部又定義了一個新的類,被稱為內部類,
2.內部類的分類
靜態內部類:類似于靜態變數
實體內部類:類似于實體變數
區域內部類:類似于區域變數
3.匿名內部類
new 介面{實作方法}
·【向上轉型 ||向下轉型】
- 向上轉型
通過子類物件(小范圍)實體化父類物件(大范圍),這種屬于自動轉換
向上轉型時,父類只能呼叫父類方法或者子類覆寫后的方法,而子類中的單獨方法則是無法呼叫的.
public class A{
public void fun(){
sout("A");
}
}
public class B extends B{
public void fun(){
sout("B");
}
}
main(){
A a= new B(); //向上轉型 自動的
a.fun();
}
輸出: B
- 向下轉型
通過父類物件(大范圍)實體化子類物件(小范圍),這種屬于強制轉換
public class C extends A{
public void fun() {
System.out.println(“C”);
}
public void funC(){
System.out.println("C的方法啊");
}
}
public class ABCtest {
public static void func(A a){
a.fun();
if( a instanceof B){
B b =new B();
b.funB();
}
else if(a instanceof C){
C c= new C();
c.funC();
}
}
public static void main(String[] args) {
func(new A());
func(new B());
func(new C());
}
}
結果:A
B
B的方法
C
C的方法啊
【JVM記憶體結構——堆、堆疊、方法區】
方法區;類加載器classloader,將硬碟上的xxx.class位元組碼檔案裝載到JVM的時候,會將位元組碼檔案存放到方法區當中,也就是說方法區中存盤的是代碼片段,
(因為類需要加載,所以方法區當中最先有資料,)
堆疊記憶體:在方法被呼叫的時候,該方法需要的記憶體空間在堆疊中分配,
方法只有在呼叫的時候才會在堆疊中分配空間,并且呼叫的時候就是壓堆疊,
方法執行結束之后,該方法所需要的空間就會釋放,此時發生彈堆疊動作,
(給main方法分配空間)
一、定義
1、堆:FIFO佇列優先,先進先出,jvm只有一個堆區被所有執行緒所共享!堆存放在二級快取中,呼叫物件的速度相對慢一些,生命周期由虛擬機的垃圾回識訓制定,
2、堆疊:FILO先進后出,暫存資料的地方,每個執行緒都包含一個堆疊區!堆疊存放在一級快取中,存取速度較快,“堆疊是限定僅在表頭進行插入和洗掉操作的線性表”,
3、方法區:用來存放方法和static變數,
二、存盤的資料型別
1、堆用來存盤new出來的物件和陣列
2、堆疊用來存盤基本型別變數和物件的參考變數的地址
3、方法區存盤方法和static變數
三、優缺點
1、堆的優點-可以動態的分配記憶體大小,生命周期不確定,缺點-速度略慢
2、堆疊的優點-速度快,缺點-存在堆疊中的資料大小和生命周期必須是明確的,缺少靈活性,
4.第四章:陣列
陣列的記憶體決議
堆疊 堆 方法區
區域變數 new出來的結構 常量池
(物件、陣列) 靜態域
1、寫出一維陣列初始化的兩種方式,
int[] arr=new int[5];//動態初始化
int[] arr=new int[]{};//靜態初始化
2、寫出二維陣列初始化的兩種方式,
int[][] arr=new int[len][len];//動態初始化1
int[][] arr=new int[len][];//動態初始化2
int[][] arr=new int[][]{{},{}};//靜態初始化
3、如何遍歷如下的二維陣列
int[][] arr=new int[][]{{1,2,3},{6,7,8}};
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]);
}
System.out.print("\n");
}
4、不同型別的一維陣列元素的默認初始化值各是多少?
整型:0
浮點型:0.0
char :0
boolean:false
參考型別:null
5、一維陣列的記憶體決議,
*陣列一旦初始化,其長度就是確定的,不能更改,
【Arrays工具類的使用】
查看幫助檔案,
常用方法
/*
* boolean equals(int[] a,int[] b) 判斷兩個陣列是否相等
* String toString(int[] a) 輸出陣列的資訊
* void fill(int[]a ,int val) 將指定值填充到陣列之中
* void sort(int[] a) 對陣列進行排序
* int binarySearch(int[] a,int key) 對排序后的陣列進行二分檢索指定的值
* *
常見例外
/*
*陣列角標越界例外:ArrayIndexOutOfBoundsException
*空指標例外:NullPointerException
**/
【String[] args】
當你使用命令列bai的形du式運行.class檔案時,向你的類傳遞引數zhi.
C:\>java YourClassName 引數1 [引數2 引數3 ....]引數之間用一個空格bai作為間隔符.
String[] args 這個字串陣列是保存運行main函式時輸入的引數的
,例如main函式所在的類名為test
那么你在cmd運行 java test a b c 時,
args[0] = a ,args[1]=b, args[2]=c
你就可以在你的程式中呼叫你輸入的這些變數了,
【陣列的擴容】
① int[] arr2=new int[arr1.length*2] //新陣列長度
for(int i=0;i<arr1.length;i++){ //復制
arr2[i]=arr1[i];
}
② int[] arr2=java.util.Arrays.copyOf(原陣列名,新陣列長度);
③ int[] arr2=new int[arr1.length*2]
System.arraycopy(原陣列名,起始下標,新陣列名,起始下標,復制長度);
(本質就是用一個新的容量大的陣列拷貝原陣列的值)
1、使用冒泡排序,實作如下的陣列從小到大排序
int[] arr=new int[]{34,5,22,-98,6,-76,0,-3};
2、如何反轉上面的陣列,請代碼實作
3、復制上述陣列,得到一個新的陣列
4、使用線性查找,從上述陣列中查找22是否存在,存在回傳所在位置
的索引,不存在,輸出提示資訊
5、陣列中常見的例外有哪些?請舉例說明,
5.第五章 例外
·例外怎么理解
程式執行程序中出現了不正常情況,這種不正常情況叫做,例外,
java語言是很完善的語言,提供了例外的處理方式,一下程式執行程序中出現了不正常的情況,
Java把該例外資訊列印輸出在控制臺,供程式員參考,程式員看到例外資訊在之后,可以對
程式進行引數修改,讓程式更加的健壯,
- 例外資訊是JVM列印的,
·例外在Java中有什么用?
- 給程式員提示程式錯誤資訊,一邊修改,
- 增強健壯性
·例外在Java中以什么形式存在?
- 例外以類和物件的形式存在
public static void main(String[] args) {
NullPointerException n =new NullPointerException(“空指標例外”);
System.out.println(n);
//java.lang.NullPointerException: 空指標例外
}
·例外的繼承結構圖
Throwable(父類)
ERROR(虛擬機錯誤、記憶體溢位、執行緒死鎖) Exception(RuntimeException、IO例外、SQL例外)
RuntimeException(空指標例外NullPointerException、
陣列下標越界例外 ArrayIndexOutOfBoundsException、
算數例外ArithmeticException、
型別轉換例外ClassCastException)
·什么是編譯時例外
是RuntimeException以外的例外,
型別上都屬于Exception類及其子類,
從程式語法角度講是必須進行處理的例外,
如果不處理,程式就不能編譯通過,
如IOException、SQLException等以及用戶自定義的Exception例外,
一般情況下不自定義檢查例外,
·什么是運行時例外
都是RuntimeException類及其子類例外,
如NullPointerException(空指標例外)、
IndexOutOfBoundsException(下標越界例外)等,
這些例外是不檢查例外,程式中可以選擇捕獲處理,
也可以不處理,這些例外一般是由程式邏輯錯誤引起的,
程式應該從邏輯角度盡可能避免這類例外的發生,
運行時例外的特點是Java編譯器不會檢查它,也就是說,
當程式中可能出現這類例外,即使沒有用try-catch陳述句捕獲它,
也沒有用throws子句宣告拋出它,也會編譯通過,
·ERROR (錯誤)是程式無法處理的錯誤,表示代碼運行時JVM出現問題,如JVM運行錯誤、類定義錯誤,
·例外的兩種處理方式:
第一種:捕捉try catch
輸出列印例外資訊,
第二種:throws(宣告該方法出現此類例外時上拋)
呼叫方法時必須對這種例外進行預先的處理,如果不處理就會報錯,
*未報告的例外錯誤java.lang.ClassNotFoundException; 必須對其進行捕獲或宣告以便拋出
·finally子句的用法
- 在finally子句中的代碼是最后執行的,并且是一定執行的,即使是try陳述句中的代碼出現例外
必須和try一起出現,不能單獨撰寫
- finally陳述句通常在哪些情況下執行?
流使用完要關閉,占用資源的關閉時,在finally子句中關閉,
·怎么自定義例外
兩步:
第一步:撰寫一個類繼承Exception(編譯時例外)或者RuntimeException(運行時例外)
第二步:提供兩個構造方法,一個無引數的,一個帶有String 引數的
·怎么手動拋異? throw new RuntimeException
·例外物件的兩個方法?
e.getMessage();獲取例外的簡短資訊
e.printStackTrace();列印例外追蹤堆疊資訊
·方法重寫與例外
·關鍵字:
try
catch
finally
throw
throws
- try catch
1、catch后面的小括號中的型別可以是具體的例外型別,也可以是該例外型別的父型別
2、catch可以寫多個,建議catch的時候,精確的一個一個處理,這樣有利于程式的除錯
3、catch寫多個的時候,從上到下,必須遵循從小到大的原則
【上報和捕捉】
希望呼叫者知道就上報,希望程式繼續運行就捕捉,
【JDK8的新特性】 :catch(例外1|例外2)
【final、finally、finalize】
final是一個關鍵字 表示最終的、不變的
finally也是一個關鍵字
finalize 是一個識別符號,是一個方法,
6.第六章 常用類
·String類的實作原理,記憶體存盤方式,
- String str = “abc”;
相當于; char data[] = {‘a’, ‘b’, ‘c’};
String str = new String(data);
- 存盤在方法區的常量池中
雙引號創建的字串可以直接用,new出來的字串當物件處理
·String一旦創建就不會改變,如果有+ 那么實際新建三個字串
-字串的比較:s1.equals(s2);
·String類的構造方法
- String s = new String(“abc”);
- String s =“abc”;
·String類的常用方法
- 見JDKAPI幫助檔案
·StringBuilder StringBuffer的常用方法?以及和String的區別
- java字串是不可變的,開發程序中,需要大量的字串拼接,會占用大量的方法區記憶體,造成記憶體空間的浪費,
StringBuffer 進行字串拼接,
- 區別
StringBuilder:初始容量16(執行緒不安全)
StringBuffer:初始容量16 (執行緒安全的synchronized修飾表示StringBuffer 在多執行緒環境運行是安全的)
·八種基本資料型別對應的包裝類
基本資料型別 包裝型別
--------------------------
byte java.long.Byte
short java.lang.Short
int java.lang.Integer
long java.lang.Long
float java.lang.Float
double java.lang.Double
boolean java.lang.Boolean
char java.lang.Character
Integer為代表
自動裝箱和自動拆箱是什么?
-JDK 1.5之后支持自動拆箱和自動裝箱
·自動裝箱:基本資料型別自動裝換成包裝類
·自動拆箱:包裝類自動轉換成基本資料型別
·有了自動拆箱之后,Number類中的方法就用不著了;
Integer、int、String三種型別互相轉換
·數字的處理
NumberFormat
BigDecimal(財務資料)
·日期處理
怎么獲取系統當前時間
Date date =new Date();
怎么獲取毫秒
date.getTime();
怎么進行日期格式化
怎么將字串日期轉換成日期型別Date
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-mm-dd hh:MM:ss SSS");
Date date= sdf.parse("String");
·列舉型別
回傳值兩種 Boolean
回傳值多種 使用enum列舉型別
public class enumTest {
public static void main(String[] args) {
Serson s =fun();
System.out.println(s);
}
public static Serson fun(){
return Serson.SPRING;
}
}
enum Serson{
SPRING,SUMMER,AUTOMU,WINTER
}
·亂數
import java.util.Random;
Random random =new Random();
int i =random.nextInt(10);
生成0-1之間的亂數,
double random = Math.random();
7.第七章 集合
·集合概述
1.1什么是集合?有什么用?
陣列其實就是個集合,集合實際上就是一個容器,可以容納其他型別的資料,
集合為什么說在開發中使用較多?
集合是一個容器,一個載體,可以一次容納多個物件,
·集合中都可以存盤什么元素
集合不能直接存盤基本資料型別,另外集合也不能直接存盤Java物件,
集合當中存盤的都是Java物件的記憶體地址,或者說集合中存盤的是參考
注意:
集合在Java中本身是一個容器
集合在任何時候存盤的都是"參考"
·在Java中集合分為兩大類:
一類是單個方式存盤元素:
單個方式存盤元素,這一類集合中超級父介面:java.util.Collection;
一類是以鍵值對的方式存盤元素
以鍵值對的方式存盤元素,這一類集合中超級父介面:java.util.Map;
·集合的繼承結構圖Collection
·集合的繼承結構圖Map
·Collection介面中常用的方法
見幫助檔案
·Collection集合的遍歷方法
~Iterator it =Collection.Iterator();
it是迭代器物件
遍歷集合
while(it.hasNext()){
Object o = it.next();
System.out.println(o);
}
·List集合特點
List集合中特有的方法
~get() ~indexOf() ~set() ~remove() ~lastIndexOf()
·Set集合特點
·ArrayAList集合
底層是什么資料結構
ArrayList集合的初始化容量
ArrayList集合的擴容是怎樣的?
(01) ArrayList 實際上是通過一個陣列去保存資料的,當我們構造ArrayList時;若使用默認建構式,則ArrayList的默認容量大小是10,
(02) 當ArrayList容量不足以容納全部元素時,ArrayList會重新設定容量:新的容量=“(原始容量x3)/2 + 1”,
(03) ArrayList的克隆函式,即是將全部元素克隆到一個陣列中,
(04) ArrayList實作java.io.Serializable的方式,當寫入到輸出流時,先寫入“容量”,再依次寫入“每一個元素”;當讀出輸入流時,先讀取“容量”,再依次讀取“每一個元素”,
·LinkedList集合
底層是什么資料結構
雙向鏈表
鏈表資料結構的優點和缺點
優點:在指定位置增加洗掉元素效率高
缺點:查找效率低
·Vectot集合
底層是什么資料結構
陣列
Vector集合的初始化容量
Vector集合的擴容是怎樣的
Vector和ArrayList集合的區別
synchronized!!!
·HashSet集合底層是HashMap
·SortedSet介面,可排序的集合,子類有:TreeSet
·TreeSet集合底層是TreeMap集合
·Map集合中常用的方法
·HashMap集合的底層資料結構
哈希表
哈希演算法是怎樣的
為什么要重寫hashcode equals
HashMap的默認加載因子
HashMap集合的初始化容量
Hash Map的擴容是怎樣的
借鑒文章:
https://blog.csdn.net/zhengwangzw/article/details/104889549?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight
·Hash table集合底層是什么資料結構
·Hashtable下的子類Properties有一定的理解
·Sorted Map的key可排序是如何實作的
·TreeMap集合底層是一個二叉樹的資料結構,他是怎么樣的一個資料結構
·Map集合的遍歷有多種方式需要掌握
public class Test4 {
public static void main(String[] args) {
HashMap<Phone,String> map = new HashMap<>();
map.put(new Phone(“Apple”,7000),“美國”);
map.put(new Phone(“Sony”,5000),“日本”);
map.put(new Phone(“Huawei”,6000),“中國”);
Set<Map.Entry<Phone, String>> entries = map.entrySet();
for (Map.Entry<Phone, String> entry : entries) {
System.out.println(entry.getKey().getBrand()+"="+entry.getKey().getPrice()+"="+entry.getValue());
}
}
}
·集合的泛型
泛型標志:<>
·集合的工具類:Collection的常用方法
總結:(所有實作類)
ArrayList:底層是陣列
LinkedList:底層是雙向鏈表
Vector:底層是陣列,執行緒安全的,效率較低,使用較少
HashSet:底層是HashMap,放到HashSet集合中的元素等同于放到HashMap集合的key部分了
TreeSet:底層是TreeMap,放到TreeSet集合中的元素等同于放到Tree Map集合key部分了
HashMap:底層是哈希表,之不夠執行緒安全的,效率較低,使用較少
Properties:是執行緒安全的,并且key和value只能存盤字串
TreeMap:底層是二叉樹,TreeMap集合的key可以自動按照大小順序排序
List集合存盤元素的特點:
有序可重復
有序:存進去的順序和取出的順序相同,每一個元素都有下標
可重復:有一個1 還可以在存1
Set集合存盤元素的特點:
無序不可重復
無序:存進去的順序和取出的順序不一定相同,另外Set集合元素沒有下標
不可重復:有1 了不能在存盤1了
Sorted(SortedMap)集合存盤元素的特點:
首先是無序不可重復,但是SortedSet集合中的元素是可排序的,
無序:存進去的順序和取出的順序不一定相同,另外Set集合中元素沒有下標
可排序:可以按照大小順序排序
Map集合的key,就是一個Set集合
在Set集合中放資料,實際上是放到了Map集合的key部分,
8.第八章 IO流(I:Input O:Output)
skip() 跳過并從輸入流中丟棄 n位元組的資料,
available()回傳從此輸入流中可以讀取(或跳過)的剩余位元組數的估計值,而不會被下一次呼叫此輸入流的方法阻塞,
~重點掌握哪些流?16個流
檔案專屬:
FileInputStream
FileOutputStream
FileReader
FileWriter
緩沖流專屬:
BufferedReader
BufferedWriter
BufferdInputStream
BufferdOutputStream
轉換流:(將位元組流轉換成字符流)
InputStreamReader
OutputStreamWriter
物件專屬流:
ObjectInputStream
ObjectOutputStream
資料流專屬:
DataInputStream
DaraOutputStream
標準輸出流:
PrintWriter
PrintStream
~流的分類?(在Java中只要"類名"以Stream結尾的都是位元組流,以"Reader/Writer"結尾的都是字符流)
輸入流 輸出流
位元組流 字符流(四大家族的首領都是抽象類)
節點流 包裝流
(當一個流的構造是一個流的時候,構造里的這個流叫位元組點流,外部的流叫做包裝流),
一種方式是按照流的方向進行分類:
以記憶體作為參照物,
往記憶體中去,叫做輸入(Input),或者叫做讀(Read)
從記憶體中出來,叫做輸出(Output),或者叫做寫(Write)
另一種方式是按照讀取資料方式不同進行分類:
有的流是按照位元組的方式讀取資料,一次讀取1個位元組byte,等同于一次讀取8個二進制位,這種流是方能的,
什么型別的檔案都可以讀取,例如:文本檔案,圖片,聲音檔案,視頻
有的流是按照字符的方式讀取資料的,一次讀取一個字符,這種流為了方便讀取文本檔案而存在的,這種流不能讀取:圖片、聲音、視頻等檔案,只能讀取純文本檔案,
連word都不無法讀取,
所有的流都實作了:
java.io.Closeable介面,都是可關閉的,
流畢竟是一個管道,是記憶體和硬碟之間的通道,
會耗用資源,用完一定要關閉,
所有的輸出流都實作了:
java.io.Flushable介面,都是可重繪的,都有flush()方法,
養成了一個好習慣,輸出流在最終輸出之后,一定要記得flush()重繪一下
,這個重繪表示將管道當中剩余未輸出的資料強行輸出完,重繪的作用:清空管道
注意:如果沒有flush()可能會缺失資料
~能夠使用流完成檔案的復制
~掌握File類的常用方法,
1.File類和四大家族沒有關系,所以不能完成檔案的讀和寫,
2.File物件代表什么?
檔案和目錄路徑名的抽象表示形式,
C:\Drivers 這是一個File物件
C:\Drivers\readMe.txt 這也是File物件
一個File物件有可能對應的是目錄,也可能是檔案,
File只是一個路徑名的抽象表示形式,
3.常用方法:
~見檔案夾 File類常用方法
FileInputStream:
/*
-
1.檔案位元組輸入流,萬能的,任何型別的檔案都可以采用這個流來讀,
-
2.位元組的方式,完成輸入的操作,完成讀的操作(硬碟—>記憶體)
-
-
*/
BufferedReader:
1.帶有緩沖區的字符輸入流
2.使用這個流的時候不需要自定義char資料,自帶緩沖,DataInputStream
1.寫的檔案記事本打不開,以什么順序寫入的,就以什么順序讀取,PrintStream
1.標準的位元組輸出流,默認輸出到控制臺的
2.標準的輸出流不需要close()關閉
/* -
標準的輸出流(日志框架原理)
-
*/
public class PrintStreamTest {
public static void main(String[] args)throws Exception {
PrintStream ps= new PrintStream(new FileOutputStream(“D:\從零開始\java\IO流\PrintStreamFile.txt”));
//改變輸出方向
System.setOut(ps);ps.println("hello"); ps.println("你好"); ps.println("My Girl");}
}
ObjectOutStream類要實作Serializable介面(JVM自動生成序列化版本號)
建議:手動寫序列化版本號
private static final long serivalVersionUID=???
序列化和反序列化
序列化多個物件:將對像放到List集合中,將集合序列化、反序列化
transient關鍵字:修飾屬性時不參與序列化
Java語言中采用什么機制區分類的?
第一:首先通過名字進行比對,如果類名不一樣,肯定不似乎同一類
第二:如果類名一樣,再怎么進行類的區別,靠序列化版本號進行區分,
自動生成的序列化版本號有什么缺陷?
后期不能修改代碼最終結論: 凡是類實作了Serializable,給類一個固定不變的版本號,IO和Properties聯合使用
/* -
IO 和Properties 聯合使用
-
*/
import java.io.FileReader;
import java.util.Properties;
public class IOTest {
public static void main(String[] args) throws Exception{
FileReader fr =new FileReader(“D:\從零開始\java\IO流\IOProperties.txt”);
Properties p =new Properties();
p.load(fr);
String username = p.getProperty(“username”);
System.out.println(username);
fr.close();
}
}
9.第九章 多執行緒
1.什么是行程?什么是執行緒?
行程是一個應用程式,(一個行程是一個軟體)
執行緒是一個行程的執行場景/執行單元
一個行程可以啟動多個執行緒
2.對于Java程式來說,當在DOS命令視窗輸入:
Java helloWorld回車之后,
會先啟動JVM,而JVM就是一個行程
JVM在啟動一個主執行緒呼叫main方法,
同時再啟動一個垃圾回收執行緒負責看護,回收垃圾,
最起碼Java程式中至少有兩個執行緒并發,一個是垃圾回收執行緒,一個是執行main方法的主執行緒
3.行程和執行緒是什么關系?
行程A和行程B的記憶體獨立不共享
執行緒A和執行緒B
在Java語言中,堆記憶體和方法區記憶體共享,
但是堆疊記憶體獨立,一個執行緒一個堆疊,
假設啟動10個執行緒,會有10個堆疊空間,每個堆疊和每個堆疊之間,互不干擾,
Java之所以有多執行緒機制,目的就是提高程式的處理效率,
4.使用多執行緒機制之后,main方法結束,是不是有可能程式沒結束
5.對于單核的CPU來說,真的可以做到真正的多執行緒并發嗎?
什么是真正的對執行緒并發?
t1執行緒執行t1的,
t2執行緒執行t2的,
t1不會影響t2,t2也不會影響t1,這叫真正的多項成并發,
單核CPU表示只有一個大腦,
不能夠做到真正的多項成并發,但是可以做到給人一種"多執行緒并發"的感覺,
對于單核CPU來書,在某一個時間點只能處理一件事請,但是由于CPU的處理速度極快,
多個執行緒之間頻繁切換執行,給人感覺是多個事請同時在做,
6.Java語言中,實作多執行緒有兩種方式,哪兩種方式呢?
第一種方式:撰寫一個類,直接繼承java.lang.Thread,重寫run方法,
//定義執行緒類
public class MyThread extends Thread{
public void run(){
}
}
//創建執行緒物件
MyThread t =new MyThread();
//啟動執行緒
t.start();
第二種方式:撰寫一個類,實作java.lang.Runnable介面,實作run方法,
//定義一個可運行的類
public class MyRunnable implements Runnable{
public void run(){
}
}
//創建執行緒物件
Thread t =new Thread(new MyRunnable());
//啟動執行緒
t.start();
============================================================
//匿名內部類
Thread t =new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(“分支執行緒”+i);
}
}
});
t.start();
~多執行緒的三種方式
繼承Thread
實作Runable
實作Callable
~多執行緒的生命周期
~執行緒的調度(sleep、yield...)
~執行緒的安全(重點)
~定時器/定時任務
~守護執行緒
~wait方法和notify方法,生產者和消費者模式
24小時多執行緒筆記:
1 執行緒概述
1.1 執行緒相關概念
行程
行程(Process)是計算機中的程式關于某資料集合上的一次運行活動,
是作業系統進行資源分配與調度的基本單位,
可以把行程簡單的理解為正在作業系統中運行的一個程式,
執行緒
執行緒(thread)是行程的一個執行單元,
一個執行緒就是行程中一個單一順序的控制流,行程的一個執行分支,
行程是執行緒的容器,一個行程至少有一個執行緒,一個行程也可以有多個執行緒,
在作業系統中是以行程為單位分配資源,如虛擬存盤空間,檔案描述符等,
每個執行緒都有各自的執行緒堆疊,自己的暫存器環境,自己的執行緒本地存盤,
主執行緒與子執行緒
JVM啟動時會創建一個主執行緒,該主執行緒負責執行main方法,主執行緒就是運行main
方法的執行緒
Java中的執行緒不孤立,執行緒之間存在一些聯系,如果在A執行緒中創建B執行緒,稱B執行緒為A執行緒的子執行緒,相應的A執行緒就是B
執行緒的父執行緒,
串行,并發與并行
串行(Sequential)先做任務A,完成之后在做任務B,完成之后再做任務C
,所有的任務逐個完成,
并發(Concurrent)先開始做任務A,在等待A完成的這段時間內開始做任務B,在等待B完成的時候做任務C.任務交替完成的,
并行(Parallel),三個任務同時開始,總耗時取決于需要時間最長的那個任務,
并發可以提高事物的處理效率,即在一段時間內可以處理或者完成過呢更多的事請,
并行是一種更為嚴格,理想的并發,
從硬體角度來說,如果單核CPU,一個處理器一次只能執行一個執行緒的情況下,處理器可以使用時間片輪轉技術,可以讓CPU快速的在各個
執行緒之間切換,對于用戶來說,感覺三個執行緒在同時執行,如果是多核CPU,可以為不同的執行緒分配不同的內核,
1.2 執行緒的創建與啟動
在Java中創建一個執行緒就是創建一個Thread類(子類)的物件(實體),
Thread類有兩個常用的構造方法:Thread()與Thread(Runnabled)對應的創建執行緒的兩種方式,
定義Thread類的子類
定義一個Runnable介面的實作類
這兩種創建執行緒的方式沒有本質的區別,
1.3 執行緒的常用方法
1.currentThread()方法
Thread.currentThread()方法可以獲得當前執行緒
Java中的任何一段代碼都是執行在某個執行緒當中的,執行當前代碼的執行緒就是當前執行緒,
同一段代碼可能被不同的執行緒執行,因此當前執行緒是相對的,這個方法的回傳值是在代碼實際運行的
時候執行緒物件,
2.setName()/getName()
thread.setName(執行緒名稱),設定執行緒名稱
thread.getName()回傳執行緒名稱
通過設定執行緒名稱,有助于程式除錯,提高程式的可讀性,建議為每個執行緒都
設定一個能夠體現執行緒功能的名稱,
3.isAlive()
thread.isAlive()判斷當前執行緒是否處于活動狀態
活動狀態就是執行緒已啟動并且尚未終止,
4.sleep()
Thread.sleep(毫秒數):當前執行緒睡眠多少毫秒
當前執行緒指的是:Thread.currentThread()回傳的執行緒
注意:子執行緒的run()方法中例外只能捕獲處理,而不能上拋,因為父類的run方法沒有拋出例外,
5.getId()
thread.getId():可以獲得執行緒的唯一標識
注意:
某個編號的執行緒運行結束后,該編號可能被后續創建的執行緒使用
重啟的JVM后,同一個執行緒的編號可能不一樣
6.yield()
Thread.yield()方法的作用是放棄當前的CPU資源,
執行緒讓步,放棄CPU的執行權,
7.setPriority()
thread.setPriority(num);設定執行緒的優先級
Java執行緒的優先級取值范圍是1~10,如果超出這個范圍會拋例外IllegalArgumentException.
在作業系統中,優先級較高的執行緒獲得CPU的資源越多
執行緒優先級本質上只是給執行緒調度器一個提示資訊,以便與調度器決定先調度哪些執行緒,注意不能保證優先級高的執行緒先運行,
Java優先級設定不當或者濫用可能會導致某些執行緒永遠無法得到運行,即產生了執行緒饑餓,
執行緒的優先級不是設定的越高越好,一般情況下使用普通的優先級即可,即在開發時不必設定執行緒的優先級,
8.interrupt()
中斷執行緒.
注意呼叫interrrupt()方法僅僅是在當前執行緒打一個停止標志,并不是真正的停止執行緒,
isInterrupted()
該方法可以回傳執行緒的中斷標志,
9.setDaemon()
java中的執行緒分為用戶執行緒與守護執行緒
守護執行緒是為其他執行緒提供服務的執行緒,如垃圾回收器(GC)就是一個典型的守護執行緒,
守護執行緒 不能單獨運行,當JVM中沒有其他用戶執行緒,只有守護執行緒時,守護執行緒會自動銷毀,JVM會退出,
注意:設定守護執行緒應該在start()之前,
1.4 執行緒的生命周期
執行緒的生命周期是執行緒物件的生老病死,即執行緒的狀態,
執行緒生命周期可以通過getState()方法獲得,執行緒的狀態是
Thread.State 列舉型別定義的,由以下幾種:
NEW ,新建狀態,創建了執行緒物件,在呼叫start()啟動之前的狀態;
RUNNABLE,可運行狀態,它是一個復合狀態,包含:READY 和RUNNING兩個
狀態,READY狀態該執行緒可以被執行緒調度器進行調度使它處于RUNNING狀態,RUNNING狀態表示該執行緒正在執行,
Thread.yield()方法可以把執行緒由RUNNING狀態轉換為READY狀態,
BLOCKED,阻塞狀態,執行緒發起阻塞的I/O操作,或者申請由其他執行緒占用的獨占資源,執行緒會轉為BLOCKED阻塞狀態,
處于阻塞狀態的執行緒不會占用CPU資源,當阻塞I/O執行完,或者執行緒獲得了其申請的資源,執行緒可以轉換為RUNNABLE,
WAITING,等待狀態,執行緒執行了object.wait(),thread.join()方法會把執行緒轉換為WAITING等待狀態,執行object,notify()方法,
或者加入的執行緒執行完畢,當前執行緒會轉換為RUNNABLE狀態,
TIMED_WAITING,狀態與WAITING狀態類似,都是等待狀態,區別在于處于該狀態的執行緒不會無限的等待,如果執行緒沒有在指定的時間范圍內完成期望的操作,
該執行緒自動轉換為RUNNABLE
TERMINATED,終止狀態,執行緒結束處于終止狀態,
1.5多執行緒編程的優勢與存盤的風險
多執行緒編程具有以下優勢:
1)提高系統的吞吐率(Throughout),多執行緒編程可以使一個行程有
多個并發(concurrent),即同時進行的操作,
2)提高回應性(Responsiveness),Web服務器會采用一些專門的執行緒
負責用戶的請求處理,縮短了用戶的等待時間
3)充分利用多核(Multicore)處理器資源,通過多執行緒可以充分的利用CPU資源
多執行緒編程存在的問題與風險:
1)執行緒安全(Thread safe)問題,多執行緒共享資料時,如果沒有采取爭取的
并發訪問控制措施,就會產生資料一致性問題,如讀取臟資料(過期的資料)
如丟失資料更新,
2)執行緒活性(Thread liveness)問題,由于程式自身的缺陷或者有資源稀缺性導致執行緒
執行緒一直處于非RUNNABLE狀態,這就是執行緒活性問題,常見的活性故障有以下幾種:
(1)死鎖(Deadlock),類似于鷸蚌相爭,
(2)鎖死(Lockout),類似于睡美人 故事中王子掛了,
(3)活鎖(Livelock),類似于小貓咬自己尾巴
(4)饑餓(Starvation),類似于健壯的雛鳥總是從母鳥嘴中搶到食物
3)背景關系替換(Context Switch)處理器從執行一個執行緒切換到執行另外一個執行緒
4)可靠性 可能會有由一個執行緒導致JVM意外終止,其他的執行緒也無法執行
2 執行緒安全問題
非執行緒安全主要是指多個執行緒對同一個物件的實體變數進行操作時,
會出現值被更改,值不同步的情況,
執行緒安全問題表現為三個方面:原子性、可見性和有序性
2.1原子性
原子(Atomic)就是不可分割的意思,原子操作的不可分割有兩層含義:
1)訪問(讀、寫)某個共享變數的操作從其他執行緒來看,該操作要么已經執行完畢
,要么尚未發生,其他執行緒看不到當前操作的中間結果,
2)訪問同一組共享變數的原子操作是不能夠交錯的,
Java中有兩種方式實作原子性:一種是使用鎖;另一種利用處理器的CAS(Compare And Swap)指令
鎖具有排他性,保證共享變數在某一時刻只能被一個執行緒訪問,
CAS指令直接在硬體(處理器和記憶體)層次上實作,看作是硬體鎖,
2.2可見性
在多執行緒環境中,一個執行緒對某個共享變數進行更新之后,后續其他的執行緒可能無法立即讀到這個更新的結果,這就是執行緒安全問題的
的另一種形式:可見性(visibility)
如果一個執行緒對共享變數更新后,后續訪問該變數的其他執行緒可以讀到更新的結果,稱這個執行緒對共享變數的更新對其他執行緒可見,否則稱這個
執行緒對共享變數的更新對其他執行緒不可見,
多執行緒程式因為可見性問題可能會導致其他執行緒讀到了舊資料(臟資料),
2.3有序性
有序性(Ordering)是指在什么情況下一個處理器上運行的一個執行緒所執行的,記憶體訪問操作在另外一個處理器運行的其他執行緒看來是亂序的(Out of Order).
亂序是指記憶體訪問操作的順序看起來發生了變化
在多核處理器的環境下,撰寫的順序結構,這種操作執行的順序可能是沒有保障的;
編譯器可能會改變兩個操作的先后順序;
處理器也可能不會按照目標代碼的順序執行;
這種一個處理器上執行的多個操作,在其他處理器來看它的順序于目標代碼指定的順序可能不一樣,
這種現象稱為重排序,
重排序是對記憶體訪問有序操作的一種優化,可以在不影響單執行緒的程式正確的情況下提升程式的性能,但是可能對多執行緒程式的
正確性產生影響,即可能導致執行緒安全問題,
重排序與可見性問題類似,不是必然出現的,
與記憶體操作順序有關的幾個概念:
源代碼順序,就是原始碼中指定的記憶體訪問順序,
程式順序,處理器上運行的目標代碼所指定的記憶體訪問順序
執行順序,記憶體訪問操作在處理器上的實際執行順序,
感知順序,給定處理器所感知到的該處理器及其他處理器的記憶體訪問操作的順序
2.4Java記憶體模型
10.第十章 反射機制
1.反射機制有什么用?
用過Java語言中的反射機制可以操作位元組碼檔案,
可以讀和修改位元組碼檔案
通過反射機制可以操作代碼片段(class檔案)
2.反射機制相關的類有哪些?
java.lang.Class :代表整個位元組碼,代表一個型別
java.lang.reflect.Method:代表位元組碼中的方法位元組碼
java.lang.reflect.Constructor:代表位元組碼中的構造方法位元組碼
java.lang.reflect.Field:代表位元組碼中的屬性位元組碼,
//java.lang.class
public class User{
//Field
int no;
//Constructor
puclic User(){
}
//method
public void setNo(int no){
this.no=no;
}
public int getNo(){
return no;
}
}
~獲取Class的三種方式
第一種方式:
Class.forName()
1.靜態方法
2.方法的引數是一個字串/
3.字串需要的是一個完整類名
4.完整類名必須帶有包名,java.lang包也不能省略,
例:
try{
Class c1 =Class.forName("java.lang.String"); //c1代表String.class檔案
}catch{
e.printStackTrace();
}
第二種方式:
Java中任何一個物件都有一個方法getClass();
例:
String s= "abc";
Class x =s.getClass();//x代表String.class位元組碼檔案
第三種方式:
Java語言種任何一種型別,包括基本資料型別,它都有.class 屬性
例:
Class z =String.class;
Class x =Date.class;
~通過反射機制能夠實體化物件
反射機制的靈活性:
一次代碼,再不改變原來的代碼基礎上可以做到不同物件的實體化,
符合OCP原則(對擴展開放,對修改關閉)
重點:
如果只是希望一個類的靜態代碼塊執行,其他代碼不執行,
可以使用:
Class.ForName("完整類名");
(JDBC 處使用)
~路徑:
src是類的根路徑,
獲取路徑(采用這種方式可以拿到一個檔案的絕對路徑)
記住: String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
~資源系結器
java.util包下提供了一個資源系結器,便于獲取屬性組態檔中的內容,
屬性組態檔xxxx.properties放在類路徑下,
ResourceBundle bundle =ResourceBundle.getBundle("檔案名不帶后綴");
String className =bundle.getString("className");
~關于JKD自帶的類加載器
1.什么是類加載器?
專門負責加載類的命令/工具
ClassLoader
2.JDK中自帶了三個類加載器
啟動類加載器
擴展類加載器
應用類加載器
3.假設有這樣一段代碼
String s="abc";
代碼在開始執行之前,會將所需要類全部加載到JVM中,
通過類加載器加載,看到以上代碼類加載器會找String.class
檔案,找到就加載,那么是怎么進行加載的呢?
首先通過"啟動類加載器"加載
注意:啟動類加載器專門加載rt.jar核心的類別庫
如果找不到,那么擴展器擴展類
擴展器沒有找到,通過應用類加載器加載
~反射Filed,操作Field
~反射Method,操作Method
~反射Constructor,操作Constructor
~通過反射機制獲取父類,以及獲取父介面
~可變長引數:
int...args
/*可變長度引數
-
1.可變長度引數要求是型別…(一定是三個…)
-
2.引數個數0-N個
-
3.可變長度引數一定在最后位置,并且只能由一個
-
*/
public class args {
public static void main(String[] args) {
fun(3);
fun(10,30);
fun(1,2,3,4);
m1(“hello”);
m1(“zhangsan”,“nihao”);
m1(“a”,“b”,“c”,“d”);}
public static void fun(int …args){
System.out.println(“fun方法執行了”);
}
public static void m1(String …args){
//args屬性有length說明是一個陣列 也可以傳一個陣列
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
11.第十一章 注解
~怎么自定義注解?
1.注解,或者叫做注釋型別,英文單詞是:Annotation
2.注解Annotation是一種參考資料型別,編譯之后也是生成xxx. class檔案,
3.自定義注解?語法格式?
[修飾符串列]@interface 注解型別名{
}
4.注解使用語法格式是:
@注解型別名
注解可以出現在類上、屬性上、方法上、變數上、注解上
5.JDK自帶哪些注解?
標識性注解
@Override 這個注解只能注解方法,這個注解是給編譯器參考的,和運行階段沒有關系,
凡是Java中的方法帶有這個注解的,編譯器都會進行編譯檢查,如果這個方法不是重寫父類的方法,編譯器報錯,
表示方法宣告旨在覆寫超型別中的方法宣告,
API幫助檔案介紹:
如果使用此注釋型別注釋方法,則除非至少滿足以下條件之一,否則需要編譯器生成錯誤訊息:
該方法將覆寫或實作在超型別中宣告的方法, 該方法具有與Object中宣告的任何公共方法的覆寫相同的簽名 ,
Deprecated 用@Deprecated 注釋的程式元素,不鼓勵程式員使用這樣的元素,通常是因為它很危隙訓存在更好的選擇(已過時),
~元注解有哪些?
元注解:用來標注“注解型別”的注解,稱為元注解,
常見的元注解
Target 表示"被標注的注解位置只出現在哪個位置上"
Retention 表示"被標注的注解"最終保存在哪里,
@Retention(RetentionPolicy.SOURCCE):表示該注解只能被保留在Java源檔案中,
@Retention(RetentionPolicy.RUNTIME):表示該注解可以被反射
@Retention(RetentionPolicy.CLASS):表示該注解被保存在class 檔案中,并且可以保留在位元組碼檔案中
~
注解的屬性是value 有且只有一個時,可以省略value =;
其他情況不行
注解中的屬性可以是哪種型別?
byte short int long double boolean char String Class 列舉型別
(以上的陣列形式)
陣列中只有一個元素,大括號可以省略,
~通過反射機制讀取注解?
~了解注解的實作原理以及應用?
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/209476.html
標籤:其他
