java重要基礎知識彙總
Table of Contents
1 定義:程式呼叫自身的程式設計技巧稱為遞迴( recursion)
本篇部落格是我個人對一些常用到的比較零碎的知識的一個大概總結。
抽象類與介面的區別
1.類可以實現多個介面,但是隻能繼承一個類
2.抽象類可以寫方法實現,介面也可以寫方法實現,不過需要加上default修飾。
3.從面向物件的角度來講,抽象類和介面的抽象層次是不一樣的
問題:什麼時候用介面什麼時候用抽象類?
抽象類的關鍵好處在於 能夠實現面向物件設計的一個最核心的原則OCP(Open-ClosedPrinciple)。因此當我有一部分內容是不想讓子類修改的,但是子類又都通用,同時各個自樂又有自己的特點,那麼就適合使用抽象類。
abstract class和interface在Java語言中都是用來進行抽象類。從面向物件的角度來講。我們知道所有的物件都是通過類來描繪的,但是反過來卻不是這樣。並不是 所有的類都是用來描繪物件的,如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類。
在面向物件領域,抽象類主要用來進行型別隱藏。 我們可以構造出一個固定的一組行為的抽象描 述,但是這組行為卻能夠有任意個可能的具體實現方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現則表現為所有可能的派生類。模組可以操作一個 抽象體。由於模組依賴於一個固定的抽象體,因此它可以是不允許修改的;同時,通過從這個抽象體派生,也可擴充套件此模組的行為功能。熟悉OCP的讀者一定知 道,為了能夠實現面向物件設計的一個最核心的原則OCP(Open-Closed Principle),抽象類是其中的關鍵所在。
符合開發封閉原則,我可以對抽象出來的類進行擴充套件,但是隻要是這個抽象類的子類,那麼他必然能夠。
從語法層面上講,java單繼承多實現,介面可以多實現。
java為什麼不支援多繼承
典型的支援多繼承的語言就是C++。在OOP的世界裡,單根繼承意味著所有的類都會有一個終極類,java裡面這個類就是Object。單根繼承既可以說是一門語言的特性,也可以說是一門語言的一個選擇。從純粹技術的角度來說,java也可以做到多繼承,只是如果那樣的話那麼java就不會再是我們今天所認識的java。
單根繼承的優點1:相容性
單根繼承帶來的一個效果就是所有的物件歸根到底都是相同的基本型別。這帶來的好處就是任何java出現的新類庫中,相容性的問題會大大降低,這一點很好理解。但是在C++之中,總是會有一些不相容的介面,這雖然帶來了一定的靈活性,但是對於不相容的介面,往往就是要通過多繼承來解決。
單根繼承的優點2: 便利性
因為單根繼承,所有的物件都會具備某些一樣的功能,比如所有的物件都會有hashcode方法,有euqals方法。因此拿到一個物件時,無論這個物件從哪裡來,我們都知道可以對他執行某些基本操作。引數傳遞也得到了簡化。
單根繼承的優點3: 垃圾回收
單根繼承會使得垃圾回收變得簡單很多。因為所有物件都保證具有其型別資訊,因此不會因為無法確定型別資訊而帶來不便。垃圾回收正是java相對於C++的重要改進之一。
continue關鍵字和break關鍵字
continue關鍵字
使用地方:continue關鍵字只能用於迴圈結構。
作用:跳過本次迴圈,重新開始下一趟迴圈。
例子:
public class HelloWorld {
public static void main(String[] args) {
//列印單數
for (int j = 0; j < 10; j++) {
if(0==j%2)
continue; //如果是雙數,後面的程式碼不執行,直接進行下一次迴圈
System.out.println(j);
}
}
}
列印結果是:1 3 5 7 9。
break關鍵字
使用地方:用於switch結構和迴圈結構
作用:
1.如果用於switch結構,跳出當前的case語句
2.如果用於迴圈結構中,跳出當前迴圈結構。
例子:
public class HelloWorld {
public static void main(String[] args) {
//列印單數
for (int j = 0; j < 10; j++) {
if(0==j%2)
break; //如果是雙數,直接結束迴圈
System.out.println(j);
}
}
}
列印結果是:什麼都不列印
列舉實現機制
列舉型別在編譯器處理之後,是由一個final的繼承Enum類的類實現的。該類是一個實實在在的類,該類當中,編譯器還幫助我們生成了每個列舉型別的例項物件分別對應列舉中定義的每個列舉型別本身。
遞迴
1 定義:程式呼叫自身的程式設計技巧稱為遞迴( recursion)
特點:一個過程或函式在其定義或說明中有直接或間接呼叫自身的一種方法,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題過程所需要的多次重複計算,大大地減少了程式的程式碼量。遞迴的能力在於用有限的語句來定義物件的無限集合
2 組成
- 邊界條件
- 遞迴前進段
- 遞迴返回段
當邊界條件不滿足時,遞迴前進;當邊界條件滿足時,遞迴返回。
3 條件
1. 子問題須與原始問題為同樣的事,且更為簡單;
2. 不能無限制地呼叫本身,須有個出口,化簡為非遞迴狀況處理
4 生活中遞迴的表現
1.德羅斯特效應是遞迴的一種視覺形式。圖中女性手持的物體中有一幅她本人手持同一物體的小圖片,進而小圖片中還有更小的一幅她手持同一物體的圖片,依此類推。
2.我們在兩面相對的鏡子之間放一根正在燃燒的蠟燭,我們會從其中一面鏡子裡看到一根蠟燭,蠟燭後面又有一面鏡子,鏡子裡面又有一根蠟燭……這也是遞迴的表現
3.從小就聽過的例子:從前有座山,山裡有座廟,廟裡有個和尚,和尚在講故事,從前有座山,山裡有座廟,廟裡有個和尚,和尚在講故事,從前有座山...
但是上述例子是和遞迴相似的場景,但是軟體當中定義的遞迴是要有一個終止條件的,否則就是死迴圈了。
5 遞迴演算法一般用於解決三類問題
(1)資料的定義是按遞迴定義的。(Fibonacci函式)
(2)問題解法按遞迴演算法實現。
這類問題雖則本身沒有明顯的遞迴結構,但用遞迴求解比迭代求解更簡單,如Hanoi問題。
(3)資料的結構形式是按遞迴定義的。
如二叉樹、廣義表等,由於結構本身固有的遞迴特性,則它們的操作可遞迴地描述
6 缺點
1.遞迴演算法解題相對常用的演算法如普通迴圈等,執行效率較低
2.在遞迴呼叫的過程當中系統為每一層的返回點、區域性量等開闢了棧來儲存。遞迴次數過多容易造成棧溢位等。
基本資料型別
簡單型別 |
boolean |
byte |
char |
short |
Int |
long |
float |
double |
void |
二進位制位數 |
1 |
8 |
16 |
16 |
32 |
64 |
32 |
64 |
-- |
封裝器類 |
Boolean |
Byte |
Character |
Short |
Integer |
Long |
Float |
Double |
Void |
byte:
- byte 資料型別是8位、有符號的,以二進位制補碼錶示的整數;
- 最小值是 -128(-2^7);
- 最大值是 127(2^7-1);
- 預設值是 0;
- byte 型別用在大型陣列中節約空間,主要代替整數,因為 byte 變數佔用的空間只有 int 型別的四分之一;
- 例子:byte a = 100,byte b = -50。
short:
- short 資料型別是 16 位、有符號的以二進位制補碼錶示的整數
- 最小值是 -32768(-2^15);
- 最大值是 32767(2^15 - 1);
- Short 資料型別也可以像 byte 那樣節省空間。一個short變數是int型變數所佔空間的二分之一;
- 預設值是 0;
- 例子:short s = 1000,short r = -20000。
int:
- int 資料型別是32位、有符號的以二進位制補碼錶示的整數;
- 最小值是 -2,147,483,648(-2^31);
- 最大值是 2,147,483,647(2^31 - 1);
- 一般地整型變數預設為 int 型別;
- 預設值是 0 ;
- 例子:int a = 100000, int b = -200000。
long:
- long 資料型別是 64 位、有符號的以二進位制補碼錶示的整數;
- 最小值是 -9,223,372,036,854,775,808(-2^63);
- 最大值是 9,223,372,036,854,775,807(2^63 -1);
- 這種型別主要使用在需要比較大整數的系統上;
- 預設值是 0L;
- 例子: long a = 100000L,Long b = -200000L。
"L"理論上不分大小寫,但是若寫成"l"容易與數字"1"混淆,不容易分辯。所以最好大寫。
float:
- float 資料型別是單精度、32位、符合IEEE 754標準的浮點數;
- float 在儲存大型浮點陣列的時候可節省記憶體空間;
- 預設值是 0.0f;
- 浮點數不能用來表示精確的值,如貨幣;
- 例子:float f1 = 234.5f。
double:
- double 資料型別是雙精度、64 位、符合IEEE 754標準的浮點數;
- 浮點數的預設型別為double型別;
- double型別同樣不能表示精確的值,如貨幣;
- 預設值是 0.0d;
- 例子:double d1 = 123.4。
boolean:
- boolean資料型別表示一位的資訊;
- 只有兩個取值:true 和 false;
- 這種型別只作為一種標誌來記錄 true/false 情況;
- 預設值是 false;
- 例子:boolean one = true。
char:
- char型別是一個單一的 16 位 Unicode 字元;
- 最小值是 \u0000(即為0);
- 最大值是 \uffff(即為65,535);
- char 資料型別可以儲存任何字元;
- 例子:char letter = 'A';。
Float和Double詳解
關於這兩個資料型別,看過很多資料和部落格也沒有搞明白,部落格質量也參差不齊。Float和Double就是java對於單精度和雙精度提供的兩種支援。
Double
事實上所謂的一個Double型別的數就是一個雙精度型別的數。
雙精度型別資料:Double precision data。 雙精度型(DOUBLE)資料是具有更高精度的一種資料型資料。
雙精度型資料採用固定長充浮點格式儲存,佔用8個位元組.在計算機中每個雙精度型資料佔用8個位元組(64位)的儲存空間,可表示的正數範圍是:4.94065645841247*10^-324~1.79769313486232*10^308,可表示的負數範圍是:-1.79769313486232*10^308~-4.94065645841247*10^-324。雙精度型資料最多可以有15位有效數字
Float
與雙精度對應的就是單精度,單精度。
單精度數是指計算機表達實數近似值的一種方式。它的範圍在負數的時候是從 -3.402823E38 到 -1.401298E-45,而在正數的時候是從 1.401298E-45 到 3.402823E38
記憶體只分配32位,雙精度分配64位記憶體,所以說雙精度的精確度更高,但佔用的記憶體也大,像金錢什麼的要高度精確的就用它。
我們也常常把單精度型別資料叫做浮點型別的數。
引用:
記住java一定要用double,就算數值不大也要用double。
瞭解java虛擬機器的底層會知道,float放在記憶體中其實是當作double來處理的,它不會比double更節約記憶體資源,對應的double虛擬機器會直接以double形式來進行處理,快速而且精度高,但是如果用float,不但不會節約記憶體資源,虛擬機器為了校驗float的精度,會花費更多的系統資源,例如cpu時鐘,程式執行步驟等等。
相對於這點,整數型別,能用int就用int,不要用什麼short型別,道理是一樣,其實虛擬機器中short,char,boolean,byte在記憶體中都是以int形式來處理的,為了校驗精度,虛擬機器還會付出格外的開銷,這樣其實得不償失,不要自作聰明以為節約了記憶體,其實錯了。當然long型別例外,雖然long型別也會增加資源的開銷,但是畢竟能完成int完成不了的功能。
還有,其實這些資源的開銷對於整個應用程式和現有硬體資源而言就是九牛一毛,微乎其微,沒有必要過於在意。就用習慣的形式即可。不要自作聰明的用特別的資料型別,浮點就double,整形就int,長整型就long,其它的必要性都不大(byte的話,用來做陣列還是很方便的,除此不推薦使用。
關於精度:https://blog.csdn.net/a327369238/article/details/52354811/
四種許可權控制關鍵字
修飾詞 | 本類 | 同一個包的類 | 繼承類 | 其他類 |
private | √ | × | × | × |
無(預設) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
Super關鍵字
1:主要存在於子類方法中,用於指向子類物件中父類物件。
2:訪問父類的屬性
3:訪問父類的函式
4:訪問父類的建構函式
this關鍵字
this關鍵字代表自身,如果new了一個物件之後,這這個this就是一個指向這個物件自己的一個引用,如下圖:
用途:
(1)this呼叫本類中的屬性,也就是類中的成員變數
(2)this呼叫本類中的其他方法;
(3)this呼叫本類中的其他構造方法,呼叫時要放在構造方法的首行。
都非常好理解,因為指向的是物件自身,能操作的自然都是成員變數以及類的方法。
final關鍵字
final是java的一個關鍵字,他可以用於修飾類,方法,變數
1 修飾變數
final顧名思義是最終的意思,他修飾變數意味著這個變數的值不能再更改,只是在修飾引用變數的時候,這個值是指的引用不變,但引用的物件的內容是可變的,在修飾基本變數如int, string時,這意味著這個基本型別的值不能改變
2 修飾方法
final修飾的一個方法代表這個方法可以被繼承,但是不可以被子類重寫。一般對一個方法加上final關鍵字作為修飾,代表這個方法你認為不需要再重寫和修改。
final方法比非final方法快的原因是在於final方法是在程式編譯的時候就靜態綁定了,但是在如今的jvm中這個速度已經可以忽略不計了。
3 修飾類
final類不能被繼承,功能通常是完整的。
與finally區別?finally 通常用在異常處理中
與finalize區別?finalize是在Object類中定義的方法,是在垃圾回收時虛擬機器呼叫來終結物件的方法
java重要運算子
算術運算子
假設整數變數A的值為10,變數B的值為20:
操作符 | 描述 | 例子 |
---|---|---|
+ | 加法 - 相加運算子兩側的值 | A + B 等於 30 |
- | 減法 - 左運算元減去右運算元 | A – B 等於 -10 |
* | 乘法 - 相乘操作符兩側的值 | A * B等於200 |
/ | 除法 - 左運算元除以右運算元 | B / A等於2 |
% | 取餘 - 左運算元除以右運算元的餘數 | B%A等於0 |
++ | 自增: 運算元的值增加1 | B++ 或 ++B 等於 21(區別詳見下文) |
-- | 自減: 運算元的值減少1 | B-- 或 --B 等於 19(區別詳見下文) |
關係運算符
例項整數變數A的值為10,變數B的值為20:
運算子 | 描述 | 例子 |
---|---|---|
== | 檢查如果兩個運算元的值是否相等,如果相等則條件為真。 | (A == B)為假(非真)。 |
!= | 檢查如果兩個運算元的值是否相等,如果值不相等則條件為真。 | (A != B) 為真。 |
> | 檢查左運算元的值是否大於右運算元的值,如果是那麼條件為真。 | (A> B)非真。 |
< | 檢查左運算元的值是否小於右運算元的值,如果是那麼條件為真。 | (A <B)為真。 |
>= | 檢查左運算元的值是否大於或等於右運算元的值,如果是那麼條件為真。 | (A> = B)為假。 |
<= | 檢查左運算元的值是否小於或等於右運算元的值,如果是那麼條件為真。 | (A <= B)為真。 |
位運算子
Java定義了位運算子,應用於整數型別(int),長整型(long),短整型(short),字元型(char),和位元組型(byte)等型別。
位運算子作用在所有的位上,並且按位運算。假設a = 60,b = 13;它們的二進位制格式表示將如下
A = 0011 1100
B = 0000 1101
-----------------
A&b = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011
整數變數A的值為60和變數B的值為13
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相對應位都是1,則結果為1,否則為0 | (A&B),得到12,即0000 1100 |
| | 如果相對應位都是0,則結果為0,否則為1 | (A | B)得到61,即 0011 1101 |
^ | 如果相對應位值相同,則結果為0,否則為1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反運算子翻轉運算元的每一位,即0變成1,1變成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移運算子。左運算元按位左移右運算元指定的位數。 | A << 2得到240,即 1111 0000 |
>> | 按位右移運算子。左運算元按位右移右運算元指定的位數。 | A >> 2得到15即 1111 |
>>> | 按位右移補零操作符。左運算元的值按右運算元指定的位數右移,移動得到的空位以零填充。 | A>>>2得到15即0000 1111 |
著重說一下一下幾個
(1)<<
A為60,60對應的二進位制為 0011 1100或者11 1100
A<<2即60 << 2即 0011 1100左移2位 得:1111 0000 。 換算成十進位制就是240。
在這裡我們可以得出移位運算的思路就是:把一個數化成對應的二進位制,然後在進行對應的移位操作,再將移位後的二進位制換算成需要的其他進位制即可。
(2)>>
0011 1100 右移兩位得: 0000 1111 。換算成十進位制就是15.
(3)~
~A 即 0011 1100取反,得 1100 0011.換算成十進位制就是-61
transient關鍵字
我們都知道一個物件只要實現了Serilizable介面,這個物件就可以被序列化,java的這種序列化模式為開發者提供了很多便利,我們可以不必關係具體序列化的過程,只要這個類實現了Serilizable介面,這個類的所有屬性和方法都會自動序列化。
然而在實際開發過程中,我們常常會遇到這樣的問題,這個類的有些屬性需要序列化,而其他屬性不需要被序列化,打個比方,如果一個使用者有一些敏感資訊(如密碼,銀行卡號等),為了安全起見,不希望在網路操作(主要涉及到序列化操作,本地序列化快取也適用)中被傳輸,這些資訊對應的變數就可以加上transient關鍵字。換句話說,這個欄位的生命週期僅存於呼叫者的記憶體中而不會寫到磁盤裡持久化。
總之,java 的transient關鍵字為我們提供了便利,你只需要實現Serilizable介面,將不需要序列化的屬性前新增關鍵字transient,序列化物件的時候,這個屬性就不會序列化到指定的目的地中
1)一旦變數被transient修飾,變數將不再是物件持久化的一部分,該變數內容在序列化後無法獲得訪問。
2)transient關鍵字只能修飾變數,而不能修飾方法和類。注意,本地變數是不能被transient關鍵字修飾的。變數如果是使用者自定義類變數,則該類需要實現Serializable介面。
3)被transient關鍵字修飾的變數不再能被序列化,一個靜態變數不管是否被transient修飾,均不能被序列化。
關於size()方法和length屬性
在程式設計時經常會用到的兩個東西,老是記混,特地看了一下。
length是陣列的一個屬性,在獲取值的時候是按屬性的方法獲取。
而size()是連結串列的一個方法,用於獲取連結串列的長度
關於類Collections,Arrays,Objects
在jdk原始碼中提供了很多有用的工具類,它們的命名也有一定的規律。
Collections類提供了很多給容器使用的實用方法。
Arrays類提供了很多給給陣列容器有用的方法
Object類提供了一些給Object類方法中的實用方法
關於資源池
資源池不僅僅是在java當中存在的概念,在軟體世界裡也是廣泛應用的一個東西。
我們非常常見的資源池有:
- 資料庫連線池
- web容器中的執行緒池
- web容器中的request,response物件池
使用資源池的原因和好處大致是相似的。無外乎建立關閉維護每一個資源是比較耗費成本的。因此我們可以維護一定數量的資源,來尋求一個效率上的平衡。
- 資源池引入的目的:提高效能
- 資源池運作機制:由資源池管理器提供一定數目的目標資源,當有請求該資源時,資源池分配給一個,然後給該資源標識為忙, 標 示為忙的資源不能再被分配使用,
- 資源池常有的引數 初始資源的數目:資源池啟動時,一次建立的資源數目,資源池最少要保證在這個數目上. 最大資源的數目:當請求的資源超出這個數目,就等待。
內部類
本質上是java的一種"語法糖"。
現在又如下程式碼:
public class A {
static class B {
}
class C {
}
}
它在編譯之後會產生三個.class檔案,分別是:A.class,A$B.class,A$C.class.
注意B類和C類一個宣告成了static的類,另一個則沒有。他們的區別在於,不用static修飾的類在編譯生成class檔案之後,會生成一個預設的構造方法,這個構造方法裡面會持有外部類A類的引用。而這有可能帶來記憶體洩露問題。
而static修飾的類則不會在構造方法裡持有外部類的引用。
詳細資訊可以參考:https://blog.csdn.net/qq_22706515/article/details/51321718
SOA
SOA 即 service-oriented architecture,翻譯成中文就是面向服務的架構。是一種伺服器架構理念。
是一個元件模型,它將應用程式的不同功能單元(稱為服務)通過這些服務之間定義良好的介面和契約聯絡起來。
SOA具有以下五個特徵:
1、可重用
一個服務建立後能用於多個應用和業務流程。
2、鬆耦合
服務請求者到服務提供者的繫結與服務之間應該是鬆耦合的。因此,服務請求者不需要知道服務提供者實現的技術細節,例如程式語言、底層平臺等等。
3、明確定義的介面
服務互動必須是明確定義的。Web服務描述語言(Web Services Description Language,WSDL)是用於描述服務請求者所要求的繫結到服務提供者的細節。WSDL不包括服務實現的任何技術細節。服務請求者不知道也不關心服務究竟是由哪種程式設計語言編寫的。
4、無狀態的服務設計
服務應該是獨立的、自包含的請求,在實現時它不需要獲取從一個請求到另一個請求的資訊或狀態。服務不應該依賴於其他服務的上下文和狀態。當產生依賴時,它們可以定義成通用業務流程、函式和 資料模型。
5、基於開放標準
當前SOA的實現形式是Web服務,基於的是公開的W3C及其他公認標準.採用第一代Web服務定義的SOAP、WSDL和UDDI以及第二代Web服務定義的WS-*來實現SOA。