String類是final類
“對String對象的任何改變都不影響到原對象,相關的任何change操作都會生成新的對象”。
public class Test{
public static void main(String[] args){
String a = "aaaa";
String b = a.replace('a', 'b');
System.out.println(a);
System.out.print(b);
}
}
當對String類對象進行subString(),replace()等,應該賦值給新的String對象,因爲a還是原來的內容。
String str="hello world"和String str=new String("hello world")的區別:
public class Test{
public static void main(String[] args){
String a = new String("aaaa");
String b = new String("aaaa");
String c = "aaaa";
System.out.println(a==b);
System.out.println(a.equals(b));
System.out.println(a==c);
System.out.println(a.equals(c));
}
}
String c = "aaaa";在編譯期間生成了 字面常量和符號引用,運行期間字面常量"aaaa"被存儲在運行時常量池(當然只保存了一份)。通過這種方式來將String對象跟引用綁定的話,JVM執行引擎會先在運行時常量池查找是否存在相同的字面常量,如果存在,則直接將引用指向已經存在的字面常量;否則在運行時常量池開闢一個空間來存儲該字面常量,並將引用指向該字面常量。
通過new關鍵字來生成對象是在堆區進行的,而在堆區進行對象生成的過程是不會去檢測該對象是否已經存在的。因此通過new來創建對象,創建出的一定是不同的對象,即使字符串的內容是相同的。
String類的equals方法只比較內容。所以equals返回true。
StringBuilder和StringBuffer類區別:
StringBuilder和StringBuffer類擁有的成員屬性以及成員方法基本相同,區別是StringBuffer類的成員方法前面多了一個關鍵字:synchronized,StringBuffer類是線程安全的
線程阻塞與喚醒方法:
1. sleep() 方法
sleep(毫秒),指定以毫秒爲單位的時間,使線程在該時間內進入線程阻塞狀態,期間得不到cpu的時間片,等到時間過去了,線程重新進入可執行狀態。不會釋放資源。(暫停線程,不會釋放鎖)
2.suspend() 和 resume() 方法:。
掛起和喚醒線程,suspend()使線程進入阻塞狀態,只有對應的resume()被調用的時候,線程纔會進入可執行狀態。(不建議用,容易發生死鎖)
3. yield() 方法:
會使的線程放棄當前分得的cpu時間片,但此時線程任然處於可執行狀態,隨時可以再次分得cpu時間片。yield()方法只能使同優先級的線程有執行的機會。調用 yield()的效果等價於調度程序認爲該線程已執行了足夠的時間從而轉到另一個線程。(暫停當前正在執行的線程,並執行其他線程,且讓出的時間不可知)
4.wait() 和 notify() 方法
兩個方法搭配使用,wait()使線程進入阻塞狀態,調用notify()時,線程進入可執行狀態。wait()內可加或不加參數,加參數時是以毫秒爲單位,當到了指定時間或調用notify()方法時,進入可執行狀態。(屬於Object類,而不屬於Thread類,wait()會先釋放鎖住的對象,然後再執行等待的動作。由於wait()所等待的對象必須先鎖住,因此,它只能用在同步化程序段或者同步化方法內,否則,會拋出異常IllegalMonitorStateException.)
5.join()方法
也叫線程加入。是當前線程A調用另一個線程B的join()方法,當前線程轉A入阻塞狀態,直到線程B運行結束,線程A才由阻塞狀態轉爲可執行狀態。
transient關鍵字
將不需要序列化的屬性前添加關鍵字transient,序列化對象的時候,這個屬性就不會被序列化。保證屬性不會被傳遞,安全。
static關鍵字
靜態變量在JVM初始化階段就被賦值。
類初始化的順序:
父類靜態變量->父類靜態代碼塊->子類靜態變量->子類靜態代碼塊->父類普通變量->父類普通代碼塊->父類構造函數->子類普通變量->子類普通代碼塊->子類構造函數
假設類A有靜態內部類B和非靜態內部類C,創建B和C的區別爲:
A a=new A();
A.B b=new A.B();
A.C c=a.new C();
volatile關鍵字
所有線程的共享變量都存儲在主內存中,每一個線程都有一個獨有的工作內存,每個線程不直接操作在主內存中的變量,而是將主內存上變量的副本放進自己的工作內存中,只操作工作內存中的數據。當修改完畢後,再把修改後的結果放回到主內存中。這就導致多線程的環境下可能會出現髒數據,加上volatile關鍵字修飾的話,它可以保證當線程對變量值做了變動之後,會立即刷回到主內存中,而其它線程讀取到該變量的值也作廢,強迫重新從主內存中讀取該變量的值,這樣在任何時刻,線程總是會看到變量的同一個值。
樹:
滿二叉樹:除了葉節點外每一個結點都有左右子女且葉節點都處在最底層的二叉樹。
完全二叉樹:只有最下面的兩層結點度小於2,並且最下面一層的結點都集中在該層最左邊的若干位置的二叉樹。
二叉樹:查找最好O(logN),最差O(N),最差情況是所有的數據全部在一端時。
二叉搜索樹:查找最好O(logN),最差O(N),最差情況是所有的數據全部在一端時
1.若任意結點的左子樹不空,則左子樹上所有結點的值均不大於它的根結點的值。
2. 若任意結點的右子樹不空,則右子樹上所有結點的值均不小於它的根結點的值。
3.任意結點的左、右子樹也分別爲二叉搜索樹。
平衡二叉樹:又稱爲AVL樹,查找O(logN),它是一顆空樹或它的左右兩個子樹的高度差的絕對值不超過1
哈夫曼樹:帶權路徑長度達到最小的二叉樹,也叫做最優二叉樹。
k層的二叉樹,最多有節點個數爲 2^k-1,最少有k個節點
第k層,最多有節點個數爲 2^(k-1)個
紅黑樹:查找刪除插入時間複雜度O(logN)
紅黑樹是每個節點都帶有顏色屬性的二叉查找樹,顏色爲紅色或黑色。在二叉查找樹強制的一般要求以外,對於任何有效的紅黑樹我們增加了如下的額外要求:
- 節點是紅色或黑色。
- 根是黑色。
- 所有葉子都是黑色(葉子是NIL節點)。
- 每個紅色節點必須有兩個黑色的子節點。(從每個葉子到根的所有路徑上不能有兩個連續的紅色節點。)
- 從任一節點到其每個葉子的所有簡單路徑都包含相同數目的黑色節點。
排序算法:
插入排序:
直接插入排序基本思想是每一步將一個待排序的記錄,插入到前面已經排好序的有序序列中去,直到插完所有元素爲止。
當數據正序時,執行效率最好,每次插入都不用移動前面的元素,時間複雜度爲O(N)。
當數據反序時,執行效率最差,每次插入都要前面的元素後移,時間複雜度爲O(N^2)。
希爾排序:
第一趟排序中,通過計算gap1=N/2(即10/2),將10個元素分爲5組,即(9,4),(1,8),(2,6),(5,3),(7,5),然後對每組內的元素進行插入排序。
第二趟排序中,把上次的 gap 縮小一半,即 gap2 = gap1 / 2 = 2 (取整數)。這樣每相隔距離爲 2 的元素組成一組,可以分爲 2 組。分組後依舊對每組的元素進行插入排序。
第三趟排序中,再次把 gap 縮小一半,即gap3 = gap2 / 2 = 1。 這樣相隔距離爲 1 的元素組成一組,即只有一組。再進行一次插入排序。
需要注意的是,圖中有兩個相等數值的元素 5 和 5 。我們可以清楚的看到,在排序過程中,兩個元素位置交換了。所以,希爾排序是不穩定的算法。
時間複雜度爲O(N^(1.3—2))
冒泡排序算法:
1.比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
2.對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素會是最大的數。
其時間複雜度依然爲O(N^2)
選擇排序:
1.從待排序序列中,找到最小的元素;
2.如果最小元素不是待排序序列的第一個元素,將其和待排序序列的第一個元素互換;
時間複雜度爲 O(N*2)
異常:
所有的異常都是繼承Throwable的,自定義異常不可以繼承自Error。
URI與URL
1.URL 比較實體 表示一個具體的
2.URI 比較抽象 表示一個相對的意思
URL -- 比如 http://www.baidu.com/124/123 是一個絕對的路徑
URI -- 比如 /124/123 是一個相對的路徑
泛型中的限定通配符和非限定通配符:
限定通配符包括兩種:
1. 表示類型的上界,格式爲:<? extends T>,即類型必須爲T類型或者T子類
2. 表示類型的下界,格式爲:<? super T>,即類型必須爲T類型或者T的父類
非限定通配符:類型爲<T>,可以用任意類型來替代。
迭代器(Iterator)
迭代器是一種設計模式,它是一個對象,它可以遍歷並選擇序列中的對象,而開發人員不需要了解該序列的底層結構。迭代器通常被稱爲“輕量級”對象,因爲創建它的代價小。
Java中的Iterator功能比較簡單,並且只能單向移動:
(1) 使用方法iterator()要求容器返回一個Iterator。第一次調用Iterator的next()方法時,它返回序列的第一個元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。
(2) 使用next()獲得序列中的下一個元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡單的實現,爲List設計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。