能夠有多個類,但只能有一個public的類,且public的類名必須與文件名相一致。html
Java中的保留字,如今未在Java中使用。java
&和&&均可以用做邏輯與的運算符,表示邏輯與(and),當運算符兩邊的表達式的結果都爲true時,整個運算結果才爲true,不然,只要有一方爲false,則結果爲false。程序員
&&還具備短路的功能,即若是第一個表達式爲false,則再也不計算第二個表達式,例如,對於if(str!= null&& !str.equals(s))表達式,當str爲null時,後面的表達式不會執行,因此不會出現NullPointerException若是將&&改成&,則會拋出NullPointerException異常。if(x==33 &++y>0) y會增加,if(x==33 && ++y>0)不會增加。web
&還能夠用做位運算符,當&操做符兩邊的表達式不是boolean類型時,&表示按位與操做,咱們一般使用0x0f來與一個整數進行&運算,來獲取該整數的最低4個bit位,例如,0x31 & 0x0f的結果爲0x01。面試
在Java中,要想跳出多重循環,能夠在外面的循環語句前定義一個標號,而後再裏層循環體的代碼中使用帶有標號的break語句,便可跳出外層循環。算法
test:for(int i=0;i<10;i++){ for(intj=0;j<10;j++){ System.out.println(「i=」 + i + 「,j=」 + j); if(j == 5) break test; } }
另外,我我的一般並不使用標號這種方式,而是讓外層的循環條件表達式的結果能夠受到裏層循環體代碼的控制,例如,要在二維數組中查找到某個數字。sql
int arr[][] ={{1,2,3},{4,5,6,7},{9}}; boolean found = false; for(int i=0;i<arr.length&&!found;i++) { for(intj=0;j<arr[i].length;j++){ System.out.println(「i=」 + i + 「,j=」 + j); if(arr[i][j] ==5) { found =true; break; } } }
在 switch(e) 中,e 只能是一個整數表達式或者枚舉常量(更大字體),整數表達式能夠使int或Integer,因爲byte,short,char均可以隱式轉換爲int,因此,這些類型及其包裝類也是能夠的。特例,Java1.7之後,switch語句支持String。綜上可知,long類型不符合switch的語法規定,而且不能隱式轉換成int類型,故不能做用於switch語句。shell
對於short s1= 1; s1 = s1 + 1;因爲s1+1運算時會自動提高表達式的類型,因此結果是int型,再賦值給short類型s1時,編譯器將報告須要強制轉換類型的錯誤。數據庫
對於short s1= 1; s1 += 1;因爲 +=是java語言規定的運算符,java編譯器會對它進行特殊處理,所以能夠正確編譯。編程
char型變量用來存儲Unicode編碼的字符,Unicode編碼字符集中包含了漢字,故能夠存儲。不過,個別特殊漢字未被包含,即不可存儲某些特殊漢字。補充說明:Unicode編碼佔用兩個字節,所以,char類型的變量也是佔用兩個字節。
2 << 3。左移三位,由於將一個數左移n位,就至關於乘以了2的n次方,且位運算cpu直接支持的,效率最高。
使用final關鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內容仍是能夠改變的。例如,對於以下語句:
final StringBuffer a=new StringBuffer("immutable");
執行以下語句將報告編譯期錯誤:
a=new StringBuffer("");
可是,執行以下語句則能夠經過編譯:
a.append(" broken!");
在語法定義上的區別:靜態變量前要加static關鍵字,而實例變量前則不加。
在程序運行時的區別:實例變量屬於某個對象的屬性,必須建立了實例對象,其中的實例變量纔會被分配空間,才能使用這個實例變量。靜態變量不屬於某個實例對象,而是屬於類,因此也稱爲類變量,只要程序加載了類的字節碼,不用建立任何實例對象,靜態變量就會被分配空間,靜態變量就能夠被使用了。總之,實例變量必須建立對象後才能夠經過這個對象來使用,靜態變量則能夠直接使用類名來引用。
例如,對於下面的程序,不管建立多少個實例對象,永遠都只分配了一個staticVar變量,而且每建立一個實例對象,這個staticVar就會加1;可是,每建立一個實例對象,就會分配一個instanceVar,便可能分配多個instanceVar,而且每一個instanceVar的值都只自加了1次。
public class VariantTest{ publicstatic int staticVar = 0; publicint instanceVar = 0; publicVariantTest(){ staticVar++; instanceVar++; System.out.println(staticVar +instanceVar); } }
不能夠。由於非static方法是要與對象關聯在一塊兒的,必須建立一個對象後,才能夠在該對象上進行方法調用,而static方法調用時不須要建立對象,能夠直接調用。也就是說,當一個static方法被調用時,可能尚未建立任何實例對象,若是從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪一個對象上的呢?這個邏輯沒法成立,因此,一個static方法內部發出對非static方法的調用。
int是java提供的8種原始數據類型之一。Java爲每一個原始類型提供了封裝類,Integer是java爲int提供的封裝類。int的默認值爲0,而Integer的默認值爲null,即Integer能夠區分出未賦值和值爲0的區別,int則沒法表達出未賦值的狀況。
例如:要想表達出沒有參加考試和考試成績爲0的區別,則只能使用Integer。
Integer提供了多個與整數相關的操做方法,例如,將一個字符串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。
Math類中提供了三個與取整有關的方法:ceil 向上取整、floor 向下取整 、round 四捨五入,這些方法的做用與它們的英文名稱的含義相對應。故,Math.round(11.5) 輸出結果爲 12 , Math.round(-11.5) 輸出結果爲 -11。
Overload是重載的意思,Override是覆蓋的意思,也就是重寫。
重載Overload表示同一個類中能夠有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不一樣)。
重寫Override表示子類中的方法能夠與父類中的某個方法的名稱和參數徹底相同,經過子類建立的實例對象調用這個方法時,將調用子類中的定義方法,這至關於把父類中定義的那個徹底相同的方法給覆蓋了,這也是面向對象編程的多態性的一種表現。子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,由於子類能夠解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。若是父類的方法是private類型,那麼,子類則不存在覆蓋的限制,至關於子類中增長了一個全新的方法。
至於Overloaded的方法是否能夠改變返回值的類型這個問題,要看你倒底想問什麼呢?這個題目很模糊。若是幾個Overloaded的方法的參數列表不同,它們的返回者類型固然也能夠不同。但我估計你想問的問題是:若是兩個方法的參數列表徹底同樣,是否可讓它們的返回值不一樣來實現重載Overload。這是不行的,咱們能夠用反證法來講明這個問題,由於咱們有時候調用一個方法時也能夠不定義返回結果變量,即不要關心其返回結果,例如,咱們調用map.remove(key)方法時,雖然remove方法有返回值,可是咱們一般都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數列表徹底相同的方法,僅僅是返回類型不一樣,java就沒法肯定編程者倒底是想調用哪一個方法了,由於它沒法經過返回結果類型來判斷。
override能夠翻譯爲覆蓋,從字面就能夠知道,它是覆蓋了一個方法而且對其重寫,以求達到不一樣的做用。對咱們來講最熟悉的覆蓋就是對接口方法的實現,在接口中通常只是對方法進行了聲明,而咱們在實現時,就須要實現接口聲明的全部方法。除了這個典型的用法之外,咱們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意如下的幾點:
一、覆蓋的方法的標誌必需要和被覆蓋的方法的標誌徹底匹配,才能達到覆蓋的效果;
二、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
三、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;
四、被覆蓋的方法不能爲private,不然在其子類中只是新定義了一個方法,並無對其進行覆蓋。
Overload對咱們來講可能比較熟悉,能夠翻譯爲重載,它是指咱們能夠定義一些名稱相同的方法,經過定義不一樣的輸入參數來區分這些方法,而後再調用時,VM就會根據不一樣的參數樣式,來選擇合適的方法執行。在使用重載要注意如下的幾點:
一、在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序(固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int,float),可是不能爲fun(int,int));
二、不能經過訪問權限、返回類型、拋出的異常進行重載;
三、方法的異常類型和數目不會對重載形成影響;
四、對於繼承來講,若是某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,若是定義的話,也只是定義了一個新方法,而不會達到重載的效果。
接口能夠繼承接口。抽象類能夠實現接口,抽象類能夠繼承具體類。抽象類中能夠有靜態的main方法。
注:抽象類與普通類的惟一區別就是不能建立實例對象和容許有abstract方法。
靠的是父類或接口定義的引用變量能夠指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是 引用變量所指向的具體實例對象的方法,即 內存中正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。
1.抽象類能夠有構造方法,接口中不能有構造方法。
2.抽象類中能夠有普通成員變量,接口中沒有普通成員變量。
3.抽象類中能夠包含非抽象的普通方法,Java 1.8後,接口能夠包含一個default的實現方法,其他必須爲抽象的普通方法。(java.util.List接口,新增sort(),可直接傳參比較器Comparator)。
4. 抽象類中的抽象方法的訪問類型能夠是public,protected,但接口中的抽象方法只能是public類型的,而且默認即爲public abstract類型。
5. 抽象類中能夠包含靜態方法,接口中不能包含靜態方法。
6. 抽象類和接口中均可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型能夠任意,但接口中定義的變量只能是public static final類型,而且默認即爲public static final類型。
7. 一個類能夠實現多個接口,但只能繼承一個抽象類。
abstract的method不能夠是static的,由於抽象的方法是要被子類實現的,而static與子類扯不上關係!
native方法表示該方法要用另一種依賴平臺的編程語言實現的,不存在着被子類實現的問題,因此,它也不能是抽象的,不能與abstract混用。
關於synchronized與abstract合用的問題,我以爲也不行,由於在我幾年的學習和開發中,歷來沒見到過這種狀況,而且我以爲synchronized應該是做用在一個具體的方法上纔有意義。並且,方法上的synchronized同步所使用的同步鎖對象是this,而抽象方法上沒法肯定this是什麼。(話術)
徹底能夠。若是不是靜態內部類,那沒有什麼限制!
若是你把靜態嵌套類看成內部類的一種特例,那在這種狀況下不能夠訪問外部類的普通成員變量,而只能訪問外部類中的靜態成員,例如,下面的代碼:
class Outer { static int x; static class Inner { voidtest() { syso(x); } } }
沒有。由於String被設計成不可變(immutable)類,因此它的全部對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內容是 "Hello",而後咱們對s進行了+操做,那麼s所指向的那個對象是否發生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另外一個 String對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是s這個引用變量再也不指向它了。
經過上面的說明,咱們很容易導出另外一個結論,若是常常對字符串進行各類各樣的修改,或者說,不可預見的修改,那麼使用String來表明字符串的話會引發很大的內存開銷。由於String對象創建以後不能再改變,因此對於每個不一樣的字符串,都須要一個String對象來表示。這時,應該考慮使用StringBuffer類,它容許修改,而不是每一個不一樣的字符串都要生成一個新的對象。而且,這兩種類的對象轉換十分容易。
同時,咱們還能夠知道,若是要使用內容相同的字符串,沒必要每次都new一個String。例如咱們要在構造器中對一個名叫s的String引用變量進行初始化,把它設置爲初始值,應當這樣作:
public class Demo { private String s; ... public Demo { s = "Initial Value"; } ... } 而非 s = new String("Initial Value");
後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,而且沒有意義,由於String對象不可改變,因此對於內容相同的字符串,只要一個String對象來表示就能夠了。也就說,屢次調用上面的構造器建立多個對象,他們的String類型屬性s都指向同一個對象。
上面的結論還基於這樣一個事實:對於字符串常量,若是內容相同,Java認爲它們表明同一個String對象。而用關鍵字new調用構造器,老是會建立一個新的對象,不管內容是否相同。
至於爲何要把String類設計成不可變類,是它的用途決定的。其實不僅String,不少Java標準類庫中的類都是不可變的。在開發一個系統的時候,咱們有時候也須要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。不可變類有一些優勢,好比由於它的對象是隻讀的,因此多線程併發訪問也不會有任何問題。固然也有一些缺點,好比每一個不一樣的狀態都要一個對象來表明,可能會形成性能上的問題。因此Java標準類庫還提供了一個可變版本,即StringBuffer。
這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,至關於一種動態的數組,咱們之後能夠按位置索引號取出某個元素,而且其中的數據是容許重複的,這是與HashSet之類的集合的最大不一樣處,HashSet之類的集合不能夠按索引號去檢索其中的元素,也不容許有重複的元素。
ArrayList與Vector的區別主要包括兩個方面:
(1)同步性:
Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不一樣步的。若是隻有一個線程會訪問到集合,那最好是使用ArrayList,由於它不考慮線程安全,效率會高些;若是有多個線程會訪問到集合,那最好是使用Vector,由於不須要咱們本身再去考慮和編寫線程安全的代碼。
(2)數據增加:
ArrayList與Vector都有一個初始的容量大小,當存儲進它們裏面的元素的個數超過了容量時,就須要增長ArrayList與Vector的存儲空間,每次要增長存儲空間時,不是隻增長一個存儲單元,而是增長多個存儲單元,每次增長的存儲單元的個數在內存空間利用與程序效率之間要取得必定的平衡。Vector默認增加爲原來兩倍,而ArrayList的增加策略在文檔中沒有明確規定(從源代碼看到的是增加爲原來的1.5倍)。ArrayList與Vector均可以設置初始的空間大小,Vector還能夠設置增加的空間大小,而ArrayList沒有提供設置增加空間的方法。總結:即Vector增加原來的一倍,ArrayList增長原來的0.5倍。
HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap容許空(null)鍵值(key),因爲非線程安全,在只有一個線程訪問的狀況下,效率要高於Hashtable。
HashMap容許將null做爲一個entry的key或者value,而Hashtable不容許。
Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。
最大的不一樣是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不須要本身爲它的方法實現同步,而HashMap就必須爲之提供同步。
就HashMap與HashTable主要從三方面來講。
一.歷史緣由:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現。
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的。
三.值:只有HashMap可讓你將空值做爲一個表的條目的key或value。
一個是存儲單列數據的集合,另外一個是存儲鍵和值這樣的雙列數據的集合,List中存儲的數據是有順序,而且容許重複;Map中存儲的數據是沒有順序的,其鍵是不能重複的,它的值是能夠有重複的。
List,Set是,Map不是。
首先,List與Set具備類似性,它們都是單列元素的集合,因此,它們有一個共同的父接口,叫Collection。Set裏面不容許有重複的元素,即不能有兩個相等(注意,不是僅僅是相同)的對象,即假設Set集合中有了一個A對象,如今我要向Set集合再存入一個B對象,但B對象與A對象equals相等,則B對象存儲不進去,因此,Set集合的add方法有一個boolean的返回值,當集合中沒有某個元素,此時add方法可成功加入該元素時,則返回true,當集合含有與某個元素equals相等的元素時,此時add方法沒法加入該元素,返回結果爲false。Set取元素時,不能細說要取第幾個,只能以Iterator接口取得全部的元素,再逐一遍歷各個元素。
List表示有前後順序的集合,注意,不是那種按年齡、按大小、按價格之類的排序。當咱們屢次調用add(Obje)方法時,每次加入的對象就像火車站買票有排隊順序同樣,按先來後到的順序排序。有時候,也能夠插隊,即調用add(intindex,Obj e)方法,就能夠指定當前對象在集合中的存放位置。一個對象能夠被反覆存儲進List中,每調用一次add方法,這個對象就被插入進集合中一次,其實,並非把這個對象自己存儲進了集合中,而是在集合中用一個索引變量指向這個對象,當這個對象被add屢次時,即至關於集合中有多個索引指向了這個對象,如圖x所示。List除了能夠用Iterator接口取得全部的元素,再逐一遍歷各個元素以外,還能夠調用get(index i)來明確說明取第幾個。
Map與List和Set不一樣,它是雙列的集合,其中有put方法,定義以下:put(obj key,obj value),每次存儲時,要存儲一對key/value,不能存儲重複的key,這個重複的規則也是按equals比較相等。取則能夠根據key得到相應的value,即get(Object key)返回值爲key所對應的value。另外,也能夠得到全部的key的結合,還能夠得到全部的value的結合,還能夠得到key和value組合成的Map.Entry對象的集合。
List以特定次序來持有元素,可有重複元素。Set沒法擁有重複元素,內部排序。Map保存key-value值,value可多值。
ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增長和插入元素,它們都容許直接按序號索引元素,可是插入元素要涉及數組元素移動等內存操做,因此索引數據快而插入數據慢,Vector因爲使用了synchronized方法(線程安全),一般性能上較ArrayList差。而LinkedList使用雙向鏈表實現存儲,按序號索引數據須要進行前向或後向遍歷,索引就變慢了,可是插入數據時只須要記錄本項的先後項便可,因此插入速度較快。
LinkedList也是線程不安全的,LinkedList提供了一些方法,使得LinkedList能夠被看成堆棧和隊列來使用。
Vector newVector = new Vector(); for (int i=0;i<vector.size();i++) { Object obj = vector.get(i); if(!newVector.contains(obj) newVector.add(obj); }
還有一種簡單的方式,利用了Set不容許重複元素:
HashSet set = new HashSet(vector);
Collection是集合類的上級接口,繼承他的接口主要有Set和List。
Collections是針對集合類的一個工具類,他提供一系列靜態方法實現對各類集合的搜索、排序、線程安全化等操做。
Set裏的元素是不能重複的,元素重複與否是使用equals()方法進行判斷的。
==操做符專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操做符。
equals方法是用於比較兩個獨立對象的內容是否相同,就比如去比較兩我的的長相是否相同,它比較的兩個對象是獨立的。
好比:兩條new語句建立了兩個對象,而後用a/b這兩個變量分別指向了其中一個對象,這是兩個不一樣的對象,它們的首地址是不一樣的,即a和b中存儲的數值是不相同的,因此,表達式a==b將返回false,而這兩個對象中的內容是相同的,因此,表達式a.equals(b)將返回true。
最經常使用的集合類是 List 和 Map。 List的具體實現包括 ArrayList和 Vector,它們是可變大小的列表,比較適合構建、存儲和操做任何類型對象的元素列表。 List適用於按數值索引訪問元素的情形。
Map 提供了一個更通用的元素存儲方法。 Map集合類用於存儲元素對(稱做"鍵"和"值"),其中每一個鍵映射到一個值。
它們都有增刪改查的方法。
對於set,大概的方法是add,remove, contains等。
對於map,大概的方法就是put,remove,contains等。
List類會有get(int index)這樣的方法,由於它能夠按順序取元素,而set類中沒有get(int index)這樣的方法。List和set均可以迭代出全部元素,迭代時先要獲得一個iterator對象,因此,set和list類都有一個iterator方法,用於返回那個iterator對象。map能夠返回三個集合,一個是返回全部的key的集合,另一個返回的是全部value的集合,再一個返回的key和value組合成的EntrySet對象的集合,map也有get方法,參數是key,返回值是key對應的value。
兩個或一個都有可能,」xyz」對應一個對象,這個對象放在字符串常量緩衝區,常量」xyz」無論出現多少遍,都是緩衝區中的那一個。new String每寫一遍,就建立一個新的對象,它使用常量」xyz」對象的內容來建立出一個新String對象。若是之前就用過’xyz’,那麼這裏就不會建立」xyz」了,直接從緩衝區拿,這時建立了一個StringObject;但若是之前沒有用過"xyz",那麼此時就會建立一個對象並放入緩衝區,這種狀況它建立兩個對象。至於String類是否繼承,答案是否認的,由於String默認final修飾,是不可繼承的。
它們能夠儲存和操做字符串,即包含多個字符的字符數據。這個String類提供了數值不可改變的字符串。而這個StringBuffer類提供的字符串能夠進行修改。當你知道字符數據要改變的時候你就能夠使用StringBuffer。即,你能夠使用StringBuffer來動態構造字符數據。
對於以下代碼:
String s1 = "a"; String s2 = s1 + "b"; String s3 = "a" + "b"; System.out.println(s2 == "ab"); System.out.println(s3 == "ab");
第一條語句打印的結果爲false,第二條語句打印的結果爲true,這說明javac編譯能夠對字符串常量直接相加的表達式進行優化,沒必要要等到運行期再去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。
題目中的第一行代碼被編譯器在編譯時優化後,至關於直接定義了一個」abcd」的字符串,因此,上面的代碼應該只建立了一個String對象。寫以下兩行代碼,
String s ="a" + "b" +"c" + "d"; System.out.println(s== "abcd");
最終打印的結果應該爲true。
首先,finally{} 中的語句必定會執行。但其再也不return以前,也再也不return以後,而是在return中間執行。參考下列程序:
public classTest { public static void main(String[]args) { System.out.println(newTest().test());; } static int test() { intx = 1; try { returnx; } finally{ ++x; } } } ---------執行結果 --------- 1
運行結果是1,爲何呢?主函數調用子函數並獲得結果的過程,比如主函數準備一個空罐子,當子函數要返回結果時,先把結果放在罐子裏,而後再將程序邏輯返回到主函數。所謂返回,就是子函數說,我不運行了,你主函數繼續運行吧,這沒什麼結果可言,結果是在說這話以前放進罐子裏的。
final 用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承。內部類要訪問局部變量,局部變量必須定義成final類型。
finally是異常處理語句結構的一部分,表示老是執行。
finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,能夠覆蓋此方法提供垃圾收集時的其餘資源回收,例如關閉文件等。可是JVM不保證此方法總被調用。
異常表示程序運行過程當中可能出現的非正常狀態,運行時異常表示虛擬機的一般操做中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,可是並不要求必須聲明拋出未被捕獲的運行時異常。
error 表示恢復不是不可能但很困難的狀況下的一種嚴重問題。好比說內存溢出。不可能期望程序能處理這樣的狀況。exception表示一種設計或實現問題。也就是說,它表示若是程序運行正常,從不會發生的狀況。
異常是指java程序運行時(非編譯)所發生的非正常狀況或錯誤,與現實生活中的事件很類似,現實生活中的事件能夠包含事件發生的時間、地點、人物、情節等信息,能夠用一個對象來表示,Java使用面向對象的方式來處理異常,它把程序中發生的每一個異常也都分別封裝到一個對象來表示的,該對象中包含有異常的信息。
Java對異常進行了分類,不一樣類型的異常分別用不一樣的Java類表示,全部異常的根類爲java.lang.Throwable,Throwable下面又派生了兩個子類:
Error和Exception,Error表示應用程序自己沒法克服和恢復的一種嚴重問題,程序只有奔潰了,例如,說內存溢出和線程死鎖等系統問題。
Exception表示程序還可以克服和恢復的問題,其中又分爲系統異常和普通異常:
系統異常是軟件自己缺陷所致使的問題,也就是軟件開發人員考慮不周所致使的問題,軟件使用者沒法克服和恢復這種問題,但在這種問題下還可讓軟件系統繼續運行或者讓軟件掛掉,例如,數組腳本越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException);
普通異常是運行環境的變化或異常所致使的問題,是用戶可以克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常後,程序不該該死掉。
Java爲系統異常和普通異常提供了不一樣的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,因此普通異常也稱爲checked異常,而系統異常能夠處理也能夠不處理,因此,編譯器不強制用try..catch處理或用throws聲明,因此係統異常也稱爲unchecked異常。
JVM 中堆和棧屬於不一樣的內存區域,使用目的也不一樣。棧經常使用於保存方法幀和局部變量,而對象老是在堆上分配。棧一般都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的全部線程共享。
棧:在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配,當在一段代碼塊定義一個變量時,Java 就在棧中爲這個變量分配內存空間,當超過變量的做用域後,Java 會自動釋放掉爲該變量分配的內存空間,該內存空間能夠當即被另做它用。
堆:堆內存用來存放由 new 建立的對象和數組,在堆中分配的內存,由 Java 虛擬機的自動垃圾回收器來管理。在堆中產生了一個數組或者對象以後,還能夠在棧中定義一個特殊的變量,讓棧中的這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量,之後就能夠在程序中使用棧中的引用變量來訪問堆中的數組或者對象,引用變量就至關因而爲數組或者對象起的一個名稱。
能夠作強制轉換,可是 Java 中 int 是 32 位的,而 byte 是 8 位的,因此,若是強制轉化,int 類型的高 24 位將會被丟棄,由於byte 類型的範圍是從 -128 到 127。
hashCode() 方法對應對象整型的 hash 值。它經常使用於基於 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關係特別緊密。根據 Java 規範,兩個使用 equal() 方法來判斷相等的對象,必須具備相同的 hash code。
要把一段二進制數據數據逐一輸出到某個設備中,或者從某個設備中逐一讀取一段二進制數據,無論輸入輸出設備是什麼,咱們要用統一的方式來完成這些操做,用一種抽象的方式進行描述,這個抽象描述方式起名爲IO流,對應的抽象類爲OutputStream和InputStream,不一樣的實現類就表明不一樣的輸入和輸出設備,它們都是針對字節進行操做的。
計算機中的一切最終都是二進制的字節形式存在。對於常常用到的中文字符,首先要獲得其對應的字節,而後將字節寫入到輸出流。讀取時,首先讀到的是字節,但是咱們要把它顯示爲字符,咱們須要將字節轉換成字符。因爲這樣的需求很普遍,Java專門提供了字符流包裝類。
底層設備永遠只接受字節數據,有時候要寫字符串到底層設備,須要將字符串轉成字節再進行寫入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫入底層設備,這爲咱們向IO設備寫入或讀取字符串提供了一點點方便。
字符向字節轉換時,要注意編碼的問題,由於字符串轉成字節數組,實際上是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。
實際應用中,有時需將一個Java對象轉換爲字節流的形式傳出去或者從一個字節流中恢復成一個Java對象,例如,要將Java對象存儲到硬盤或者傳送給網絡上的其餘計算機,這個過程須要將一個Java對象轉換爲某種格式的字節流再傳輸。
並且,JRE自己就提供了這種支持,能夠調用ObjectOutputStream的writeObject方法來作,這時就須要被傳輸的對象必須實現Serializable接口,如此,javac編譯時就會進行特殊處理,編譯的類才能夠被writeObject方法操做,即所謂的序列化。須要被序列化的類必須實現Serializable接口,該接口是一個mini接口,其中沒有須要實現的方法,implements Serializable只是爲了標註該對象是可被序列化的。
例如,在web開發中,若是對象被保存在了Session中,tomcat在重啓時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。若是對象要通過分佈式系統進行網絡傳輸,被傳輸的對象就必須實現Serializable接口。
JVM中類的裝在是由ClassLoader和它的子類來實現的,Java ClassLoader是一個重要的Java運行時系統組件。它負責在運行時查找和裝入類文件中的類。
Java的內存分爲兩類,一類是棧內存,一類是堆內存。棧內存是指程序進入一個方法時,會爲這個方法單獨分配一塊私屬存儲空間,用於存儲這個方法內部的局部變量,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。
堆是與棧做用不一樣的內存,通常用於存放不在當前方法棧中的那些數據,例如,使用new建立的對象都放在堆裏,因此,它不會隨方法的結束而消失。方法中的局部變量使用final修飾後,放在堆中,而不是棧中。
GC即Garbage Collection,內存處理是開發人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠自動檢測對象是否超過做用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯式操做方法。
Java語言中一個顯著的特色就是引入了垃圾回收機制,使C++程序員最頭疼的內存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候再也不過多考慮內存管理。因爲垃圾回收機制,Java中的對象再也不有"做用域"的概念,只有對象的引用纔有"做用域"。
垃圾回收能夠有效的防止內存泄露,有效的使用能夠使用的內存。垃圾回收器一般是做爲一個單獨的低級別的線程運行,不可預知的狀況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或全部對象進行垃圾回收。
回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。
對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對象。經過這種方式肯定哪些對象是"可達的",哪些對象是"不可達的"。當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。
System.gc()和Runtime.getRuntime().gc(),但兩者的行爲沒有任何不一樣,前者僅能夠理解爲後者的簡寫。其實基本沒有什麼機會用獲得這個命令,由於這個命令只是建議JVM安排GC運行,還有可能徹底被拒絕。GC自己是會週期性的自動運行的,由JVM決定運行的時機,並且如今的版本有多種更智能的模式能夠選擇,還會根據運行的機器自動去作選擇,就算真的有性能上的需求,也應該去對GC的運行機制進行微調,而不是經過使用這個命令來實現性能的優化。
throw 用於拋出 java.lang.Throwable 類的一個實例化對象,意思是說你能夠經過關鍵字 throw 拋出一個Exception,如:
throw new IllegalArgumentException(「XXXXXXXXX″);
而throws 的做用是做爲方法聲明和簽名的一部分,方法被拋出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。
所謂內存泄露就是指一個再也不被程序使用的對象或變量一直被佔據在內存中。java中有垃圾回收機制,它能夠保證當對象再也不被引用的時候,對象將自動被垃圾回收器從內存中清除掉。
因爲Java使用有向圖的方式進行垃圾回收管理,能夠消除引用循環的問題,例若有兩個對象,相互引用,只要它們和根進程不可達,那麼GC也是能夠回收它們的。
Java中的內存泄露的狀況:長生命週期的對象持有短生命週期對象的引用就極可能發生內存泄露,儘管短生命週期對象已經再也不須要,可是由於長生命週期對象持有它的引用而致使不能被回收,這就是Java中內存泄露的發生場景,通俗地說,就是程序員可能建立了一個對象,之後一直再也不使用這個對象,這個對象卻一直被引用,即這個對象無用可是卻沒法被垃圾回收器回收的,這就是java中可能出現內存泄露的狀況,例如,緩存系統,咱們加載了一個對象放在緩存中(例如放在一個全局map對象中),而後一直再也不使用它,這個對象一直被緩存引用,但卻再也不被使用。
同時,本地資源的釋放,如Opencv中的VideoCapture、Mat等,IO、Connection等流資源的釋放,都是內存泄漏的源頭。
Servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由javax.servlet.Servlet接口的init(),service()和destroy方法表達。
Servlet被服務器實例化後,容器運行其init方法,請求到達時運行其service方法,service方法自動派遣運行與請求對應的doXXX方法(doGet,doPost)等,當服務器決定將實例銷燬的時候調用其destroy方法。
web容器加載servlet,生命週期開始。經過調用servlet的init()方法進行servlet的初始化。經過調用service()方法實現,根據請求的不一樣調用不一樣的do***()方法。結束服務,web容器調用servlet的destroy()方法。
Cookie是會話技術,將用戶的信息保存到瀏覽器的對象。
區別:
1.Cookie數據存放在客戶的瀏覽器上,session數據放在服務器上
2.Cookie不是很安全,別人能夠分析存放在本地的Cookie並進行Cookie欺騙,若是主要考慮到安全應當使用Session
3.Session會在必定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能,若是主要考慮到減輕服務器性能方面,應當使用Cookie
所以,將登錄信息等重要信息存放爲SESSION;其餘信息若是須要保留,能夠放在COOKIE中。
當容器啓動時,會讀取在webapps目錄下全部的web應用中的web.xml文件,而後對xml文件進行解析,並讀取servlet註冊信息。而後,將每一個應用中註冊的servlet類都進行加載,並經過反射的方式實例化。(有時候也是在第一次請求時實例化)
在servlet註冊時加上<load-on-startup>1</load-on-startup>若是爲正數,則在一開始就實例化,若是不寫或爲負數,則第一次請求實例化。
1.加載驅動
2.經過DriverManager對象獲取鏈接對象Connection
3.經過鏈接對象獲取會話
4.經過會話進行數據的增刪改查,封裝對象
5.關閉資源
1.事務是做爲單個邏輯工做單元執行的一系列操做
2.一個邏輯工做單元必須有四個屬性,稱爲原子性、一致性、隔離性和持久性 (ACID) 屬性,只有這樣才能成爲一個事務
事務處理步驟:
3.conn.setAutoComit(false);設置提交方式爲手工提交
4.conn.commit()提交事務
5.出現異常,回滾 conn.rollback()
1.數據庫鏈接是一件費時的操做,鏈接池能夠使多個操做共享一個鏈接
2.數據庫鏈接池的基本思想就是爲數據庫鏈接創建一個「緩衝池」。預先在緩衝池中放入必定數量的鏈接,當須要創建數據庫鏈接時,只需從「緩衝池」中取出一個,使用完畢以後再放回去。咱們能夠經過設定鏈接池最大鏈接數來防止系統無盡的與數據庫鏈接。更爲重要的是咱們能夠經過鏈接池的管理機制監視數據庫的鏈接的數量、使用狀況,爲系統開發,測試及性能調整提供依據
3.使用鏈接池是爲了提升對數據庫鏈接資源的管理
JDBC的DriverManager是一個工廠類,咱們經過它來建立數據庫鏈接。當JDBC的Driver類被加載進來時,它會本身註冊到DriverManager類裏面;而後咱們會把數據庫配置信息傳成DriverManager.getConnection()方法,DriverManager會使用註冊到它裏面的驅動來獲取數據庫鏈接,並返回給調用的程序。
1.Spring是實現了工廠模式的工廠類,這個類名爲BeanFactory(其實是一個接口),在程序中一般BeanFactory的子類ApplicationContext。Spring至關於一個大的工廠類,在其配置文件中經過<bean>元素配置用於建立實例對象的類名和實例對象的屬性。
2. Spring提供了對IOC良好支持,IOC是一種編程思想,是一種架構藝術,利用這種思想能夠很好地實現模塊之間的解耦,IOC也稱爲DI(Depency Injection)。
3. Spring提供了對AOP技術的良好封裝, AOP稱爲面向切面編程,就是系統中有不少各不相干的類的方法,在這些衆多方法中要加入某種系統功能的代碼,例如,加入日誌,加入權限判斷,加入異常處理,這種應用稱爲AOP。
實現AOP功能採用的是代理技術,客戶端程序再也不調用目標,而調用代理類,代理類與目標類對外具備相同的方法聲明,有兩種方式能夠實現相同的方法聲明,一是實現相同的接口,二是做爲目標的子類。
在JDK中採用Proxy類產生動態代理的方式爲某個接口生成實現類,若是要爲某個類生成子類,則能夠用cglib。在生成的代理類的方法中加入系統功能和調用目標類的相應方法,系統功能的代理以Advice對象進行提供,顯然要建立出代理對象,至少須要目標類和Advice類。Spring提供了這種支持,只須要在Spring配置文件中配置這兩個元素便可實現代理和AOP功能。
輕量:Spring 是輕量的,基本的版本大約2MB。
控制反轉:Spring經過控制反轉實現了鬆散耦合,對象們給出它們的依賴,而不是建立或查找依賴的對象們。
面向切面的編程(AOP):Spring支持面向切面的編程,而且把應用業務邏輯和系統服務分開。
容器:Spring 包含並管理應用中對象的生命週期和配置。
MVC框架:Spring的WEB框架是個精心設計的框架,是Web框架的一個很好的替代品。
事務管理:Spring 提供一個持續的事務管理接口,能夠擴展到上至本地事務下至全局事務(JTA)。
異常處理:Spring 提供方便的API把具體技術相關的異常(好比由JDBC,Hibernate or JDO拋出的)轉化爲一致的unchecked 異常。
FileSystemXmlApplicationContext :此容器從一個XML文件中加載beans的定義,XML Bean 配置文件的全路徑名必須提供給它的構造函數。
ClassPathXmlApplicationContext:此容器也從一個XML文件中加載beans的定義,這裏,你須要正確設置classpath由於這個容器將在classpath裏找bean配置。
WebXmlApplicationContext:此容器加載一個XML文件,此文件定義了一個WEB應用的全部bean。
Spring框架支持如下五種bean的做用域:
singleton : bean在每一個Spring ioc 容器中只有一個實例。
prototype:一個bean的定義能夠有多個實例。
request:每次http請求都會建立一個bean,該做用域僅在基於web的Spring ApplicationContext情形下有效。
session:在一個HTTP Session中,一個bean定義對應一個實例。該做用域僅在基於web的Spring ApplicationContext情形下有效。
global-session:在一個全局的HTTP Session中,一個bean定義對應一個實例。該做用域僅在基於web的Spring ApplicationContext情形下有效。
缺省的Spring bean的做用域是Singleton。
一、Spring容器從XML文件中讀取bean的定義,或者掃描實現@Component的類,並實例化bean。
二、Spring根據bean的定義填充全部的屬性。
三、若是bean實現了BeanNameAware接口,Spring傳遞bean的ID到setBeanName方法。
四、若是bean實現了BeanFactoryAware接口,Spring傳遞beanFactory給setBeanFactory方法。
五、若是有任何與bean相關聯的BeanPostProcessors,Spring會在postProcesserBeforeInitialization方法內調用它們。
六、若是bean實現了IntializingBean,調用它的afterPropertySet方法,若是bean聲明瞭初始化方法,調用此初始化方法。
七、若是有BeanPostProcessors和bean關聯,這些bean的postProcesserAfterInitialization方法將被調用。
八、若是bean實現了DisposableBean,它將調用destroy方法。
#將傳入的數據都當成一個字符串,會對傳入的數據自動加上引號;
$將傳入的數據直接顯示生成在SQL中。
注意:使用$佔位符可能會致使SQL注射攻擊,能用#的地方就不要使用$。而$方式通常用於傳入數據庫對象,例如傳入表名或列名,尤爲是在寫order by子句的時候應該用$而不是#。如:order by ${user_id},若是傳入的值是111,那麼解析成sql時的值爲order by 111, 若是傳入的值是id,則解析成的sql爲order by id,而用#則爲order by 'id',能夠經過執行,但無效。
在大型項目中,可能存在大量的SQL語句,這時候爲每一個SQL語句起一個惟一的標識(ID)就變得並不容易了。爲了解決這個問題,在MyBatis中,能夠爲每一個映射文件起一個惟一的命名空間,這樣定義在這個映射文件中的每一個SQL語句就成了定義在這個命名空間中的一個ID。只要咱們可以保證每一個命名空間中這個ID是惟一的,即便在不一樣映射文件中的語句ID相同,也不會再產生衝突了。命名空間,通常命名爲xml對應Mapper接口的參考路徑名 reference path,com.rosetta.image.mapper.UserMapper。
對於一些複雜的查詢,可能會指定多個查詢條件,可是這些條件可能存在也可能不存在,若是不使用持久層框架咱們可能須要本身拼裝SQL語句,不過MyBatis提供了動態SQL的功能來解決這個問題。MyBatis中用於實現動態SQL的元素主要有:
if - choose / when / otherwise - trim - where - set - foreach
用法舉例:
<select id="foo" parameterType="Blog" resultType="Blog"> select * from t_blog where 1 = 1 <if test="title != null"> and title = #{title} </if> <if test="content != null"> and content = #{content} </if> <if test="owner != null"> and owner = #{owner} </if> </select>
1.JDBC:數據庫連接建立、釋放頻繁形成系統資源浪費從而影響系統性能,若是使用數據庫連接池可解決此問題。
MyBatis:在SqlMapConfig.xml中配置數據連接池,使用鏈接池管理數據庫連接。
2.JDBC:Sql語句寫在代碼中形成代碼不易維護,實際應用sql變化的可能較大,sql變更須要改變java代碼。
MyBatis:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。
3.JDBC:向sql語句傳參數麻煩,由於sql語句的where條件不必定,可能多也可能少,佔位符須要和參數一一對應。
MyBatis: Mybatis自動將java對象映射至sql語句。
4.JDBC:對結果集解析麻煩,sql變化致使解析代碼變化,且解析前須要遍歷,若是能將數據庫記錄封裝成pojo對象解析比較方便。
MyBatis:Mybatis自動將sql執行結果映射至java對象。
Mybatis首先去緩存中查詢結果集,若是沒有則查詢數據庫,若是有則從緩存取出返回結果集就不走數據庫。Mybatis內部存儲緩存使用一個HashMap,key爲hashCode+sqlId+Sql語句。value爲從查詢出來映射生成的java對象。
Mybatis的二級緩存即查詢緩存,它的做用域是一個mapper的namespace,即在同一個namespace中查詢sql能夠從緩存中獲取數據。二級緩存是能夠跨SqlSession的。
student(sno,sname,sage,ssex)學生表
course(cno,cname,tno) 課程表
sc(sno,cno,score) 成績表
teacher(tno,tname) 教師表
select a.sno from (select sno,score from sc where cno=1) a, (select sno,score from sc where cno=2) b where a.score>b.score and a.sno=b.sno
select a.sno as "學號", avg(a.score) as "平均成績" from (select sno,score from sc) a group by sno having avg(a.score)>60
select a.sno as 學號, b.sname as 姓名, count(a.cno) as 選課數, sum(a.score) as 總成績 from sc a, student b where a.sno = b.sno group by a.sno, b.sname 或者: selectstudent.sno as 學號, student.sname as 姓名, count(sc.cno) as 選課數, sum(score) as 總成績 from student left Outer join sc on student.sno = sc.sno group by student.sno, sname
select student.sno,student.sname from student where sno not in (select distinct(sc.sno) from sc,course,teacher where sc.cno=course.cno and teacher.tno=course.tno and teacher.tname='張三')
select sno, sname from student where sno in (select sno from sc where sc.cno = 1) and sno in (select sno from sc where sc.cno = 2) 或者: selectc.sno, c.sname from (select sno from sc where sc.cno = 1) a, (select sno from sc where sc.cno = 2) b, student c where a.sno = b.sno and a.sno = c.sno 或者: select student.sno,student.sname from student,sc where student.sno=sc.sno and sc.cno=1 and exists( select * from sc as sc_2 where sc_2.sno=sc.sno and sc_2.cno=2)
select a.sno, a.sname from student a, sc b where a.sno = b.sno and b.cno in (select c.cno from course c, teacher d where c.tno = d.tno and d.tname = '李四') 或者: select a.sno, a.sname from student a, sc b, (select c.cno from course c, teacher d where c.tno = d.tno and d.tname = '李四') e where a.sno = b.sno and b.cno = e.cno
select a.sno, a.sname from student a, (select sno, score from sc where cno = 1) b, (select sno, score from sc where cno = 2) c where b.score > c.score and b.sno = c.sno and a.sno = b.sno
select distinct a.sno, a.sname from student a, sc b where a.sno <> 1 and a.sno=b.sno and b.cno in (select cno from sc where sno = 1) 或者: select s.sno,s.sname from student s, (select sc.sno from sc where sc.cno in (select sc1.cno from sc sc1 where sc1.sno=1)and sc.sno<>1 group by sc.sno)r1 where r1.sno=s.sno
update sc set score = (select avg(sc_2.score) from sc sc_2 wheresc_2.cno=sc.cno) from course,teacher where course.cno=sc.cno and course.tno=teacher.tno andteacher.tname='王五'
delete sc from course, teacher where course.cno = sc.cno and course.tno = teacher.tno and tname = '王五'
insert sc select sno, 3, (select avg(score) from sc where cno = 2) from student where sno not in (select sno from sc where cno = 3)
select sno as 學號 ,max(case when cno = 1 then score end) AS 企業管理 ,max(case when cno = 2 then score end) AS 馬克思 ,max(case when cno = 3 then score end) AS UML ,max(case when cno = 4 then score end) AS 數據庫 ,max(case when cno = 5 then score end) AS 物理 ,count(cno) AS 課程數 ,avg(score) AS 平均分 FROM sc GROUP by sno ORDER by avg(score) DESC
SELECT t.cno AS 課程號, max(course.cname)AS 課程名, isnull(AVG(score),0) AS 平均成績, 100 * SUM(CASE WHEN isnull(score,0)>=60 THEN 1 ELSE 0 END)/count(1) AS 及格率 FROM sc t, course where t.cno = course.cno GROUP BY t.cno ORDER BY 及格率 desc
select avg(case when cno = 1 then score end) as 平均分1, avg(case when cno = 2 then score end) as 平均分2, avg(case when cno = 3 then score end) as 平均分3, avg(case when cno = 4 then score end) as 平均分4, 100 * sum(case when cno = 1 and score > 60 then 1 else 0 end) / sum(casewhen cno = 1 then 1 else 0 end) as 及格率1, 100 * sum(case when cno = 2 and score > 60 then 1 else 0 end) / sum(casewhen cno = 2 then 1 else 0 end) as 及格率2, 100 * sum(case when cno = 3 and score > 60 then 1 else 0 end) / sum(casewhen cno = 3 then 1 else 0 end) as 及格率3, 100 * sum(case when cno = 4 and score > 60 then 1 else 0 end) / sum(casewhen cno = 4 then 1 else 0 end) as 及格率4 from sc
select max(c.tname) as 教師, max(b.cname) 課程, avg(a.score) 平均分 from sc a, course b, teacher c where a.cno = b.cno and b.tno = c.tno group by a.cno order by 平均分 desc 或者: select r.tname as '教師',r.rname as '課程' , AVG(score) as '平均分' from sc, (select t.tname,c.cno as rcso,c.cname as rname from teacher t ,course c where t.tno=c.tno)r where sc.cno=r.rcso group by sc.cno,r.tname,r.rname order by AVG(score) desc
select top 6 max(a.sno) 學號, max(b.sname) 姓名, max(case when cno = 1 then score end) as 企業管理, max(case when cno = 2 then score end) as 馬克思, max(case when cno = 3 then score end) as UML, max(case when cno = 4 then score end) as 數據庫, avg(score) as 平均分 from sc a, student b where a.sno not in (select top 2 sno from sc where cno = 1 order by score desc) and a.sno not in (select top 2 sno from sc where cno = 2 order by scoredesc) and a.sno not in (select top 2 sno from sc where cno = 3 order by scoredesc) and a.sno not in (select top 2 sno from sc where cno = 4 order by scoredesc) and a.sno = b.sno group by a.sno
線程是操做系統可以進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運做單位。程序員能夠經過它進行多處理器編程,能夠使用多線程對運算密集型任務提速。
線程是進程的子集,一個進程能夠有不少線程,每條線程並行執行不一樣的任務。不一樣的進程使用不一樣的內存空間,而全部的線程共享一片共同的內存空間。每一個線程都擁有單獨的棧內存用來存儲本地數據。
兩種方式:java.lang.Thread 類的實例就是一個線程可是它須要調用java.lang.Runnable接口來執行,因爲線程類自己就是調用的Runnable接口因此你能夠繼承java.lang.Thread 類或者直接調用Runnable接口來重寫run()方法實現線程。
1.volatile
它所修飾的變量不保留拷貝,直接訪問主內存中的。
在Java內存模型中,有主內存,每一個線程也有本身的內存(例如寄存器、棧內存)。爲了性能,一個線程會在本身的內存中保持要訪問的變量的副本。這樣就會出現同一個變量在某個瞬間,在一個線程內存中的值能夠與另外一個線程內存中的值,或者主內存中的值不一致的狀況。一個變量聲明爲volatile,就意味着這個變量是隨時會被其它線程修改的,所以不能將它緩存在線程內存中。
2.synchronized
當它用來修飾一個方法或者一個代碼塊的時候,可以保證在同一時刻最多隻有一個線程執行該段代碼。
a、當兩個併發線程訪問同一個對象object中的synchronized(this)同步代碼塊時,一個時間內只能有一個線程獲得執行。另外一個線程必須等待當前線程執行完這個代碼塊之後才能執行該代碼塊。
b、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另外一個線程仍然能夠訪問該object中的非synchronized(this)同步代碼塊。
c、尤爲關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其餘線程對object中全部其它synchronized(this)同步代碼塊的訪問將被阻塞。
d、當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就得到了這個object的對象鎖。結果,其它線程對該object對象全部同步代碼部分的訪問都被暫時阻塞。
e、以上規則對其它對象鎖一樣適用。
在Java程序中新建一個線程時,它的狀態是New。當調用線程的start()方法時,狀態被改變爲Runnable。線程調度器會爲Runnable線程池中的線程分配CPU時間而且將它們的狀態改變爲Running。其餘的線程狀態還有Waiting,Blocked 和Dead。
每個線程都是有優先級的,通常來講,高優先級的線程在運行時會具備優先權,但這依賴於線程調度的實現,這個實現是和操做系統相關的(OS dependent)。咱們能夠定義線程的優先級,可是這並不能保證高優先級的線程會在低優先級的線程前執行。線程優先級是一個int變量(從1-10),1表明最低優先級,10表明最高優先級。
死鎖是指兩個以上的線程永遠阻塞的狀況,這種狀況的產生至少須要兩個以上的線程和兩個以上的資源。
分析死鎖,咱們須要查看Java應用程序的線程轉儲。須要找出那些狀態爲BLOCKED的線程和它們等待的資源。每一個資源都有一個惟一的id,用這個id咱們能夠找出哪些線程已經擁有了它的對象鎖。
避免嵌套鎖,只在須要的地方使用鎖和避免無限期等待是避免死鎖的一般辦法。
若是代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。若是每次運行結果和單線程運行的結果是同樣的,並且其餘的變量的值也和預期的是同樣的,就是線程安全的。一個線程安全的計數器類的同一個實例對象在被多個線程使用的狀況下也不會出現計算失誤。很顯然你能夠將集合類分紅兩組,線程安全和非線程安全的。Vector 是用同步方法來實現線程安全的, 而和它類似的ArrayList不是線程安全的。
Java提供了很豐富的API但沒有爲中止線程提供API。JDK 1.0原本有一些像stop(), suspend() 和 resume()的控制方法可是因爲潛在的死鎖威脅所以在後續的JDK版本中他們被棄用了,以後Java API的設計者就沒有提供一個兼容且線程安全的方法來中止一個線程。當run() 或者 call() 方法執行完的時候線程會自動結束,若是要手動結束一個線程,你能夠用volatile 布爾變量來退出run()方法的循環或者是取消任務來中斷線程。
ThreadLocal用於建立線程的本地變量,一個對象的全部線程會共享它的全局變量,因此這些變量不是線程安全的,這時能夠使用同步技術。可是當不想使用同步的時候,能夠選擇ThreadLocal變量。
每一個線程都會擁有自身的ThreadLocal變量,它們能夠使用get()\set()方法去獲取他們的默認值或者在線程內部改變他們的值。ThreadLocal實例一般是但願它們同線程狀態關聯起來是private static屬性。
Thread.sleep()使當前線程在指定的時間處於「非運行」(Not Runnable)狀態。線程一直持有對象的監視器。好比一個線程當前在一個同步塊或同步方法中,其它線程不能進入該塊或方法中。若是另外一線程調用了interrupt()方法,它將喚醒那個「睡眠的」線程。
注意:sleep()是一個靜態方法。這意味着只對當前線程有效,一個常見的錯誤是調用t.sleep(),(這裏的t是一個不一樣於當前線程的線程)。即使是執行t.sleep(),也是當前線程進入睡眠,而不是t線程。t.suspend()是過期的方法,使用suspend()致使線程進入停滯狀態,該線程會一直持有對象的監視器,suspend()容易引發死鎖問題。
Object.wait()使當前線程出於「不可運行」狀態,和sleep()不一樣的是wait是object的方法而不是thread。調用object.wait()時,線程先要獲取這個對象的對象鎖,當前線程必須在鎖對象保持同步,把當前線程添加到等待隊列中,隨後另外一線程能夠同步同一個對象鎖來調用object.notify(),這樣將喚醒原來等待中的線程,而後釋放該鎖。基本上wait()/notify()與sleep()/interrupt()相似,只是前者須要獲取對象鎖。
線程餓死,指當全部線程阻塞、或者因爲須要的資源無效而不能處理,不存在非阻塞線程使資源可用的狀況。
JavaAPI中線程活鎖可能發生在如下情形:
1.當全部線程在程序中執行Object.wait(0),參數爲0的wait方法。程序將發生活鎖直到在相應的對象上有線程調用Object.notify()或者Object.notifyAll()。
2.當全部線程卡在無限循環中。
同步塊是更好的選擇,由於它不會鎖住整個對象(固然也可讓它鎖住整個對象)。同步方法會鎖住整個對象,哪怕這個類中有多個不相關聯的同步塊,這一般會致使他們中止執行並須要等待得到這個對象上的鎖。
泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,即所操做的數據類型被指定爲一個參數。
好處:
1.類型安全,提供編譯期間的類型檢測
2.先後兼容
3.泛化代碼,代碼能夠更多的重複利用
4.性能較高,用GJ(泛型Java : Genericity Java)編寫的代碼能夠爲Java編譯器和虛擬機帶來更多的類型信息,這些信息對Java程序作進一步優化提供條件。
1.類型檢查:在生成字節碼以前提供類型檢查
2.類型擦除:全部類型參數都用它們的限定類型替換,包括類、變量和方法
3.若是類型擦除和多態性發生了衝突時,則在子類中生成橋方法解決
4.若是調用泛型方法的返回類型被擦除,則在調用該方法時插入強制類型轉換
類型擦除:全部類型參數都用他們的限定類型替換 ,好比:
T -> Object ? extends BaseClass -> BaseClass;
如何工做:
泛型是經過類型擦除來實現的,編譯器在編譯時擦除了全部類型相關的信息,因此在運行時不存在任何類型相關的信息。例如 List<String>在運行時僅用一個List來表示。這樣作的目的,是確保能和Java 5以前的版本開發二進制類庫進行兼容。你沒法在運行時訪問到類型參數,由於編譯器已經把泛型類型轉換成了原始類型。根據你對這個泛型問題的回答狀況,你會獲得一些後續提問,好比爲何泛型是由類型擦除來實現的或者給你展現一些會致使編譯器出錯的錯誤泛型代碼。
不能夠,由於List<Object>能夠存儲任何類型的對象包括String, Integer等等,而List<String>卻只能用來存儲String s。
List<Object> objectList; List<String> stringList; objectList = stringList; //compilation error incompatible types
1.根據須要選擇正確的集合類型。好比,若是指定了大小,咱們會選用Array而非ArrayList(Array不支持泛型,平常使用推薦List)。若是咱們想根據插入順序遍歷一個Map,咱們須要使用TreeMap。若是咱們不想重複,咱們應該使用Set。
2.一些集合類容許指定初始容量,因此若是咱們可以估計到存儲元素的數量,咱們能夠使用它,就避免了從新哈希或大小調整。
3.基於接口編程,而非基於實現編程,它容許咱們後來輕易地改變實現。
4.老是使用類型安全的泛型,避免在運行時出現ClassCastException。
5.使用JDK提供的不可變類做爲Map的key,能夠避免本身實現hashCode()和equals()。
6.儘量使用Collections工具類以及Apache commons工具包,或者獲取只讀、同步或空的集合,而非編寫本身的實現。它將會提供代碼重用性,它有着更好的穩定性和可維護性。
Java內存模型規定和指引Java程序在不一樣的內存架構、CPU和操做系統間有肯定性的行爲。它在多線程的狀況下尤爲重要。Java內存模型對一個線程所作的變更能被其它線程可見提供了保證,它們之間是先行發生原則。這個關係定義了一些規則,編譯併發編程的代碼實現。好比,先行發生原則確保了:
線程內的代碼可以按前後順序執行,即程序次序規則。
對於同一個鎖,一個解鎖操做必定要發生在時間上後發生的另外一個鎖定操做以前,即管程鎖定規則。
前一個對volatile的寫操做在後一個volatile的讀操做以前,即volatile變量規則。
一個線程內的任何操做必須在這個線程的start()調用以後,即線程啓動規則。
一個線程的全部操做都會在線程終止以前,即線程終止規則。
一個對象的終結操做必須在這個對象構造完成以後,即對象終結原則。
同步集合與併發集合都爲多線程和併發提供了合適的線程安全的集合,不過併發集合的可擴展性更高。在Java1.5以前程序員們只有同步集合來用且在多線程併發的時候會致使爭用,阻礙了系統的擴展性。Java1.5提供了併發集合像ConcurrentHashMap,不只提供線程安全還用鎖分離和內部分區等現代技術提供了可擴展性。
無論是同步集合仍是併發集合他們都支持線程安全,他們之間主要的區別體如今性能和可擴展性,還有他們如何實現的線程安全上。
同步HashMap, Hashtable, HashSet, Vector, ArrayList 相比他們併發的實現(ConcurrentHashMap, CopyOnWriteArrayList, CopyOnWriteHashSet)會慢得多。主要緣由是鎖,同步集合會把整個Map或List鎖起來,而併發集合不會。併發集合實現線程安全經過使用鎖剝離等新手段。
好比ConcurrentHashMap會把整個Map劃分紅幾個片斷,只對相關的幾個片斷上鎖,同時容許多線程訪問其餘未上鎖的片斷。
一樣的,CopyOnWriteArrayList容許多個線程以非同步的方式讀,當有線程寫的時候它會將整個List複製一個副本給它。
若是在讀多寫少這種對併發集合有利的條件下使用併發集合,這會比使用同步集合更具備可伸縮性。
建立線程要花費昂貴的資源和時間,若是任務來了才建立線程那麼響應時間會變長,並且一個進程能建立的線程數有限。爲了不這些問題,在程序啓動的時候就建立若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工做線程。從JDK1.5開始,Java API提供了Executor框架讓你能夠建立不一樣的線程池。好比單線程池,每次處理一個任務;數目固定的線程池或者是緩存線程池(一個適合不少生存期短的任務的程序的可擴展線程池)。
線程池的做用,就是在調用線程的時候初始化必定數量的線程,有線程過來的時候,先檢測初始化的線程還有空的沒有,沒有就再看當前運行中的線程數是否是已經達到了最大數,若是沒有,就新分配一個線程去處理。
線程池的優勢就是能夠管理線程,有一個高度中樞,這樣程序纔不會亂,保證系統不會由於大量的併發而由於資源不足掛掉。
活鎖:一個線程有時會響應其它線程的活動。若是其餘線程也會響應另外一個線程的活動,那麼就有可能發生活鎖。同死鎖同樣,發生活鎖的線程沒法繼續執行。然而線程並無阻塞——他們在忙於響應對方沒法恢復工做。這就至關於兩個在走廊相遇的人:甲向他本身的左邊靠想讓乙過去,而乙向他的右邊靠想讓甲過去。可見他們阻塞了對方。甲向他的右邊靠,而乙向他的左邊靠,他們仍是阻塞了對方。
死鎖:兩個或更多線程阻塞着等待其它處於死鎖狀態的線程所持有的鎖。死鎖一般發生在多個線程同時但以不一樣的順序請求同一組鎖的時候,死鎖會讓你的程序掛起沒法完成任務。
死鎖的發生必須知足如下四個條件:
互斥條件:一個資源每次只能被一個線程使用
請求與保持條件:一個線程因請求資源而阻塞時,對已得到的資源保持不放
不剝奪條件:線程已得到的資源,在未使用完以前,不能強行剝奪
循環等待條件:若干線程之間造成一種首尾相接的循環等待資源關係
三種用於避免死鎖的技術:
加鎖順序(線程按照必定的順序加鎖)
加鎖時限(線程嘗試獲取鎖的時候加上必定的時限,超過期限則放棄對該鎖的請求,並釋放本身佔有的鎖)
死鎖檢測
1.notify()和notifyAll()都是Object對象用於通知處在等待該對象的線程的方法。
2.void notify() :喚醒一個正在等待該對象的線程。
3.void notifyAll() :喚醒全部正在等待該對象的線程。
二者的最大區別在於:
notifyAll 使全部原來在該線程上等待被notify的線程通通退出wait的狀態,變成等待該對象上的鎖,一旦該對象被解鎖,它們將會去競爭。
notify 只是選擇一個wait狀態線程進行通知,並使它得到該對象上的鎖,但不驚動其餘一樣在等待被該對象notify的線程,當第一個線程運行完畢之後釋放對象上的鎖,此時若是該對象沒有再次使用notify語句,即便該對象已經空閒,其它wait狀態等待的線程因爲沒有獲得該對象的通知,繼續處在wait狀態,直到這個對象發出一個notify或notifyAll,它們等待的是被notify或notifyAll,而不是鎖。
java.util.concurrent.Lock中的Lock框架是鎖的一個抽象,它容許把鎖的實現做爲Java類,而不是做爲語言的特性來實現。這爲Lock的多種實現提供了空間,不一樣的實現能夠有不一樣的調度算法、性能特性或者鎖語義。
ReentrantLock類實現了Lock,它擁有與 synchronized 相同的併發行和內存語義,可是添加了相似鎖投票、定時鎖等候和可中斷鎖等候的特性。此外,它還提供了在激烈爭用狀況下更佳的性能。(換句話說,當許多線程都想訪問共享資源時,JVM能夠花更少的時間來調度線程,把更多時間用在執行線程上。)
ReentrantLock意味着什麼呢?它有一個與鎖相關的獲取計數器,若是擁有鎖的某個線程再次獲得鎖,那麼獲取計數器就加一,而後鎖須要被釋放兩次才能得到真正釋放。這模仿了synchronized的語義:若是線程進入由線程已經擁有的監控器保護的synchronized塊,就容許線程繼續執行,當線程退出第二個(或者後續)synchronized塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個synchronized塊時,才釋放鎖。
讀寫鎖能夠用於 「多讀少寫」 的場景,讀寫鎖支持多個讀操做併發執行,寫操做只能由一個線程來操做。
ReadWriteLock對向數據結構相對不頻繁地寫入,可是有多個任務要常常讀取這個數據結構的這類狀況進行了優化。ReadWriteLock使得你能夠同時有多個讀取者,只要它們都不試圖寫入便可。若是寫鎖已經被其餘任務持有,那麼任何讀取者都不能訪問,直至這個寫鎖被釋放爲止。
ReadWriteLock對程序性能的提升主要受制於以下幾個因素:
1.數據被讀取的頻率與被修改的頻率相比較的結果
2.讀取和寫入的時間
3.有多少線程競爭
4.是否在多處理機器上運行
概念:
棧(stack)是爲了執行線程留出的內存空間。當函數被調用的時候,棧頂爲局部變量和一些「簿記(bookkeeping)」數據預留塊。當函數執行完畢,塊就沒有了,可能在下次的函數調用的時候再被使用。棧一般用後進先出的方式預留空間;所以最近的保留塊一般最早被釋放。這樣作能夠使跟蹤堆棧變得簡單;從棧中釋放塊只不過是指針的偏移而已。
堆(heap)是爲動態分配預留的內存空間。和棧不同,從堆上分配和從新分配塊沒有固定模式;你能夠在任什麼時候候分配和釋放它。這樣使得跟蹤哪部分堆已經被分配和被釋放變的異常複雜;有許多定製的堆分配策略來爲不一樣的使用模式下調整堆的性能。
區別:
內存分配:
棧:由編譯器自動分配和釋放,存放函數的參數、局部變量、臨時變量、函數返回地址等。
堆:通常人爲分配和釋放,對Java而言是由系統釋放回收,但對於C++等,必須手動釋放,若是沒有手動釋放會引發內存泄漏。
系統響應:
棧:只要棧的剩餘空間大於所申請的空間,系統將爲程序提供內存,不然將報異常提示棧溢出。
堆:在記錄空閒內存地址的鏈表中尋找一個空間大於所申請空間的堆節點,而後將該節點從空閒節點鏈表中刪除,並將該節點的空間分配給程序。
大小限制:
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。即棧頂的地址和棧的最大容量是系統預先規定好的,在 windows下,棧的大小是2M,若是申請的空間超過棧的剩餘空間時,將提示overflow。所以,能從棧得到的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是因爲系統是用鏈表來存儲的空閒內存地址的,天然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。
結論:堆得到的空間比較靈活,也比較大。
分配效率:
棧:由系統自動分配,速度較快,沒法人爲控制。
堆:由new分配的內存,通常速度比較慢,並且容易產生內存碎片,不過用起來最方便。
存儲內容:
棧:在棧中,第一個進棧的是主函數下一條指令的地址,而後是函數的各個參數,在大多數編譯器中,參數是由右向左入棧,而後是函數中的局部變量。注意,靜態變量不入棧。
堆:通常在堆的頭部用一個字節存放堆的大小,具體內容受人爲控制。
比較:
1.穩定性比較
插入排序、冒泡排序、二叉樹排序、二路歸併排序及其它線形排序是穩定的
選擇排序、希爾排序、快速排序、堆排序是不穩定的
2.時間複雜度比較
插入排序、冒泡排序、選擇排序的時間複雜度爲 O(n2)
其它非線形排序的時間複雜度爲 O(nlog2n)
線形排序的時間複雜度爲O(n)
3.輔助空間的比較
線形排序、二路歸併排序的輔助空間爲O(n)
其它排序的輔助空間爲O(1)
4.其它比較
*插入、冒泡排序的速度較慢,但參加排序的序列局部或總體有序時,這種排序能達到較快的速度,可是在這種狀況下,快速排序反而慢了。
*當n較小時,對穩定性不做要求時宜用選擇排序,對穩定性有要求時宜用插入或冒泡排序。
*若待排序的記錄的關鍵字在一個明顯有限範圍內時,且空間容許是用桶排序。
*當n較大時,關鍵字元素比較隨機,對穩定性沒要求宜用快速排序。
*當n較大時,關鍵字元素可能出現自己是有序的,對穩定性有要求時,空間容許的狀況下宜用歸併排序。
*當n較大時,關鍵字元素可能出現自己是有序的,對穩定性沒有要求時宜用堆排序。
常見的排序算法:
選擇排序
public class SelectionSort { public void selectionSort(int[] array) { int temp; for (int i = 0; i < array.length - 1; i++) { for (int j = i + 1; j <= array.length - 1; j++) { if (array[i] > array[j]) { // 注意和冒泡排序的區別,這裏是i和j比較。 temp = array[i]; array[i] = array[j]; array[j] = temp; } } // 打印每趟排序結果 for (int m = 0; m <= array.length - 1; m++) { System.out.print(array[m] + "\t"); } System.out.println(); } } public static void main(String[] args) { SelectionSort selectionSort = new SelectionSort(); int[] array = { 5, 69, 12, 3, 56, 789, 2, 5648, 23 }; selectionSort.selectionSort(array); for (int m = 0; m <= array.length - 1; m++) { System.out.print(array[m] + "\t"); } } }
插入排序
public class InsertSort { public void insertSort(int[] array, int first, int last) { int temp, i, j; for (i = first + 1; i <= last - 1; i++) { temp = array[i]; j = i - 1; while (j >= first && array[j] > temp) { array[j + 1] = array[j]; j--; } array[j + 1] = temp; // 打印每次排序結果 for (int m = 0; m <= array.length - 1; m++) { System.out.print(array[m] + "\t"); } System.out.println(); } } public static void main(String[] args) { InsertSort insertSort = new InsertSort(); int[] array = { 5, 69, 12, 3, 56, 789, 2, 5648, 23 }; insertSort.insertSort(array, 0, array.length); for (int i = 0; i <= array.length - 1; i++) { System.out.print(array[i] + "\t"); } } }
快速排序
public class QuickSort { public int partition(int[] sortArray, int low, int height) { int key = sortArray[low]; while (low < height) { while (low < height && sortArray[height] >= key) height--; sortArray[low] = sortArray[height]; while (low < height && sortArray[low] <= key) low++; sortArray[height] = sortArray[low]; } sortArray[low] = key; // 打印每次排序結果 for (int i = 0; i <= sortArray.length - 1; i++) { System.out.print(sortArray[i] + "\t"); } System.out.println(); return low; } public void sort(int[] sortArray, int low, int height) { if (low < height) { int result = partition(sortArray, low, height); sort(sortArray, low, result - 1); sort(sortArray, result + 1, height); } } public static void main(String[] args) { QuickSort quickSort = new QuickSort(); int[] array = { 5, 69, 12, 3, 56, 789, 2, 5648, 23 }; for (int i = 0; i <= array.length - 1; i++) { System.out.print(array[i] + "\t"); } System.out.println(); quickSort.sort(array, 0, 8); for (int i = 0; i <= array.length - 1; i++) { System.out.print(array[i] + "\t"); } } }
希爾排序
public class ShellSort { public void shellSort(int[] array, int n) { int i, j, gap; int temp; for (gap = n / 2; gap > 0; gap /= 2) { for (i = gap; i < n; i++) { for (j = i - gap; j >= 0 && array[j] > array[j + gap]; j -= gap) { temp = array[j]; array[j] = array[j + gap]; array[j + gap] = temp; } // 打印每趟排序結果 for (int m = 0; m <= array.length - 1; m++) { System.out.print(array[m] + "\t"); } System.out.println(); } } } public static void main(String[] args) { ShellSort shellSort = new ShellSort(); int[] array = { 5, 69, 12, 3, 56, 789, 2, 5648, 23 }; shellSort.shellSort(array, array.length); for (int m = 0; m <= array.length - 1; m++) { System.out.print(array[m] + "\t"); } } }
ArithmeticException, 數學運算異常,eg:整數除以零
ArrayStoreException, 數組保存異常,eg:數組類型不匹配
BufferOverflowException, 緩衝區上溢異常,eg:ByteBuffer.allocate(2);分配的兩個字節而put了三個
BufferUnderflowException, 緩衝區下溢異常,eg:ByteBuffer中保存了一個字節,而請求兩個字節
ClassCastException, 類轉換異常
ConcurrentModificationException, 對Vector、ArrayList迭代同時對其修改拋該異常,緣由:成員內部類中成員變量更新不及時,參見:https://www.cnblogs.com/dolphin0520/p/3933551.html
IllegalArgumentException, 非法參數異常
IllegalMonitorStateException,
拋出這個異常代表線程嘗試等待一個對象的監視器或者去通知其餘正在等待這個對象監視器的線程時,可是沒有擁有這個監視器的全部權。
1>當前線程不含有當前對象的鎖資源的時候,調用obj.wait()方法; 2>當前線程不含有當前對象的鎖資源的時候,調用obj.notify()方法。 3>當前線程不含有當前對象的鎖資源的時候,調用obj.notifyAll()方法。
IndexOutOfBoundsException, 角標越界異常
MissingResourceException, 找不到指定的配置文件
NegativeArraySizeException, 建立大小爲負的數組,拋出該異常
NoSuchElementException, 多見流操做,hasNext()判斷後再next()
NullPointerException, 空指針異常
UndeclaredThrowableException, 使用jdk動態代理接口時,
若方法執行過程當中拋出了受檢異常但方法簽名又沒有聲明該異常時則會被代理 類包裝成UndeclaredThrowableException拋出
UnmodifiableSetException, 當因爲設置不可修改而沒法執行請求的操做時,拋出該異常。
UnsupportedOperationException 常見數組轉集合後,給集合add/remove時報錯。
這是由於Arrays.asList(String[] aa)轉換的類型爲其內部類ArrayList,不包含add/remove
超鍵:在關係中能惟一標識元組的屬性集稱爲關係模式的超鍵。一個屬性能夠爲做爲一個超鍵,多個屬性組合在一塊兒也能夠做爲一個超鍵。超鍵包含候選鍵和主鍵。
候選鍵:是最小超鍵,即沒有冗餘元素的超鍵。
主鍵:數據庫表中對儲存數據對象予以惟一和完整標識的數據列或屬性的組合。一個數據列只能有一個主鍵,且主鍵的取值不能缺失,即不能爲空值(Null)。
外鍵:在一個表中存在的另外一個表的主鍵稱此表的外鍵。
事務:就是被綁定在一塊兒做爲一個邏輯工做單元的 SQL 語句分組,若是任何一個語句操做失敗那麼整個操做就被失敗,之後操做就會回滾到操做前狀態,或者是上有個節點。爲了確保要麼執行,要麼不執行,就能夠使用事務。要將有組語句做爲事務考慮,就須要經過 ACID 測試,即原子性,一致性,隔離性和持久性。
鎖:在全部的 DBMS 中,鎖是實現事務的關鍵,鎖能夠保證事務的完整性和併發性。與現實生活中鎖同樣,它能夠使某些數據的擁有者,在某段時間內不能使用某些數據或數據結構。固然鎖還分級別的。
原子性:整個事務中的全部操做,要麼所有完成,要麼所有不完成,不可能停滯在中間某個環節。事務在執行過程當中發生錯誤,會被回滾(Rollback)到事務開始前的狀態。
一致性:在事務開始以前和事務結束之後,數據庫的完整性約束沒有被破壞。
隔離性:隔離狀態執行事務,使其好像是系統在給定時間內執行的惟一操做。若是有兩個事務,運行在相同的時間內,執行相同的功能,事務的隔離性將確保每一個事務在系統中認爲只有該事務在使用系統。這種屬性有時成爲串行化,爲了防止事務操做間的混淆,必須串行化或序列化請求,使得在同一時間僅有一個請求用於同一數據。
持久性:在事務完成之後,該事務對數據庫所作的更改便保存在數據庫之中,並不會被回滾。
視圖是一種虛擬的表,具備和物理表相同的功能。能夠對視圖進行增,改,查,操做,試圖一般是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得咱們獲取數據更容易,相比多表查詢。
以下兩種場景通常會使用到視圖:
(1)不但願訪問者獲取整個表的信息,只暴露部分字段給訪問者,因此就建一個虛表,就是視圖。
(2)查詢的數據來源於不一樣的表,而查詢者但願以統一的方式查詢,這樣也能夠創建一個視圖,把多個表查詢結果聯合起來,查詢者只須要直接從視圖中獲取數據,沒必要考慮數據來源於不一樣表所帶來的差別。
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。索引的實現一般使用B樹及其變種B+樹。
在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就能夠在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
爲表設置索引要付出代價的:一是增長了數據庫的存儲空間,二是在插入和修改數據時要花費較多的時間(由於索引也要隨之變更)。
建立索引能夠大大提升系統的性能(優勢):
第一,經過建立惟一性索引,能夠保證數據庫表中每一行數據的惟一性。
第二,能夠大大加快數據的檢索速度,這也是建立索引的最主要的緣由。
第三,能夠加速表和表之間的鏈接,特別是在實現數據的參考完整性方面特別有意義。
第四,在使用分組和排序子句進行數據檢索時,一樣能夠顯著減小查詢中分組和排序的時間。
第五,經過使用索引,能夠在查詢的過程當中,使用優化隱藏器,提升系統的性能。
增長索引也有許多不利的方面:
第一,建立索引和維護索引要耗費時間,這種時間隨着數據量的增長而增長。
第二,索引須要佔物理空間,除了數據表佔數據空間以外,每個索引還要佔必定的物理空間,若是要創建聚簇索引,那麼須要的空間就會更大。
第三,當對錶中的數據進行增長、刪除和修改的時候,索引也要動態的維護,這樣就下降了數據的維護速度。
索引是創建在數據庫表中的某些列的上面。在建立索引的時候,應該考慮在哪些列上能夠建立索引,在哪些列上不能建立索引。
通常來講,應該在這些列上建立索引:
(1)在常常須要搜索的列上,能夠加快搜索的速度;
(2)在做爲主鍵的列上,強制該列的惟一性和組織表中數據的排列結構;
(3)在常常用在鏈接的列上,這些列主要是一些外鍵,能夠加快鏈接的速度;
(4)在常常須要根據範圍進行搜索的列上建立索引,由於索引已經排序,其指定的範圍是連續的;
(5)在常常須要排序的列上建立索引,由於索引已經排序,這樣查詢能夠利用索引的排序,加快排序查詢時間;
(6)在常用在WHERE子句中的列上面建立索引,加快條件的判斷速度。
一樣,對於有些列不該該建立索引:
第一,對於那些在查詢中不多使用或者參考的列不該該建立索引。這是由於,既然這些列不多使用到,所以有索引或者無索引,並不能提升查詢速度。相反,因爲增長了索引,反而下降了系統的維護速度和增大了空間需求。
第二,對於那些只有不多數據值的列也不該該增長索引。這是由於,因爲這些列的取值不多,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比例,即須要在表中搜索的數據行的比例很大。增長索引,並不能明顯加快檢索速度。
第三,對於那些定義爲text, image和bit數據類型的列不該該增長索引。這是由於,這些列的數據量要麼至關大,要麼取值不多。
第四,當修改性能遠遠大於檢索性能時,不該該建立索引。這是由於,修改性能和檢索性能是互相矛盾的。當增長索引時,會提升檢索性能,可是會下降修改性能。當減小索引時,會提升修改性能,下降檢索性能。所以,當修改性能遠遠大於檢索性能時,不該該建立索引。
(1) DELETE語句執行刪除的過程是每次從表中刪除一行,而且同時將該行的刪除操做做爲事務記錄在日誌中保存以便進行進行回滾操做。TRUNCATE TABLE 則一次性地從表中刪除全部的數據並不把單獨的刪除操做記錄記入日誌保存,刪除行是不能恢復的。而且在刪除的過程當中不會激活與表有關的刪除觸發器。執行速度快。
(2) 表和索引所佔空間。當表被TRUNCATE 後,這個表和索引所佔用的空間會恢復到初始大小,而DELETE操做不會減小表或索引所佔用的空間。drop語句將表所佔用的空間全釋放掉。
(3) 通常而言,drop > truncate > delete
(4) 應用範圍。TRUNCATE 只能對TABLE;DELETE能夠是table和view
(5) TRUNCATE 和DELETE只刪除數據,而DROP則刪除整個表(結構和數據)。
(6) truncate與不帶where的delete :只刪除數據,而不刪除表的結構(定義)truncate語句將刪除表的結構被依賴的約束(constrain),觸發器(trigger)索引(index);依賴於該表的存儲過程/函數將被保留,但其狀態會變爲:invalid(無效的)。
(7) delete語句爲DML(data maintain Language),這個操做會被放到 rollback segment中,事務提交後才生效。若是有相應的 tigger,執行的時候將被觸發。
(8) truncate、drop是DLL(data define language),操做當即生效,原數據不放到 rollback segment中,不能回滾。
(9) 在沒有備份狀況下,謹慎使用 drop 與 truncate。要刪除部分數據行採用delete且注意結合where來約束影響範圍。回滾段要足夠大。要刪除表用drop;若想保留表而將表中數據刪除,若是於事務無關,用truncate便可實現。若是和事務有關,或須要觸發trigger,仍是用delete。
(10) Truncate table 表名 速度快,並且效率高,由於:
truncate table 在功能上與不帶 WHERE 子句的 DELETE 語句相同:兩者均刪除表中的所有行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日誌資源少。DELETE 語句每次刪除一行,並在事務日誌中爲所刪除的每行記錄一項。TRUNCATE TABLE 經過釋放存儲表數據所用的數據頁來刪除數據,而且只在事務日誌中記錄頁的釋放。
(11) TRUNCATE TABLE 刪除表中的全部行,但表結構及其列、約束、索引等保持不變。新行標識所用的計數值重置爲該列的種子。若是想保留標識計數值,請改用 DELETE。若是要刪除表定義及其數據,請使用 DROP TABLE 語句。
(12) 對於由 FOREIGN KEY 約束引用的表,不能使用 TRUNCATE TABLE,而應使用不帶 WHERE 子句的 DELETE 語句。因爲 TRUNCATE TABLE 不記錄在日誌中,因此它不能激活觸發器。
一、Read uncommitted(讀未提交)就是一個事務能夠讀取另外一個未提交事務的數據。
二、Read committed(讀提交)就是一個事務要等另外一個事務提交後才能讀取數據。
三、Repeatable read(重複讀)就是在開始讀取數據(事務開啓)時,再也不容許修改操做。
四、Serializable(序列化)在該級別下,事務串行化順序執行,能夠避免髒讀、不可重複讀與幻讀。是最高的事務隔離級別,可是這種事務隔離級別效率低下,比較耗數據庫性能,通常不使用。
事務的做用就是保證數據的一致性、完整性。事務隔離級別越高,在併發下會產生的問題就越少,但同時付出的性能消耗也將越大,所以不少時候必須在併發性和性能之間作一個權衡。因此設立了幾種事務隔離級別,以便讓不一樣的項目能夠根據本身項目的併發狀況選擇合適的事務隔離級別,對於在事務隔離級別以外會產生的併發問題,在代碼中作補償。
MySQL支持單向、異步複製,複製過程當中一個服務器充當主服務器,而一個或多個其它服務器充當從服務器。
MySQL複製是基於主服務器在二進制日誌中跟蹤全部對數據庫的更改。所以,要進行復制,必須在服務器上啓用二進制日誌。每一個從服務器從主服務器接收主服務器已經記錄到日誌的數據。
當一個從服務器鏈接主服務器時,它通知主服務器從服務器在日誌中讀取的最後一次成功更新的位置。從服務器接收從那時起發生的任何更新;並在本機上執行相同的更新。而後封鎖並等待主服務器通知新的更新。從服務器執行備份不會干擾主服務器,在備份過程當中主服務器能夠繼續處理更新。