Java基礎複習,整理知識點
最近開始複習Java基礎,和Android,將知識點整理如下,另外開始嘗試使用MarkDown寫部落格,寫的有問題的地方還請各位包含。
1.Java關鍵字總結梳理
首先這裡總結一下在編寫類時常常會碰到的一些關鍵字:
private,public,protected,default
關鍵字 | 同一個包中的其他類 | 不同包中的其他類 | 子類 | 自身 |
---|---|---|---|---|
private | No | No | No | Yes |
protected | Yes | No | Yes | Yes |
public | Yes | Yes | Yes | Yes |
無修飾(default) | Yes | No | No | Yes |
注意:以上幾個修飾詞是和包有關的
static
static關鍵字修飾內容的幾個特點:
1. static修飾的變數和類檔案一同被載入到記憶體中
2. 被修飾的方法可以直接通過類名加點來引用,也就是說static修飾部分的引用是不需要將物件例項化的。
有關static一些注意事項:
- static方法只能訪問static變數
- static方法中不能使用this,super這樣的關鍵字,因為static優先於物件被載入到記憶體之中,static執行時物件可能還未被例項化。
- 內部類包含static修飾的屬性或方法時,內部類必須也被static修飾,其實理解起來也很簡答,應為static會優先被載入,如果內部類不被static修飾,那麼內部變數是不會被提前載入的,這時static關鍵字修飾就不起作用了。
final
- final是一個修飾詞,可修飾類,變數,函式
- final修飾的類不可被繼承
- final修飾的函式無法被複寫
- final修飾的變數只能賦值一次
abstract
- abstract同樣是一個修飾詞,能夠修飾方法和類
- abstract修飾的類無法被例項化,只能夠通過子類的繼承並實現內部所有的抽象函式才能被例項化。
- abstract修飾的函式只需要申明方法名,引數,不需要寫函式體。
- 抽象類中同樣可以定義非抽象的方法,同時抽象類也有建構函式,這個建構函式提供給子類例項化時使用。
- 抽象類中也可以沒有抽象的方法。
- abstract不可以和static,private,final公用,簡單理解一下,static修飾說明優先載入,而abstract未被實現,所以無法被優先載入。final修飾表名為最終狀態無法修改,而abstract修飾的需要子類去實現,必須可以修改。private表示私有化,自由自身能夠訪問到,而abstract需要子類訪問並實現函式體。
instanceof
用於判斷類是否實現了指定介面或實現了指定的類,舉個簡單的例子:
public class Test {
public static void main(String[] args) {
NullPointerException e = new NullPointerException();
System.out.println(e instanceof Exception);
}
}
輸出結果為true
2.物件導向
物件導向最為主要的兩個內容
- 過程,其實也就是函式
- 物件,則是對一些函式和屬性進行了封裝
所以,其實在物件導向的程式設計過程中,編寫類,也就是完成對函式和成員變數的封裝(當然,在編寫前需要對類進行設計)。
介面和介面的實現
- 介面有interface關鍵字定義,內部函式預設為抽象的,所以介面無法例項化.
- 一個類在實現了介面中所有的方法時才能被例項化,否則這個類還是一個抽象類,無法被例項化,實現某個介面使用關鍵字implements
- 一個類可以實現多個介面,而且介面之間也可以相互繼承,並且介面可以多繼承,一個簡單的例子:
public class Test {
interface interface1 {
void function1();
}
interface interface2 {
void function2();
}
interface interface3 extends interface1, interface2 {
}
class MyClass implements interface3 {
@Override
public void function1() {
// TODO Auto-generated method stub
}
@Override
public void function2() {
// TODO Auto-generated method stub
}
}
}
可以看到,當MyClass實現了interface3,並且interface3繼承了interface1和interface2時,MyClass需要實現interface1和interface2中的所有方法。
繼承
繼承當中子類與父類之間的一些關係:
- 成員變數:當子類中出現與父類相同的成員變數時,在子類中呼叫優先呼叫子類的該變數,如果想要呼叫父類中的該成員,則需要使用super關鍵字。
- 成員函式:當子類中出現與父類之中相同的方法時,子類的方法會將父類中的方法覆蓋。在外部呼叫時,會呼叫子類的方法。
- 建構函式:子類的建構函式中會預設呼叫super()意味著在構造子類之前需要先對其父類進行構造。
多型
舉一個簡單的多型例子:
父類定義
class Father
{
void sayHi()
{
System.out.println("father hello");
}
}
子類定義:
class Son extends Father
{
void sayHi()
{
System.out.println("son hello");
}
}
測試程式碼:
public static void main(String[] args) {
Father f = new Son();
f.sayHi();
}
輸出結果為“son hello”
可以看出,可以通過父類訪問到子類的方法,這樣為我們操作大量物件提供了方便,當我們需要操作大量不同物件時,我們只需要通過訪問他們的父類來操作他們共性的一部分即可。
當然以上只是簡單的多型的例子,動態在Java中有很多體現,介面的實現,繼承,複寫都體現著多型。
3.那些我們常常遇到的類
Exception
異常是程式執行期間發生的不正常的行為,Java中將異常進行了封裝,並能夠使用try catch語句對異常捕獲和處理。所有異常的父類都是Exception,這些異常類的共有特點就是能夠被丟擲。
這裡對比一下throws和throw的區別:
throws丟擲的是異常的類名,出現在方法頭部,throws只是存在丟擲異常的可能並且自身無法處理,需要交給呼叫者來處理。
private void main() {
try {
function();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void function() throws IOException {
Socket s = new Socket("", 11);
}
可以看到,我們通過throws將異常丟擲,並且在function被其他函式呼叫時,呼叫者任然需要對異常進行捕獲和處理,當然呼叫者也可以繼續講異常丟擲,等待其他的呼叫者對異常進行處理。
throw丟擲的是異常的物件,出現在函式體內部,throw一定會丟擲異常。看例子
public static void main(String[] args) {
String real_pass_word = "123456768";
String input_pass_word = "123456";
try {
if (!real_pass_word.equals(input_pass_word)) {
throw new IOException();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
可以看到需要對當密碼不相等時,我們使用throw丟擲了異常IOException,並且在外層通過try catch對異常進行了捕獲。
Thread
首選明確一下執行緒和程式的區別:
程式是程式在執行當中分配資源和管理資源的最小單位。程式之間通常不會共享資源,每個程式獨有系統分配的資源,程式中可以包含多個執行緒。
執行緒是程式中的一個程式執行控制單元,同時也是一條執行路徑,屬於同一個程式的執行緒之間共享程式內的資料,並且可以相互之間進行通訊。
建立一個新的執行緒有兩種辦法:
- 通過Thread或繼承至Thread的類建立執行緒物件
- 通過實現Runable介面,並將實現Runable介面的物件作為引數傳入Thread()構造方法中(這裡解釋一下Runable介面出現的原因,由於,應為Java中類是單繼承的,所以當一個類既想作為一個執行緒也有其他必須要繼承的類時,就可以通過實現Runable介面來將需要作為執行緒執行的部分放入run方法之中)
這裡有一個常見的面試題
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("哈哈哈");
}
}) {
public void run() {
System.out.println("呵呵呵");
};
}.start();
}
上面的程式碼執行結果輸出的“呵呵呵”,簡單的解釋一下,上述程式碼首先建立了一個Thread物件,此時run中輸出“哈哈哈”,然後我們通過Thread實現了一個匿名的內部類,這個類的run方法輸出“呵呵呵”,最後執行輸出的結果就是“呵呵呵”了。
多執行緒的好處當然是能夠更好的利用cpu,但是多執行緒同樣也帶來了一些問題,由於同一個程式內的多個執行緒共享著程式內的資源,當多個執行緒同時執行時就容易出現共享資源的搶奪,一個常見的情況是多個執行緒在共同訪問一個資料時,A執行緒正在運算元據,這個時候B執行緒進入並修改資料,這樣會導致產生錯誤的結果,為了解決執行緒訪問共享資源的問題,Java提供了關鍵字synchronized,以下提供一個synchronized關鍵的使用例子:
public class Test {
public static void main(String[] args) {
Example example = new Example();
Thread t1 = new Thread1(example);
Thread t2 = new Thread1(example);
t1.start();
t2.start();
}
}
class Example {
public synchronized void execute() {
for (int i = 0; i < 10; ++i) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello: " + i);
}
}
}
class Thread1 extends Thread {
private Example example;
public Thread1(Example example) {
this.example = example;
}
@Override
public void run() {
example.execute();
}
}
上面的程式碼對於excute方法使用了synchronized修飾,執行結果為先列印一次0-9再列印一次0-9,而去除synchronized關鍵字後,會同步列印,輸出結果為001122…..99。證明synchronized保證了函式被呼叫後執行完才能被其他呼叫者再次呼叫。
當然,處理synchronized方法以外,我們同樣可以使用synchronized塊來對小部分的程式碼進行同步,再來一個例子:
public class Test {
private static Test instance;
private Test() {
}
public static Test getInstance() {
if (instance == null) {
//鎖是類的位元組碼檔案,由於是靜態方法
synchronized (Test.class) {
if (instance == null) {
instance = new Test();
}
}
}
return instance;
}
}
上面的程式碼是一個典型的使用延遲載入的單例模式類,這種時候當多執行緒同事呼叫getInstance方法時,可能出現建立多個實體的情況,這樣顯然不符合單例模式的思想,所以我們需要在建立實體時加上程式碼同步。為了避免由於判斷加鎖和解鎖的過程帶來的低效,可以再同步部分再次新增判斷,避免沒有必要的同步。從Java 5 開始,推出了新的同步解決辦法Lock。
這部分的內容這裡有一個不錯的博文,推薦給大家,傳送門點這裡。
String
String類,作為Java中使用最為頻發的幾個類之一,有必要好好熟悉一下,String類其實很簡單,就是對字串的封裝,以及提供了很多方法方便我們操作字串。這裡整理了一些很好用的,但是可能被大家忽略的方法:
方法 | 作用 |
---|---|
charAt | 獲取指定位置的字元 |
indexOf | 順序獲取字元或字串的位置,沒有返回-1 |
lastIndexOf | 倒序獲取字元或字串的位置,沒有返回-1 |
subString | 獲取指定位置的子串 |
contain | 判斷字串是否包含指定字串 |
startWith | 判斷字串是否以指定字串開頭 |
endWith | 判斷字串是否以指定字串結尾 |
equalsIgnoreCase | 判斷字串是否相等,忽略大小寫 |
toLowerCase | 所有字母轉換為小寫 |
toUpperCase | 所有字母轉換為大寫 |
replace | 替換 |
trim | 去除字串首位空格 |
總結完String的一些方法,這裡再簡單的提一下StringBuilder和StringBuffer兩個類。String是賦值後無法修改的(我們可以看到所有的關於String的操作返回結果都是一個新的String物件而不是原物件),而StringBuilder和StringBuffer是可修改的,這兩個類作用類似都用於構建字串,不同在於:StringBuffer對於多執行緒是安全的,而StringBuilder對於多執行緒是不安全的。所以推薦的使用情況如下:
- 單執行緒操作時推薦使用StringBuilder,效率更高。
- 多執行緒時操作推薦使用StringBuffer,更加安全。
集合
Java中提供了功能強大的集合類,這裡我們對Java中的集合類進行整理:
- Iterator (訪問集合的迭代器介面)
- Collection(單列)
- List(有序,可儲存重複元素,元素有索引)
- Set(無序,不可儲存重複元素,元素都是唯一的)
- Map(雙列)
- Hashtable
- TreeMap
List介面下我們經常用到主要為以下幾個類:
- ArrayList: 底層陣列實現,查詢速度很快,執行緒不同步
- LinkedList:底層連結串列實現,增刪熟讀很快,執行緒不同步
- Vector:底層陣列實現,查詢增刪速度都很慢,執行緒同步
在通過Iterator對List介面物件進行迭代時,如果想要對集合物件進行操作,會出現ConcurrentModificationException的異常,錯誤原因是迭代過程中Iterator已經在操作集合物件了,這時我們再去操作集合物件會導致訪問衝突。解決辦法是使用iterator的子介面ListIterator,這個介面提供了對List集合物件的操作。
注意:由於在List集合中,判斷元素是否存在或是刪除元素都是通過元素的equals方法,所以在日常的開發過程中,通常需要自己重寫集合元素物件的equals方法,這樣能夠提高List集合的操作效率。
Set介面下我們經常用到主要為以下幾個類:
- HashSet:底層資料結構為Hash表,效率高,執行緒不同步
- LinkedHashSet:HashSet的子類,有序
- TreeSet:底層資料結構為二叉樹,可以對之中的資料進行指定順序的排序,執行緒不同步
簡單介紹一下Hash表是什麼:
1.對元素中特有資料進行Hash演算法,並得到元素的Hash值
2.Hash值就是這個元素在表中的位置
3.在儲存過程中,如果Hash值發生衝突,則需要進行衝突解決,最簡單的一個Hash衝突解決辦法為再次判斷元素是否相同,如果相同則不儲存,如果不同則儲存,在原元素的Hash值的基礎上加1。
(提供一個Hash衝突解決的博文連結)
4.儲存Hash值的結構稱之為Hash表
5.為了提高效率,應該儘量保證元素關鍵字的唯一性,這樣能夠提高Hash表的效率。
TreeSet中的元素需要是可比較的,為了保證元素可比較,需要元素實現Comparable介面,TreeSet中為保證元素的唯一,是通過Comparable介面的toCompare方法來實現的,當toCompare方法返回0時,表示兩個元素相同。
Map
Map介面與Collection有很大的區別,Map一次儲存一個鍵值對,並且需要保證Map中所有的健是唯一的。
迭代Map的方法:
- 通過Map.keySet()獲取健的Set,然後再遍歷時通過getKey方法迭代
- 通過Map.entrySet()方法獲取到鍵值對set,直接遍歷。
這裡總結一下集合的使用規律:
當需要儲存的是單個資料時考慮使用Collection,當需要儲存的內容是鍵值對形式的資料使用Map
- 需要保證內部元素唯一用Set,不要需要使用List
- 看到Array說明底層資料結構是陣列,證明查詢速度快
- 看到Linked說明底層資料結構是連結串列,增加刪除的速度開
- 看到Hash說明底層資料結構是Hash表,需要儘量保證內部元素的Hash值唯一,並且需要複寫元素的hasCode方法和equals方法。
- 看到Tree就說明底層的資料結構是二叉樹,需要相當排序,內部元素需要Comparable
泛型
泛型只是針對編譯時期,在執行時期並不存在泛型的概念,泛型只是為了將一些型別強制轉換的異常轉化為編譯錯誤。使用泛型時必須保證等式兩邊宣告的泛型是一樣的。
泛型的上限與下限:
- ?extends E 泛型指 接受E和E的所有子類
- ? super E 泛型指接受E和E的所有父類
IO Stream
首先明確一下字元流和位元組流的區別(這個問題今天早上把我一個電話面阿里的同學給難住了,有必要好好記一下)
位元組流:位元組流可以處理幾乎計算機當中的所有資料(凡是以InputStream和OutputStream結尾的都為位元組流)
- 字元流:字元流的出現是應為,各個國家的語言不通,字元也不通,所以當將各總編碼表和流封裝在一起,為了方便字元的操作,所以設計到字元操作的時候優先考慮字元流(凡是以Reader和Writer結尾的都是字元流)
開發的時候如何明確該使用什麼樣的流呢:
- 如果需要讀入資料使用InputStream和Reader,寫入資料使用OutputStream和Writer
- 如果需要處理純文字物件 使用Reader和Writer,否者使用InputStream和OutputStream
- 明確使用那個具體的流,通過明確具體操作的資料裝置:(磁碟)File,(記憶體)CharArray。。。
- 是否需要利用快取提高效率,如果需要可以使用Buffer對流進再一次的封裝。
Java部分到這裡基本整理完畢了,4天的時間,也算是查漏補缺,感覺的確再看一遍書又有了一些提高。這裡整理的是我不太熟悉的一些知識點,並不一定全面,明天開始整理有關Android的部分。加油~!~~~
相關文章
- Servlet基礎知識點整理Servlet
- MySQL 資料庫基礎知識點複習MySql資料庫
- 資料庫基礎知識整理與複習總結資料庫
- java基礎知識點Java
- 整理Java基礎知識--Calendar 類Java
- Java基礎知識整理之this用法Java
- Java基礎知識點梳理Java
- Java 基礎面試知識點Java面試
- Java基礎知識整理之註解Java
- JavaSE基礎學習知識整理大全Java
- 計算機基礎知識複習計算機
- 前端基礎知識複習之CSS前端CSS
- 前端基礎知識複習之html前端HTML
- Babel基礎知識整理Babel
- JS基礎知識整理JS
- 整理Java基礎知識--Number&Math類Java
- Java基礎知識整理之程式碼塊Java
- Java基礎知識點總結Java
- Java入門基礎知識點Java
- Java基礎知識整理之static修飾方法Java
- mysql資料庫學習基礎知識整理MySql資料庫
- Python基礎知識整理Python
- Web前端基礎知識整理Web前端
- C++基礎知識整理C++
- Java基礎面試知識點總結Java面試
- java面試重要知識點複習大綱Java面試
- Java EE 基礎知識學習(六)Java
- Java基礎知識Java
- 生信基礎知識複習之測序
- Linux基礎知識複習之命令篇Linux
- 刷演算法中途複習基礎知識演算法
- Java基礎知識整理之static修飾屬性Java
- 零基礎學習Java,全方位知識點總結!Java
- 初識Java Java基礎知識Java
- Java 基礎知識點(必知必會其一)Java
- Java個人知識點總結(基礎篇)Java
- OC UIApplication基礎知識整理UIAPP
- JavaWeb基礎知識點JavaWeb