之前學習Java基礎的時候做的一些筆記,稍微整理了一下,也方便以後看。不過這裡都是一些較為基礎的Java知識,後期有時間,會針對裡面的泛型,多線程,算法,nio 等模塊進行更深入的解析。
如果有寫錯的地方,還望指出,一定及時更正。
基礎
1 switch支持的類型:byte, short, int, char, enum,
注意:不支持long,double,JDK7之後,開始支持String。
//簡單示例
public class MyDemo {
public static void main(String… args) {
Demo demo = Demo.A;
switch (demo) {
case A:
break;
case B:
break;
}
}
enum Demo {
A,
B,
C
}
}
2 if和switch的區別:
if :1.對具體的值進行判斷 2.對區間判斷 3.對運算結果是boolean類型的表達式進行判斷
switch :1.對具體的值進行判斷;2.值的個數通常是固定的。
對於幾個固定值的判斷,建議使用switch語句,因為switch語句會將具體的答案加載進內存,相對高效一點。
重載和重寫的區別
重載:允許存在一個以上的同名函數,只要它們的參數類型不同即可。
重寫:當子類繼承父類,沿襲了父類的功能到子類中,子類雖具備該功能,但功能內容不一致,這是使用覆蓋特性,保留父類的功能定義,並重寫功能內容。
單例模式
餓漢式
private static Single s = new Single ( ) ;
private Single ( ) { }
public static Single getInstance ()
{
return s ;
}
懶漢式
class Single {
public static Single getInstance (){
if ( s== null ){
synchronized (Single.class){//鎖不讀可以提高效率
if ( s== null ){
s = new Single () ;
}
}
return s ;
}
}
特殊關鍵字:final
可以修飾類、函數、變量;
被final修飾的類不可以被繼承。為了避免被繼承,被子類複寫。final class Demo { }
被final修飾的方法不可以被複寫。final void show () { }
被final 修飾的變量是一個常量,只能賦值一次。
內部類定義在類中的局部位置上時,只能訪問該局部被final修飾的局部變量。
異常:(關於問題1,謝謝ylt提醒)
try{}catch(){}finally{}
1.在catch中return(),finally{}會不會執行?
答:會,會在return之後執行。
2.finally()在什麼情況下不會執行
答:只有一種情況不會執行,當執行到System.exit(0)時,finally不會執行。
public class Test {
public static void main(String[] args) {
System.out.println(“haha:” + haha(true));
}
private static boolean haha(boolean isTrue) {
try {
int i = 1 / 0;
return isTrue ? System.out.printf(“return try !null “, “test”) != null : System.out.printf(“return try null “, “test”) == null;
} catch (Exception e) {
System.out.println(“catch”);
return isTrue ? System.out.printf(“return catch !null “, “test”) != null : System.out.printf(“return catch null “, “test”) == null;
} finally {
System.out.println(“”);
System.out.println(“finally”);
}
}
}
//打印結果:
catch
return catch !null
finally
haha:true
常見Runtime異常:
ArithmeticException, ClassCastException, IllegalArgumentException,
IndexOutOfBoundsException, NullPointerException,
訪問權限
權限.png
Java靜態代碼塊、構造函數、構造代碼塊
先看下面一段代碼,運行Test,會打印什麼?
package test;
public class Test {
public static void main(String… args) {
TestA a;
a = new TestA();
a = new TestA();
TestA aa = new TestA();
}
}
class TestA {
{
System.out.println(“TestA code create”);
}
private TestB b = new TestB(); private static TestC c = new TestC(); public TestA() { System.out.println("TestA create"); } static { System.out.println("TestA static create"); }
}
class TestB {
public TestB() {
System.out.println(“TestB create”);
}
}
class TestC {
public TestC() {
System.out.println(“TestC create”);
}
}
打印結果:
TestC create
TestA static create
TestA code create
TestB create
TestA create
TestA code create
TestB create
TestA create
TestA code create
TestB create
TestA create
static特點:
隨著類的加載而加載(隨著類的消失而消失,生命週期最長)
優先於對象存在
被所有對象所共享
可以直接被類所調用
static是一個修飾符,用於修飾成員
構造代碼塊
作用:給對象進行初始化,對象一建立就運行,而且優先於構造函數執行。
和構造函數的區別:
構造代碼塊是給所有對象進行統一初始化;而構造函數是給對應的對象初始化
構造代碼塊中定義的是不同對象共性的初始化內容
靜態代碼塊
static
{
靜態代碼塊中的執行語句;
}
特點:隨著類的加載而執行,只執行一次(再new一個對象也不會執行,類只加載一次),
如果定義在有主函數的類中,則優先於主函數執行。用於給類進行初始化。
有些類不用創建對象,無法用構造函數初始化,就通過靜態代碼塊初始化。
執行順序:靜態代碼塊先執行,如果有對象,構造代碼塊先執行,然後是構造函數。
如果沒有對象,則構造代碼塊和構造函數都不會執行。
Java-封裝、繼承、多態
抽象類的特點:
抽象方法一定在抽象類中。
抽象方法和抽象類都必須被abstract關鍵字修飾。
抽象類不可以用new創建對象,因為調用抽象方法沒有意義。
抽象類中的抽象方法要被使用,必須由子類複寫所有的抽象方法後,建立子類對象調用。如果子類只覆蓋了部分抽象方法,那麼該子類還是一個抽象類。強迫子類複寫,強迫子類做一些事。
抽象類中可以不定義抽象方法,如果不定義抽象方法,那麼抽象類的功能就是為了不讓該類建立對象。
抽象關鍵字不可以和哪些關鍵字共存?
答:(1)private不能:抽象方法就是給子類覆蓋的,私有了就不能覆蓋了。
(2)static不能:static可以直接用類名調用,而調用抽象方法沒有意義。
(3)final 不能:final修飾的方法不可以被複寫,修飾的類不可以被繼承。與abstract衝突。
接口的特點
● 接口是對外暴露的規則。
● 接口是程序的功能擴展。
● 接口可以多實現。
● 類與接口直接是實現關係,而且類可以繼承一個類的同時實現多個接口。
● 接口與接口之間可以有繼承關係,可以多繼承。
因為接口沒有方法體,不會存在兩個父類出現同一個方法但是方法體不同的情況,
不會引起衝突,如下:
public class Test implements d{
public static void main(String… args) {
}
@Override
public void as() {
}
}
interface d extends e,f {
}
interface f{
void as();
}
interface e{
void as();
}
接口和抽象類的異同點:
相同點:都是不斷向上抽取而來的。不可以被實例化
不同點:
抽象類需要被繼承,而且只能單繼承;接口需要被實現,而且可以多實現
抽象類中可以定義抽象方法和非抽象方法,子類繼承後,可以直接使用非抽象方法;
接口只能定義抽象方法,必須有子類實現。
抽象類的繼承,是is a關係,在定義該體系的基本共性內容;
接口的實現是like a 關係,在定義體系額外功能。
繼承
子類的實例化過程:
結論:子類的所有的構造函數,默認都會訪問父類中空參數構造函數,因為子類中每一個構造函數內的第一行都有一句隱式的super() ;
當父類中沒有空參數的構造函數時,子類必須手動通過super或者this語句形式來指定要訪問的構造函數。
當然:子類的構造函數第一行也可以手動指定this語句來訪問本類中的構造函數,
子類中至少會有一個構造函數會訪問到父類中的構造函數。
對象的初始化過程,見下圖:
對象初始化過程.png
打印結果:
打印結果.png
線程
關於線程這塊,後期有時間會寫一個完整的深入的文章,這裡寫的都是比較簡單基礎的線程的一些知識。
創建線程的兩種方式:
1 繼承Thread類。
①.定義類繼承Thread;
②.複寫父類中的方法;目的:將自定義代碼存儲在run方法中,讓線程運行。
③.調用線程的start方法,該方法有兩個作用:啟動線程,調用run方法
2 實現Runnable接口
1. 定義類實現Runnable接口。
2. 覆蓋Runnable接口中的run方法。
3. 通過Thread類建立線程對象。
4. 將Runnable接口的子類對象作為實際參數傳遞給Thread類的構造函數。
5. 調用Thread類的start方法開啟線程並調用Runnable接口子類的run方法。
實現方式和繼承方式有什麼區別?
實現方式相比繼承方式的好處:
避免了單繼承的侷限性(單繼承只能繼承一個父類)。在定義線程時,建議使用實現方式。
2.存放代碼的位置不一樣:
繼承Thread:線程代碼存放Thread子類的run方法中
實現Runnable,線程代碼存在接口的子類的run方法。
實現Runnable接口的好處:
1,將線程的任務從線程的子類中分離出來,進行了單獨的封裝。
按照面向對象的思想將任務的封裝成對象。
2,避免了java單繼承的侷限性。
同步的兩種表現形式:
1 同步代碼塊
synchronized(對象){
需要被同步的代碼;
}
2 同步函數。
將synchronized關鍵字作為修飾符放在函數上。
public synchronized void add()
同步函數用的是哪一個鎖:函數需要被對象調用,那麼該函數都有一個所屬對象引用,就是this,所以同步函數使用的鎖是this(對象)
JDK1.5中提供了多線程升級解決方案,將同步synchronized替換成實現Lock操作,將Object中的wait,notify,notifyAll,替換成了Condition對象的await(),signal(),signalAll(),該對象可以通過Lock鎖進行獲取。
停止線程
原理:run方法結束
1 setDeamon() 守護線程:setDaemon(ture) ;
也稱後臺線程,當前臺線程執行時後臺線程也在執行,但是當前臺線程全部執行完關閉時,
後臺線程也會跟著自動關閉,jvm退出。
!!該方法必須在啟動線程前調用。
2 join()等待該線程終止:一般用於臨時加入線程。
當A線程執行到了B線程的.join()方法時,A就會等待,等B線程都執行完,A才會執行
3 yield()方法:釋放執行權,讓其他線程運行。
暫停當前正在執行的線程對象,並執行其他線程。
一個死鎖的demo
class Test implements Runnable {
private boolean flag;
Test(boolean flag) {
this.flag = flag;
}
public void run() {
if (flag) { while (true) synchronized (MyLock.locka) { System.out.println(Thread.currentThread().getName() + "..if locka...."); synchronized (MyLock.lockb) { System.out.println(Thread.currentThread().getName() + "..if lockb...."); } } } else { while (true) synchronized (MyLock.lockb) { System.out.println(Thread.currentThread().getName() + "..else lockb...."); synchronized (MyLock.locka) { System.out.println(Thread.currentThread().getName() + "..else locka...."); } } }
}
}
class MyLock {
public static final Object locka = new Object();
public static final Object lockb = new Object();
}
class DeadLockTest {
public static void main(String[] args) {
Test a = new Test(true);
Test b = new Test(false);
Thread t1 = new Thread(a);
Thread t2 = new Thread(b);
t1.start();
t2.start();
}
}
wait和sleep的區別
wait 可以指定時間也可以不指定。sleep必須指定時間。
在同步中,對CPU的執行權和鎖的處理不同:
wait:釋放執行權,釋放鎖
sleep:釋放執行權,不釋放鎖
StringBuffer和StringBuilder的區別
使用intrrupt()方法。該方法是結束線程的凍結狀態,使線程回到運行狀態中來。
當線程處於凍結狀態,就不會結束讀取到標記,那麼線程就不會結束。
當沒有指定的方式讓凍結的線程恢復到運行狀態時,這時需要對凍結進行清除。
強制讓線程恢復到運行狀態中來,這樣就可以操作標記讓線程結束。
定義循環結束標記。線程運行代碼一般都是循環,只要控制了循環即可。
線程常見方法
StringBuffer是線程同步(安全)。如果是單線程,效率就比較低
StringBuilder是線程不同步。
集合
Java集合關係圖.png
Collection:單列集合
List 和 set
List:元素是有序的,元素可以重複,因為該集合體繫有索引
Set:元素是無序的,元素不可以重複(存入和取出的順序不一定一致)。
List特有方法:凡是可以操作角標的方法都是該體系特有的方法
List中常見的三個子類
ArrayList :底層的數據使用的是數組結構。
特點:查詢速度很快,但是增刪稍慢。線程不同步,效率高 。
可變長度數組,默認容量為10的空列表,如果超過了,則50%的增加
LinkedList :底層的數據使用的是鏈表數據結構。
特點:增刪數度很快,但是查詢稍慢。
Vector:底層使用的是數組結構。枚舉是Vector特有的取出方式
是同步的,效率較低,被ArrayList替代。最早出現的。
默認容量為10的空列表,如果超過了,則100%的增加.
LinkedList
JDK1.6版本出現的:pollFirst(),pollLast(),peekFirst() ,peekLast(),offerFirst(),offerLast()
(如果鏈表為空,返回null )。
分別替代了remove 和 get 和add (如果鏈表為空,則拋出異常)。
set常見子類
HashSet:底層數據結構是哈希表。
HashSet是如何保證元素的唯一性的:
是通過元素的兩個方法,hashCode和equals來完成,如果元素的hashCode值相同,
才會判斷equals是否為true,如果元素的hashCode值不同,不會調用equals 。
開發時描述事物,需要往集合裡面存時,一般都要複寫hashCode和equals。
TreeSet底層的數據結構:二叉樹
保證數據元素唯一性的依據compareTo方法return 0,為0則表示是相同元素 ;
排序的兩種方式:
TreeSet排序的第一種方式:
讓元素自身具備比較性。元素需要實現Comparable接口,覆蓋compareTo方法。這種方式也稱為元素的自然順序,或者叫做默認順序。
TreeSet的第二種排序方式:
當元素自身不具備比較性時,或具備的比較性不是所需要的,這是就需要讓集合自身具備比較性。
定義一個比較器,將比較器對象作為參數傳遞給TreeSet集合的構造函數。
定義一個類,實現Comparator接口,覆蓋compare方法
當兩種排序都存在時,以比較器為主。
泛型
泛型技術是給編譯器使用的技術,用於編譯時期。確保了類型的安全。
運行時,會將泛型去掉,生成的class文件中是不帶泛型的,這個稱為泛型的擦除。
為什麼擦除呢?因為為了兼容運行的類加載器。
泛型的補償:在類加載器原有基礎上,編寫一個補償程序。在運行時,通過反射,
獲取元素的類型進行轉換動作。不用使用者在強制轉換了。
Map:雙列集合
常見子類
Hashtable:底層是哈希表數據結構,不可以存入null鍵null值,該集合是線程同步的。jdk1.0 ,效率低 。
HashMap:底層是哈希表數據結構,並允許使用null鍵null值,該集合不是同步的,jdk1.2 ,效率高。
TreeMap :底層是二叉樹數據結構,線程不同步,可以給map集合中的鍵進行排序 。
Map 和 Set很像 :其實,Set底層使用了Map集合 。
map集合的兩種取出方式:
1.Set KeySet:
將Map中所有的Key存到了Set集合中,因為Set集合具備迭代器。
所有可以迭代方式取出所有的鍵,再根據get方法,獲取每一個鍵對應的值
Map集合的取出原理:將Map集合轉成Set集合,再通過迭代器取出
2.Set
大家可以點擊加入群:478052716【JAVA高級程序員】裡面有Java高級大牛直播講解知識點 走的就是高端路線 (如果你想跳槽換工作 但是技術又不夠 或者工作上遇到了 瓶頸 我這裡有一個JAVA的免費直播課程 講的是高端的知識點基礎不好的誤入喲 只要你有1-5年的開發經驗可以加群找我要課堂鏈接 注意:是免費的 沒有開發經驗誤入哦)