我的博客
我的博客:面試總結(jié)-Java基礎(chǔ)(一)
之前學習Java基礎(chǔ)的時候做的一些筆記,稍微整理了一下,也方便以后看。不過這里都是一些較為基礎(chǔ)的Java知識,后期有時間,會針對里面的泛型,多線程,算法,nio 等模塊進行更深入的解析。
如果有寫錯的地方,還望指出,一定及時更正。
基礎(chǔ)
-
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的區(qū)別:
if :1.對具體的值進行判斷 2.對區(qū)間判斷 3.對運算結(jié)果是boolean類型的表達式進行判斷
switch :1.對具體的值進行判斷;2.值的個數(shù)通常是固定的。
對于幾個固定值的判斷,建議使用switch語句,因為switch語句會將具體的答案加載進內(nèi)存,相對高效一點。
-
重載和重寫的區(qū)別
- 重載:允許存在一個以上的同名函數(shù),只要它們的參數(shù)類型不同即可。
- 重寫:當子類繼承父類,沿襲了父類的功能到子類中,子類雖具備該功能,但功能內(nèi)容不一致,這是使用覆蓋特性,保留父類的功能定義,并重寫功能內(nèi)容。
-
單例模式
-
餓漢式
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 ; } }
-
-
特殊關(guān)鍵字:final
1. 可以修飾類、函數(shù)、變量; 2. 被final修飾的類不可以被繼承。為了避免被繼承,被子類復寫。final class Demo { } 3. 被final修飾的方法不可以被復寫。final void show () { } 4. 被final 修飾的變量是一個常量,只能賦值一次。 5. 內(nèi)部類定義在類中的局部位置上時,只能訪問該局部被final修飾的局部變量。 -
異常:(關(guān)于問題1,謝謝ylt提醒)
try{}catch(){}finally{} 1.在catch中return(),finally{}會不會執(zhí)行? 答:會,會在return之后執(zhí)行。 2.finally()在什么情況下不會執(zhí)行 答:只有一種情況不會執(zhí)行,當執(zhí)行到System.exit(0)時,finally不會執(zhí)行。
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");
}
}
}
```java
//打印結(jié)果:
catch
return catch !null
finally
haha:true
-
常見Runtime異常:
ArithmeticException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException, NullPointerException, 訪問權(quán)限

Java靜態(tài)代碼塊、構(gòu)造函數(shù)、構(gòu)造代碼塊
-
先看下面一段代碼,運行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"); } }
打印結(jié)果:
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特點:
1. 隨著類的加載而加載(隨著類的消失而消失,生命周期最長) 2. 優(yōu)先于對象存在 3. 被所有對象所共享 4. 可以直接被類所調(diào)用 5. static是一個修飾符,用于修飾成員 -
構(gòu)造代碼塊
作用:給對象進行初始化,對象一建立就運行,而且優(yōu)先于構(gòu)造函數(shù)執(zhí)行。 和構(gòu)造函數(shù)的區(qū)別: 構(gòu)造代碼塊是給所有對象進行統(tǒng)一初始化;而構(gòu)造函數(shù)是給對應(yīng)的對象初始化 構(gòu)造代碼塊中定義的是不同對象共性的初始化內(nèi)容 -
靜態(tài)代碼塊
static { 靜態(tài)代碼塊中的執(zhí)行語句; } 特點:隨著類的加載而執(zhí)行,只執(zhí)行一次(再new一個對象也不會執(zhí)行,類只加載一次), 如果定義在有主函數(shù)的類中,則優(yōu)先于主函數(shù)執(zhí)行。用于給類進行初始化。 有些類不用創(chuàng)建對象,無法用構(gòu)造函數(shù)初始化,就通過靜態(tài)代碼塊初始化。 執(zhí)行順序:靜態(tài)代碼塊先執(zhí)行,如果有對象,構(gòu)造代碼塊先執(zhí)行,然后是構(gòu)造函數(shù)。 如果沒有對象,則構(gòu)造代碼塊和構(gòu)造函數(shù)都不會執(zhí)行。
Java-封裝、繼承、多態(tài)
-
抽象類的特點:
1. 抽象方法一定在抽象類中。 2. 抽象方法和抽象類都必須被abstract關(guān)鍵字修飾。 3. 抽象類不可以用new創(chuàng)建對象,因為調(diào)用抽象方法沒有意義。 4. 抽象類中的抽象方法要被使用,必須由子類復寫所有的抽象方法后,建立子類對象調(diào)用。如果子類只覆蓋了部分抽象方法,那么該子類還是一個抽象類。強迫子類復寫,強迫子類做一些事。 5. 抽象類中可以不定義抽象方法,如果不定義抽象方法,那么抽象類的功能就是為了不讓該類建立對象。 -
抽象關(guān)鍵字不可以和哪些關(guān)鍵字共存?
答:(1)private不能:抽象方法就是給子類覆蓋的,私有了就不能覆蓋了。 (2)static不能:static可以直接用類名調(diào)用,而調(diào)用抽象方法沒有意義。 (3)final 不能:final修飾的方法不可以被復寫,修飾的類不可以被繼承。與abstract沖突。 -
接口的特點
● 接口是對外暴露的規(guī)則。 ● 接口是程序的功能擴展。 ● 接口可以多實現(xiàn)。 ● 類與接口直接是實現(xiàn)關(guān)系,而且類可以繼承一個類的同時實現(xiàn)多個接口。 ● 接口與接口之間可以有繼承關(guān)系,可以多繼承。 因為接口沒有方法體,不會存在兩個父類出現(xiàn)同一個方法但是方法體不同的情況, 不會引起沖突,如下: 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(); } -
接口和抽象類的異同點:
相同點:都是不斷向上抽取而來的。不可以被實例化 不同點: 1. 抽象類需要被繼承,而且只能單繼承;接口需要被實現(xiàn),而且可以多實現(xiàn) 2. 抽象類中可以定義抽象方法和非抽象方法,子類繼承后,可以直接使用非抽象方法; 接口只能定義抽象方法,必須有子類實現(xiàn)。 3. 抽象類的繼承,是is a關(guān)系,在定義該體系的基本共性內(nèi)容; 接口的實現(xiàn)是like a 關(guān)系,在定義體系額外功能。 -
繼承
子類的實例化過程: 結(jié)論:子類的所有的構(gòu)造函數(shù),默認都會訪問父類中空參數(shù)構(gòu)造函數(shù),因為子類中每一個構(gòu)造函數(shù)內(nèi)的第一行都有一句隱式的super() ; 當父類中沒有空參數(shù)的構(gòu)造函數(shù)時,子類必須手動通過super或者this語句形式來指定要訪問的構(gòu)造函數(shù)。 當然:子類的構(gòu)造函數(shù)第一行也可以手動指定this語句來訪問本類中的構(gòu)造函數(shù), 子類中至少會有一個構(gòu)造函數(shù)會訪問到父類中的構(gòu)造函數(shù)。 對象的初始化過程,見下圖:

打印結(jié)果:

線程
關(guān)于線程這塊,后期有時間會寫一個完整的深入的文章,這里寫的都是比較簡單基礎(chǔ)的線程的一些知識。
創(chuàng)建線程的兩種方式:
1 繼承Thread類。
①.定義類繼承Thread;
②.復寫父類中的方法;目的:將自定義代碼存儲在run方法中,讓線程運行。
③.調(diào)用線程的start方法,該方法有兩個作用:啟動線程,調(diào)用run方法
2 實現(xiàn)Runnable接口
1. 定義類實現(xiàn)Runnable接口。
2. 覆蓋Runnable接口中的run方法。
3. 通過Thread類建立線程對象。
4. 將Runnable接口的子類對象作為實際參數(shù)傳遞給Thread類的構(gòu)造函數(shù)。
5. 調(diào)用Thread類的start方法開啟線程并調(diào)用Runnable接口子類的run方法。
-
實現(xiàn)方式和繼承方式有什么區(qū)別?
1. 實現(xiàn)方式相比繼承方式的好處: 避免了單繼承的局限性(單繼承只能繼承一個父類)。在定義線程時,建議使用實現(xiàn)方式。 2.存放代碼的位置不一樣: 繼承Thread:線程代碼存放Thread子類的run方法中 實現(xiàn)Runnable,線程代碼存在接口的子類的run方法。 -
實現(xiàn)Runnable接口的好處:
1,將線程的任務(wù)從線程的子類中分離出來,進行了單獨的封裝。 按照面向?qū)ο蟮乃枷雽⑷蝿?wù)的封裝成對象。 2,避免了java單繼承的局限性。 -
同步的兩種表現(xiàn)形式:
-
1 同步代碼塊
synchronized(對象){
需要被同步的代碼;
} -
2 同步函數(shù)。
將synchronized關(guān)鍵字作為修飾符放在函數(shù)上。
public synchronized void add()
-
* 同步函數(shù)用的是哪一個鎖:函數(shù)需要被對象調(diào)用,那么該函數(shù)都有一個所屬對象引用,就是this,所以同步函數(shù)使用的鎖是this(對象)
* JDK1.5中提供了多線程升級解決方案,將同步synchronized替換成實現(xiàn)Lock操作,將Object中的wait,notify,notifyAll,替換成了Condition對象的await(),signal(),signalAll(),該對象可以通過Lock鎖進行獲取。
-
停止線程
原理:run方法結(jié)束 1. 使用intrrupt()方法。該方法是結(jié)束線程的凍結(jié)狀態(tài),使線程回到運行狀態(tài)中來。 當線程處于凍結(jié)狀態(tài),就不會結(jié)束讀取到標記,那么線程就不會結(jié)束。 當沒有指定的方式讓凍結(jié)的線程恢復到運行狀態(tài)時,這時需要對凍結(jié)進行清除。 強制讓線程恢復到運行狀態(tài)中來,這樣就可以操作標記讓線程結(jié)束。 2. 定義循環(huán)結(jié)束標記。線程運行代碼一般都是循環(huán),只要控制了循環(huán)即可。 -
線程常見方法
1 setDeamon() 守護線程:setDaemon(ture) ; 也稱后臺線程,當前臺線程執(zhí)行時后臺線程也在執(zhí)行,但是當前臺線程全部執(zhí)行完關(guān)閉時, 后臺線程也會跟著自動關(guān)閉,jvm退出。 ??!該方法必須在啟動線程前調(diào)用。 2 join()等待該線程終止:一般用于臨時加入線程。 當A線程執(zhí)行到了B線程的.join()方法時,A就會等待,等B線程都執(zhí)行完,A才會執(zhí)行 3 yield()方法:釋放執(zhí)行權(quán),讓其他線程運行。 暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程。 -
一個死鎖的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的區(qū)別
1. wait 可以指定時間也可以不指定。sleep必須指定時間。 2. 在同步中,對CPU的執(zhí)行權(quán)和鎖的處理不同: wait:釋放執(zhí)行權(quán),釋放鎖 sleep:釋放執(zhí)行權(quán),不釋放鎖 -
StringBuffer和StringBuilder的區(qū)別
StringBuffer是線程同步(安全)。如果是單線程,效率就比較低
StringBuilder是線程不同步。
集合

Collection:單列集合
-
List 和 set
List:元素是有序的,元素可以重復,因為該集合體系有索引 Set:元素是無序的,元素不可以重復(存入和取出的順序不一定一致)。 List特有方法:凡是可以操作角標的方法都是該體系特有的方法 -
List中常見的三個子類
1. ArrayList :底層的數(shù)據(jù)使用的是數(shù)組結(jié)構(gòu)。 特點:查詢速度很快,但是增刪稍慢。線程不同步,效率高 。 可變長度數(shù)組,默認容量為10的空列表,如果超過了,則50%的增加 2. LinkedList :底層的數(shù)據(jù)使用的是鏈表數(shù)據(jù)結(jié)構(gòu)。 特點:增刪數(shù)度很快,但是查詢稍慢。 3. Vector:底層使用的是數(shù)組結(jié)構(gòu)。枚舉是Vector特有的取出方式 是同步的,效率較低,被ArrayList替代。最早出現(xiàn)的。 默認容量為10的空列表,如果超過了,則100%的增加. -
LinkedList
JDK1.6版本出現(xiàn)的:pollFirst(),pollLast(),peekFirst() ,peekLast(),offerFirst(),offerLast() (如果鏈表為空,返回null )。 分別替代了remove 和 get 和add (如果鏈表為空,則拋出異常)。 -
set常見子類
1. HashSet:底層數(shù)據(jù)結(jié)構(gòu)是哈希表。 HashSet是如何保證元素的唯一性的: 是通過元素的兩個方法,hashCode和equals來完成,如果元素的hashCode值相同, 才會判斷equals是否為true,如果元素的hashCode值不同,不會調(diào)用equals 。 開發(fā)時描述事物,需要往集合里面存時,一般都要復寫hashCode和equals。 -
TreeSet底層的數(shù)據(jù)結(jié)構(gòu):二叉樹
保證數(shù)據(jù)元素唯一性的依據(jù)compareTo方法return 0,為0則表示是相同元素 ; 排序的兩種方式: TreeSet排序的第一種方式: 讓元素自身具備比較性。元素需要實現(xiàn)Comparable接口,覆蓋compareTo方法。這種方式也稱為元素的自然順序,或者叫做默認順序。 TreeSet的第二種排序方式: 當元素自身不具備比較性時,或具備的比較性不是所需要的,這是就需要讓集合自身具備比較性。 定義一個比較器,將比較器對象作為參數(shù)傳遞給TreeSet集合的構(gòu)造函數(shù)。 定義一個類,實現(xiàn)Comparator接口,覆蓋compare方法 當兩種排序都存在時,以比較器為主。 -
泛型
泛型技術(shù)是給編譯器使用的技術(shù),用于編譯時期。確保了類型的安全。 運行時,會將泛型去掉,生成的class文件中是不帶泛型的,這個稱為泛型的擦除。 為什么擦除呢?因為為了兼容運行的類加載器。 泛型的補償:在類加載器原有基礎(chǔ)上,編寫一個補償程序。在運行時,通過反射, 獲取元素的類型進行轉(zhuǎn)換動作。不用使用者在強制轉(zhuǎn)換了。
Map:雙列集合
-
常見子類
Hashtable:底層是哈希表數(shù)據(jù)結(jié)構(gòu),不可以存入null鍵null值,該集合是線程同步的。jdk1.0 ,效率低 。 HashMap:底層是哈希表數(shù)據(jù)結(jié)構(gòu),并允許使用null鍵null值,該集合不是同步的,jdk1.2 ,效率高。 TreeMap :底層是二叉樹數(shù)據(jù)結(jié)構(gòu),線程不同步,可以給map集合中的鍵進行排序 。 Map 和 Set很像 :其實,Set底層使用了Map集合 。 -
map集合的兩種取出方式:
1.Set<K> KeySet: 將Map中所有的Key存到了Set集合中,因為Set集合具備迭代器。 所有可以迭代方式取出所有的鍵,再根據(jù)get方法,獲取每一個鍵對應(yīng)的值 Map集合的取出原理:將Map集合轉(zhuǎn)成Set集合,再通過迭代器取出 2.Set<Map.Entry<K,V>> entrySet:將Map集合中的映射關(guān)系存入到了Set集合中,而這個關(guān)系的數(shù)據(jù)類型就是:Map.Entry。 Map.Entry :其實Entry也是一個接口,它是Map接口中的一個內(nèi)部接口。 先有Map,才有映射關(guān)系,所有Entry類定義在Map內(nèi)部 -
Math類:
double d = Math.ceil(12.56);// 13.0 。ceil返回大于指定整數(shù)的最小整數(shù) double d1 =Math.floor(12.34);//12.0 。floor返回小于指定數(shù)據(jù)的最大整數(shù) long l = Math.round(12.64);//四舍五入 double d2 = Math.pow(2,3);//冪運算 :2^3 = 8
io
字節(jié)流:InputStream(讀) OutputStream(寫)
-
RandomAccessFile(斷點下載會用到的類):
隨機訪問文件,自身具備讀寫的方法。
通過skipBytes(int x),seek(int x)來達到隨機訪問。seek(int x):調(diào)整對象中指針,指針跳轉(zhuǎn),可以實現(xiàn)對數(shù)據(jù)指定位置的讀取和寫入。
-
IO流體系:
字符流: Reader |--BufferedReader: |--LineNumberReader |--CharArrayReader |--StringReader |--InputStreamReaer |--FileReader Writer |--BufferedWriter |--CharArrayWriter |--StringWriter |--OutputStreamWriter |--FileWriter |--PrintWriter 字節(jié)流: InputStream |--FileInputStream: |--FilterInputStream |--BufferedInputStream |--DataInputStream |--ByteArrayInputStream |--ObjectInputStream |--SequenceInputStream |--PipedInputStream OutputStream |--FileOutputStream |--FilterOutputStream |--BufferedOutputStream |--DataOutputStream |--ByteArrayOutputStream |--ObjectOutputStream |--PipedOutputStream |--PrintStream -
示例:讀出C盤下txt文件
public static void listDemo_2() { File dir = new File("c:\\"); String[] names = dir.list(new SuffixFilter(".txt")); for(String name : names){ System.out.println(name); } } public class SuffixFilter implements FilenameFilter { private String suffix ; public SuffixFilter(String suffix) { super(); this.suffix = suffix; } @Override public boolean accept(File dir, String name) { return name.endsWith(suffix); } } -
示例:深度遞歸,讀出制定目錄下的所有文件和文件夾,包括子目錄。
public class FileTest { public static void main(String[] args) { File dir = new File("D:\\me\\mime\\RuntimePermissions"); listAll(dir,0); } /** * * @param dir * @param spaceLevel 這個是為了打印結(jié)果好看,與空格有關(guān)的參數(shù) */ public static void listAll(File dir,int spaceLevel) { System.out.println(getSpace(spaceLevel)+dir.getName()); //獲取指定目錄下當前的所有文件夾或者文件對象 spaceLevel++; File[] files = dir.listFiles(); for(int x=0; x<files.length; x++){ if(files[x].isDirectory()){ listAll(files[x],spaceLevel); } else System.out.println(getSpace(spaceLevel)+files[x].getName()); } } private static String getSpace(int spaceLevel) { StringBuilder builder = new StringBuilder(); builder.append("|--"); for(int x=0; x<spaceLevel; x++){ builder.insert(0,"| "); } return builder.toString(); } }