下面是java的一些面試點,主要是基礎知識。java
檢查式異常:咱們常常遇到的IO異常及sql異常就屬於檢查式異常。對於這種異常,java編譯器要求咱們必須對出現的這些異常進行catch 因此 面對這種異常無論咱們是否願意,只能本身去寫一堆catch來捕捉這些異常。程序員
運行時異常:咱們能夠不處理。當出現這樣的異常時,老是由虛擬機接管。好比:咱們歷來沒有人去處理過NullPointerException異常,它就是運行時異常,而且這種異常仍是最多見的異常之一。面試
RuntimeExecption在java.lang包下,ajax
ClassCastException(類轉換異常)算法
IndexOutOfBoundsException(數組越界)spring
NullPointerException(空指針)sql
ArrayStoreException(數據存儲異常,操做數組時類型不一致)數據庫
還有IO操做的BufferOverflowException異常編程
能夠,可是一個文件中只能有一個public類,而且此public類必須與文件名相同。
抽象
抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。
繼承數組
類的重用。一個新類能夠從現有的類中派生,這個過程稱爲類繼承。派生類能夠從它的基類那裏繼承方法和實例變量,而且類能夠修改或增長新的方法使之更適合特殊的須要,提升代碼的重用行。
封裝
封裝是把數據和過程(對數據的操做)包圍起來,隱藏內部的實現細節,對數據的訪問只能經過已定義的方法 。
多態
多態性是指容許不一樣類的對象對同一消息做出響應。
AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。
AOP、OOP在字面上雖然很是相似,但倒是面向不一樣領域的兩種設計思想。
OOP(面向對象編程)針對業務處理過程的實體及其屬性和行爲進行抽象封裝,以得到更加清晰高效的邏輯單元劃分。
而AOP則是針對業務處理過程當中的切面進行提取,它所面對的是處理過程當中的某個步驟或階段,以得到邏輯過程當中各部分之間低耦合性的隔離效果。這兩種設計思想在目標上有着本質的差別。
上面的陳述可能過於理論化,舉個簡單的例子,對於「僱員」這樣一個業務實體進行封裝,天然是OOP/OOD的任務,咱們能夠爲其創建一個「Employee」類,並將「僱員」相關的屬性和行爲封裝其中。而用AOP設計思想對「僱員」進行封裝將無從談起。
一樣,對於「權限檢查」這一動做片段進行劃分,則是AOP的目標領域。而經過OOD/OOP對一個動做進行封裝,則有點不三不四。
換而言之,OOD/OOP面向名詞領域,AOP面向動詞領域。
IoC就是Inversion of Control,控制反轉。在Java開發中,IoC意味着將你設計好的類交給系統去控制,而不是在你的類內部控制。這稱爲控制反轉。
將對象的建立和獲取提取到外部。由外部容器提供須要的組件。
AOP 關注與主要的東西,也能夠說讓你只關注與業務,其餘的東西就讓AOP幫你完成。好比事務管理、持久化、資源池、系通通一的認證、權限管理等。容許經過分離應用的業務邏輯與系統級服務進行內聚性的開發。
設要排序的數組是A[0]……A[N-1],首先任意選取一個數據(一般選用數組的第一個數)做爲關鍵數據,而後將全部比它小的數都放到它前面,全部比它大的數都放到它後面,這個過程稱爲一趟快速排序。值得注意的是,快速排序不是一種穩定的排序算法,也就是說,多個相同的值的相對位置也許會在算法結束時產生變更。
一趟快速排序的算法是:
1)設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
2)以第一個數組元素做爲關鍵數據,賦值給key,即key=A[0];
3)從j開始向前搜索,即由後開始向前搜索(j--),找到第一個小於key的值A[j],將A[j]和A[i]互換;
4)從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]互換;
5)重複第三、4步,直到i=j; (3,4步中,沒找到符合條件的值,即3中A[j]不小於key,4中A[i]不大於key的時候改變j、i的值,使得j=j-1,i=i+1,直至找到爲止。找到符合條件的值,進行交換的時候i, j指針位置不變。另外,i==j這一過程必定正好是i+或j-完成 的時候,此時令循環結束)。
假設用戶輸入了以下數組:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
數據 |
6 |
2 |
7 |
3 |
8 |
9 |
建立變量i=0(指向第一個數據), j=5(指向最後一個數據), k=6(賦值爲第一個數據的值)。
咱們要把全部比k小的數移動到k的左面,因此咱們能夠開始尋找比6小的數,從j開始,從右往左找,不斷遞減變量j的值,咱們找到第一個下標3的數據比6小,因而把數據3移到下標0的位置,把下標0的數據6移到下標3,完成第一次比較:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
數據 |
3 |
2 |
7 |
6 |
8 |
9 |
i=0 j=3 k=6
接着,開始第二次比較,此次要變成找比k大的了,並且要從前日後找了。遞加變量i,發現下標2的數據是第一個比k大的,因而用下標2的數據7和j指向的下標3的數據的6作交換,數據狀態變成下表:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
數據 |
3 |
2 |
6 |
7 |
8 |
9 |
i=2 j=3 k=6
稱上面兩次比較爲一個循環。
接着,再遞減變量j,不斷重複進行上面的循環比較。
在本例中,咱們進行一次循環,就發現i和j「碰頭」了:他們都指向了下標2。因而,第一遍比較結束。獲得結果以下,凡是k(=6)左邊的數都比它小,凡是k右邊的數都比它大:
下標 |
0 |
1 |
2 |
3 |
4 |
5 |
數據 |
3 |
2 |
6 |
7 |
8 |
9 |
若是i和j沒有碰頭的話,就遞加i找大的,尚未,就再遞減j找小的,如此反覆,不斷循環。注意判斷和尋找是同時進行的。
而後,對k兩邊的數據,再分組分別進行上述的過程,直到不能再分組爲止。
注意:第一遍快速排序不會直接獲得最終結果,只會把比k大和比k小的數分到k的兩邊。爲了獲得最後結果,須要再次對下標2兩邊的數組分別執行此步驟,而後再分解數組,直到數組不能再分解爲止(只有一個數據),才能獲得正確結果。
代碼:
public class QuickSort { private static int par(int[]arr,int left,int right){ int key=arr[left]; while(left < right){ //從最右邊開始找比key小的數 while(left<right && arr[right]>=key) right--; //把找到的數移到左邊 arr[left]=arr[right]; //從最左邊開始找比key大的數 while(left<right && arr[left]<=key) left++; //把找到的數移到右邊 arr[right]=arr[left]; } //最後,left等於right,將key至於中間,這樣,key以前的數,比key小,key以後的數,比key大 arr[left]=key; return left; } private static void quickSort(int[]arr,int left,int right) { if(arr==null || arr.length==0 || left>=right){ return ; } int pos=par(arr,left,right); quickSort(arr,left,pos-1); quickSort(arr,left+1,right); } public static void main(String[]args) { int[] arr={22,11,23,32,45,32,21,33,67,12}; quickSort(arr,0,arr.length-1); for(int k:arr) System.out.print(k+" "); } }
創建在歸併操做上的一種有效的排序算法,該算法是採用分治法(Divide and Conquer)的一個很是典型的應用。將已有序的子序列合併,獲得徹底有序的序列;即先使每一個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱爲二路歸併。
歸 並過程爲:比較a[i]和a[j]的大小,若a[i]≤a[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;不然將第二 個有序表中的元素a[j]複製到r[k]中,並令j和k分別加上1,如此循環下去,直到其中一個有序表取完,而後再將另外一個有序表中剩餘的元素複製到r中 從下標k到下標t的單元。歸併排序的算法咱們一般用遞歸實現,先把待排序區間[s,t]以中點二分,接着把左邊子區間排序,再把右邊子區間排序,最後把左 區間和右區間用一次歸併操做合併成有序的區間[s,t]。
歸併操做
歸併操做(merge),也叫歸併算法,指的是將兩個順序序列合併成一個順序序列的方法。
如 設有數列{6,202,100,301,38,8,1}
初始狀態:6,202,100,301,38,8,1
第一次歸併後:{6,202},{100,301},{8,38},{1},比較次數:3;
第二次歸併後:{6,100,202,301},{1,8,38},比較次數:4;
第三次歸併後:{1,6,8,38,100,202,301},比較次數:4;
總的比較次數爲:3+4+4=11,;
逆序數爲14;
算法描述
歸併操做的工做原理以下:
第一步:申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列
第二步:設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置
第三步:比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置
重複步驟3直到某一指針超出序列尾
將另外一序列剩下的全部元素直接複製到合併序列尾
代碼:
public class MergeSort { public static void mergeSort(int[] arr) { if(arr==null || arr.length<=1){ return; } mSort(arr, 0, arr.length-1); } public static void mSort(int[] arr, int left, int right) { if(left >= right) return ; int mid = (left + right) / 2; mSort(arr, left, mid); //遞歸排序左邊 mSort(arr, mid+1, right); //遞歸排序右邊 merge(arr, left, mid, right); //合併 } /** * 合併兩個有序數組 * @param arr 待合併數組 * @param left 左指針 * @param mid 中間指針 * @param right 右指針 */ public static void merge(int[] arr, int left, int mid, int right) { //[left, mid] [mid+1, right] int[] temp = new int[right - left + 1]; //中間數組 int i = left; int j = mid + 1; int k = 0; while(i <= mid && j <= right) { if(arr[i] <= arr[j]) { temp[k++] = arr[i++]; } else { temp[k++] = arr[j++]; } } while(i <= mid) { temp[k++] = arr[i++]; } while(j <= right) { temp[k++] = arr[j++]; } for(int p=0; p<temp.length; p++) { arr[left + p] = temp[p]; } } public static void main(String[] args) { int[] arr={1,98,33,31,35,2,55,78,44,3}; mergeSort(arr); for(int k:arr) System.out.print(k+" "); } }
所謂洗牌算法,就是給你一個1到n的序列,讓你隨機打亂,保證每一個數出如今任意一個位置的機率相同,也就是說在n!個的排列中,每個排列出現的機率相同。
咱們考慮,當一個數被選以後,咱們是沒有必要在下一次隨機的時候再考慮它的,所以,咱們每次只從可選的數的集合中進行隨機,也就不用考慮是否會碰到已經選過的數了,這樣子直接將算法的複雜度降了一個數量級。
咱們考慮,當一個數被選以後,咱們是沒有必要在下一次隨機的時候再考慮它的,所以,咱們每次只從可選的數的集合中進行隨機,也就不用考慮是否會碰到已經選過的數了,這樣子直接將算法的複雜度降了一個數量級。
void MySwap(int &x, int &y) { int temp = x; x = y; y = temp; } void Shuffle(int n) { for(int i=n-1; i>=1; i--) { MySwap(num[i], num[rand()%(i+1)]); } }
把對象轉換爲字節序列的過程—序列化。
把字節序列恢復爲對象的過程—反序列化。
對象的序列化主要有兩種用途:
1) 把對象的字節序列永久地保存到硬盤上,一般存放在一個文件中;
2) 在網絡上傳送對象的字節序列。
JDK類庫中的序列化API
java.io.ObjectOutputStream表明對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把獲得的字節序列寫到一個目標輸出流中。
java.io.ObjectInputStream表明對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。
只有實現了Serializable和Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自 Serializable接口,實現Externalizable接口的類徹底由自身來控制序列化的行爲,而僅實現Serializable接口的類能夠 採用默認的序列化方式 。
對象序列化包括以下步驟:
1) 建立一個對象輸出流,它能夠包裝一個其餘類型的目標輸出流,如文件輸出流;
2) 經過對象輸出流的writeObject()方法寫對象。
對象反序列化的步驟以下:
1) 建立一個對象輸入流,它能夠包裝一個其餘類型的源輸入流,如文件輸入流;
2) 經過對象輸入流的readObject()方法讀取對象。
StringBuffer對象的內容能夠修改;而String對象一旦產生後就不能夠被修改,從新賦值後生成的新對象。
硬件環境不一樣:
C/S 通常創建在專用的網絡上, 小範圍裏的網絡環境, 局域網之間再經過專門服務器提供鏈接和數據交換服務. B/S 創建在廣域網之上的, 沒必要是專門的網絡硬件環境,例與電話上網, 租用設備. 信息本身管理. 有比C/S更強的適應範圍, 通常只要有操做系統和瀏覽器就行
對安全要求不一樣 :
C/S 通常面向相對固定的用戶羣, 對信息安全的控制能力很強. 通常高度機密的信息系統採用C/S 結構適宜. 能夠經過B/S發佈部分可公開信息.
B/S 創建在廣域網之上, 對安全的控制能力相對弱, 面向是不可知的用戶羣.
對程序架構不一樣:
C/S 程序能夠更加註重流程, 能夠對權限多層次校驗, 對系統運行速度能夠較少考慮.
B/S 對安全以及訪問速度的多重的考慮, 創建在須要更加優化的基礎之上. 比C/S有更高的要求 B/S結構的程序架構是發展的趨勢, 從MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持網絡的構件搭建的系統. SUN 和IBM推的JavaBean 構件技術等,使 B/S更加成熟.
軟件重用不一樣:
C/S 程序能夠不可避免的總體性考慮, 構件的重用性不如在B/S要求下的構件的重用性好.
B/S 對的多重結構,要求構件相對獨立的功能. 可以相對較好的重用.就入買來的餐桌能夠再利用,而不是作在牆上的石頭桌子
系統維護不一樣 :
系統維護是軟件生存週期中,開銷大, -------重要
C/S 程序因爲總體性, 必須總體考察, 處理出現的問題以及系統升級. 升級難. 多是再作一個全新的系統
B/S 構件組成,方面構件個別的更換,實現系統的無縫升級. 系統維護開銷減到最小.用戶從網上本身下載安裝就能夠實現升級.
處理問題不一樣:
C/S 程序能夠處理用戶面固定, 而且在相同區域, 安全要求高需求, 與操做系統相關. 應該都是相同的系統
B/S 創建在廣域網上, 面向不一樣的用戶羣, 分散地域, 這是C/S沒法做到的. 與操做系統平臺關係最小.
用戶接口不一樣
C/S 可能是創建的Window平臺上,表現方法有限,對程序員廣泛要求較高
B/S 創建在瀏覽器上, 有更加豐富和生動的表現方式與用戶交流. 而且大部分難度減低,減低開發成本.
不能夠,private咳喲用來修飾類變量。方法內的變量做用域是從這個變量聲明直到方法體結束,若是再使用private修飾的話二者就會衝突,因此不能在方法體內聲明一個變量爲private,並且在方法裏 聲明變量爲private也沒什麼意義,方法內聲明的變量的做用域原本就在方法體內,天然也不會被其它方法所訪問。
能夠進入其餘非synchronized的方法,synchronized的方法不能夠的!
Java中的每一個對象都有一個鎖(lock)或者叫作監視器(monitor),當訪問某個對象的synchronized方法時,表示的將該對象上鎖,此時其餘任何線程都沒法再去訪問該synchronized方法了,直到以前的那個線程執行方法完畢後(或者是拋出了異常),纔將該對象的鎖釋放掉,其餘線程纔有可能再去訪問該synchronized方法。
若是一個對象有多個synchronized方法,某一時刻某個線程已經進入到了某個synchronized方法,那麼在該方法沒有執行完畢前,其餘線程是沒法訪問該對象的任何synchronized方法的。
13.對象的上轉型,子類重寫了基類的方法A,那麼上轉型對象操做的這個方法A,是基類的方法A?仍是子類的方法A?
對象的上轉型,操做的是子類的方法A。上轉型對象只能操做基類的變量,子類繼承的方法和子類重寫的方法,不能使用子類新增的變量和方法。
能夠。for( boolean1; boolean2&&條件表達式;boolean3)是正確的。
byte、short、char、int、enum
在jdk1.5上,Byte、Short、Character、Integer也支持。
1 讀取並解析配置文件
Configuration conf = new Configuration().configure();
2 讀取並解析映射信息,建立SessionFactory
SessionFactory sf = conf.buildSessionFactoty();
3 打開Session
Session session = sf.openSession;//sf.getCurrentSession();
4 開始一個事務(增刪改操做必須,查詢操做可選)
Transaction tx = session.beginTransaction();
5 數據庫操做
session.sava();
6 提交事務(回滾事務)
tx.commit();(tx.rollback();)
7 關閉session
session.close();
一:static聲明的內部類
假設定義了一個類Outer,在Outer裏定義了一個內部類Inner。
class Outer{ // 定義外部類 private static String info = "hello world" ; // 定義外部類的私有屬性 static class Inner{ // 使用static定義內部類爲外部類 public void print(){ // 定義內部類的方法 System.out.println(info) ; // 直接訪問外部類的私有屬性 } }; public void fun(){ // 定義外部類的方法 new Inner().print() ; // 經過內部類的實例化對象調用方法 } }
那麼編譯後會生成Outer.class和Outer$Inner.class。
經過Outer.Inner in=new Outer.Inner(); 訪問內部類。
二:不使用statc聲明一個內部類
class Outer{ // 定義外部類 private static String info = "hello world" ; // 定義外部類的私有屬性 class Inner{ // 使用static定義內部類爲外部類 public void print(){ // 定義內部類的方法 System.out.println(info) ; // 直接訪問外部類的私有屬性 } }; public void fun(){ // 定義外部類的方法 new Inner().print() ; // 經過內部類的實例化對象調用方法 } }
經過 Outer o=new Outer(); Outer.Inner in=o.new Inner();訪問內部類。
注意點:內部類不能含有static變量和方法,由於成員內部類的建立依賴於外部類對象。只有建立了外部類對象,才能建立內部類對象。
Inverse是hibernate雙向關係中的基本概念。inverse的真正做用就是指定由哪一方來維護之間的關聯關係。當一方中指定了「inverse=true」,那麼那一方就有責任負責之間的關聯關係。
在set節點裏設置。
①瀏覽器和服務器會對用get方式提交的數據進行限制,服務器會對用post方式提交的數據進行限制。
②post的請求數據放置在http請求包中。
③get的參數個數理論上沒有限制,可是瀏覽器和服務器會對用get方式提交的數據進行限制。
另外,get方式的提交的url採用ASCII編碼。
1. public static void main(String args[]){ {
String a;
System.out.println("a="+a);
}
2. public class InnerClassDemo03{
static String a;
public static void main(String args[]){
System.out.println("a="+a);
}
}
結果:第一個編譯會有問題,第二個運行輸出a=null。
分析:第一個很好理解,使用前沒進行初始化,因此報錯。第二個的a實際上是成員變量,編譯器有個默認初始化,初始化爲null,因此有運行結果。
java集合(能夠存儲和操做數目不固定的一組數據,只能存放引用類型的數據,不能存放基本類型的數據,位於java.util包中)主要分爲三種類型,set、list、map。
List:可自動擴展的數組。
Set:沒有重複的數組。
部署java應用:Tomcat、Resin、Jboss、Weblogic
和ajax有關的框架:JQuery、DWR、Dojo、ExtJs、Mootools
System.gc()方法強制垃圾回收
① abstract class 在 Java 語言中表示的是一種繼承關係,一個類只能使用一次繼承關係。可是,一個類卻能夠實現多個interface,實現多重繼承。接口還有標識(裏面沒有任何方法,如Remote接口)和數據共享(裏面的變量全是常量)的做用。abstract class和interface所反映出的設計理念不一樣。其實abstract class表示的是"is-a"關係,interface表示的是"has-a"關係
② 接口是公開的,裏面不能有私有的方法或變量,是用於讓別人使用的,而抽象類是能夠有私有方法或私有變量的。
③ 在abstract class 中能夠有abstract的成員方法,也能夠有非abstarct的成員方法,而在interface中全部的成員方法默認都是public abstract 類型的
④ 接口中定義的變量默認是public static final 型,且必須給其初值,因此實現類中不能從新定義,也不能改變其值。抽象類中的變量默認是 friendly 型,其值能夠在子類中從新定義,也能夠在子類中從新賦值。
⑤ 實現接口的必定要實現接口裏定義的全部方法,而實現抽象類能夠有選擇地重寫須要用到的方法,通常的應用裏,最頂級的是接口,而後是抽象類實現接口,最後纔到具體類實現。抽象類中能夠有非抽象方法。接口中則不能有實現方法。
1)一旦變量被transient修飾,變量將再也不是對象持久化的一部分,該變量內容在序列化後沒法得到訪問。
2)transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量若是是用戶自定義類變量,則該類須要實現Serializable接口。
3)被transient關鍵字修飾的變量再也不能被序列化,一個靜態變量無論是否被transient修飾,均不能被序列化。
對象的初始化順序:(1)類加載以後,按從上到下(從父類到子類)執行被static修飾的語句;(2)當static語句執行完以後,再執行main方法;(3)若是有語句new了自身的對象,將從上到下執行構造代碼塊、構造器(二者能夠說綁定在一塊兒)。
在Java中,子類的構造過程當中必須調用其父類的構造函數,是由於有繼承關係存在時,子類要把父類的內容繼承下來。但若是父類有多個構造函數時,該如何選擇調用呢?第 一個規則:子類的構造過程當中,必須調用其父類的構造方法。一個類,若是咱們不寫構造方法,那麼編譯器會幫咱們加上一個默認的構造方法(就是沒有參數的構造 方法),可是若是你本身寫了構造方法,那麼編譯器就不會給你添加了,因此有時候當你new一個子類對象的時候,確定調用了子類的構造方法,可是若是在子類構造方法中咱們並無顯示的調用基類的構造方法,如:super(); 這樣就會調用父類沒有參數的構造方法。
第二個規則:若是子類的構造方法中既沒有顯示的調用基類構造方法,而基類中又沒有無參的構造方法,則編譯出錯,因此,一般咱們須要顯示的:super(參數列表),來調用父類有參數的構造函數,此時無參的構造函數就不會被調用。
總之,一句話:子類沒有顯示調用父類構造函數,無論子類構造函數是否帶參數都默認調用父類無參的構造函數,若父類沒有則編譯出錯。