Java基礎知識積累2
switch語句後的控制表示式只能是short、char、int、long整數型別和列舉型別,不能是float,double和boolean型別。String型別是java7開始支援。
Java程式的種類有:
(a)內嵌於Web檔案中,由瀏覽器來觀看的_Applet
(b)可獨立執行的 Application
(c)伺服器端的 Servlets
A 顯然是錯誤的,Java一律採用Unicode編碼方式,每個字元無論中文還是英文字元都佔用2個位元組。
B 也是不正確的,不同的編碼之間是可以轉換的,通常流程如下:
將字串S以其自身編碼方式分解為位元組陣列,再將位元組陣列以你想要輸出的編碼方式重新編碼為字串。
例:String newUTF8Str = new String(oldGBKStr.getBytes(“GBK”), “UTF8”);
C 是正確的。Java虛擬機器中通常使用UTF-16的方式儲存一個字元
D 也是正確的。ResourceBundle能夠依據Local的不同,選擇性的讀取與Local對應字尾的properties檔案,以達到國際化的目的。
資料型別的轉換,分為自動轉換和強制轉換。自動轉換是程式在執行過程中 “ 悄然 ” 進行的轉換,不需要使用者提前宣告,一般是從位數低的型別向位數高的型別轉換;強制型別轉換則必須在程式碼中宣告,轉換順序不受限制。
自動資料型別轉換
自動轉換按從低到高的順序轉換。不同型別資料間的優先關係如下:
低 ———————————————> 高
byte,short,char-> int -> long -> float -> double
異常通常指,你的程式碼可能在編譯時沒有錯誤,可是執行時會出現異常。比如常見的空指標異常。
也可能是程式可能出現無法預料的異常,比如你要從一個檔案讀資訊,可這個檔案不存在,
程式無法執行下去了,故程式要抓這些異常,通過異常處理機制來丟擲這些異常,
程式設計師就可以通過丟擲的異常來修改程式碼。try{}catch{}finally{}try塊中放入可能會出現異常的程式碼,
catch塊負責捕獲異常,finally塊負責處理一些必須執行的程式碼,比較關閉流等。
描述一下JVM載入class檔案的原理機制?
答:JVM中類的裝載是由類載入器(ClassLoader)和它的子類來實現的,Java中的類載入器是一個重要的Java執行時系統元件,它負責在執行時查詢和裝入類檔案中的類。
由於Java的跨平臺性,經過編譯的Java源程式並不是一個可執行程式,而是一個或多個類檔案。當Java程式需要使用某個類時,
JVM會確保這個類已經被載入、連線(驗證、準備和解析)和初始化。類的載入是指把類的.class檔案中的資料讀入到記憶體中,
通常是建立一個位元組陣列讀入.class檔案,然後產生與所載入類對應的Class物件。載入完成後,Class物件還不完整,所以此時的類還不可用。
當類被載入後就進入連線階段,這一階段包括驗證、準備(為靜態變數分配記憶體並設定預設的初始值)和解析(將符號引用替換為直接引用)三個步驟。
最後JVM對類進行初始化,包括:1)如果類存在直接的父類並且這個類還沒有被初始化,那麼就先初始化父類;2)如果類中存在初始化語句,就依次執行這些初始化語句。
類的載入是由類載入器完成的,類載入器包括:根載入器(BootStrap)、擴充套件載入器(Extension)、系統載入器(System)和使用者自定義類載入器(java.lang.ClassLoader的子類)。從Java 2(JDK 1.2)開始,類載入過程採取了父親委託機制(PDM)。PDM更好的保證了Java平臺的安全性,在該機制中,JVM自帶的Bootstrap是根載入器,其他的載入器都有且僅有一個父類載入器。類的載入首先請求父類載入器載入,父類載入器無能為力時才由其子類載入器自行載入。JVM不會向Java程式提供對Bootstrap的引用。下面是關於幾個類載入器的說明:
Bootstrap:一般用原生代碼實現,負責載入JVM基礎核心類庫(rt.jar);
Extension:從java.ext.dirs系統屬性所指定的目錄中載入類庫,它的父載入器是Bootstrap;
System:又叫應用類載入器,其父類是Extension。它是應用最廣泛的類載入器。
它從環境變數classpath或者系統屬性java.class.path所指定的目錄中記載類,
是使用者自定義載入器的預設父載入器。
闡述靜態變數和例項變數的區別。
答:靜態變數是被static修飾符修飾的變數,也稱為類變數,它屬於類,不屬於類的任何一個物件,一個類不管建立多少個物件,靜態變數在記憶體中有且僅有一個拷貝;
例項變數必須依存於某一例項,需要先建立物件然後通過物件才能訪問到它。靜態變數可以實現讓多個物件共享記憶體。
靜態巢狀類(Static Nested Class)和內部類(Inner Class)的不同?
答:Static Nested Class是被宣告為靜態(static)的內部類,它可以不依賴於外部類例項被例項化。而通常的內部類需要在外部類例項化後才能例項化
抽象的(abstract)方法是否可同時是靜態的(static),是否可同時是本地方法(native),是否可同時被synchronized修飾?
答:都不能。抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。本地方法是由原生代碼(如C程式碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。
synchronized和方法的實現細節有關,抽象方法不涉及實現細節,因此也是相互矛盾的。
是否可以從一個靜態(static)方法內部發出對非靜態(non-static)方法的呼叫?
答:不可以,靜態方法只能訪問靜態成員,因為非靜態方法的呼叫要先建立物件,在呼叫靜態方法時可能物件並沒有被初始化。
如何實現物件克隆?
答:有兩種方式:
1). 實現Cloneable介面並重寫Object類中的clone()方法;
2). 實現Serializable介面,通過物件的序列化和反序列化實現克隆,可以實現真正的深度克隆
Java 中的final關鍵字有哪些用法?
答:(1)修飾類:表示該類不能被繼承;(2)修飾方法:表示方法不能被重寫;(3)修飾變數:表示變數只能一次賦值以後值不能被修改(常量)。
建立物件時構造器的呼叫順序是:先初始化靜態成員,然後呼叫父類構造器,再初始化非靜態成員,最後呼叫自身構造器。
如何實現字串的反轉及替換?
答:方法很多,可以自己寫實現也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常見的面試題是用遞迴實現字串反轉,程式碼如下所示:
public static String reverse(String originStr) {
if(originStr == null || originStr.length() <= 1)
return originStr;
return reverse(originStr.substring(1)) + originStr.charAt(0);
}
Java語言如何進行異常處理,關鍵字:throws、throw、try、catch、finally分別如何使用?
答:Java通過面向物件的方法進行異常處理,把各種不同的異常進行分類,並提供了良好的介面。在Java中,每個異常都是一個物件,它是Throwable類或其子類的例項。
當一個方法出現異常後便丟擲一個異常物件,該物件中包含有異常資訊,呼叫這個物件的方法可以捕獲到這個異常並可以對其進行處理。
Java的異常處理是通過5個關鍵詞來實現的:try、catch、throw、throws和finally。一般情況下是用try來執行一段程式,如果系統會丟擲(throw)一個異常物件,
可以通過它的型別來捕獲(catch)它,或通過總是執行程式碼塊(finally)來處理;try用來指定一塊預防所有異常的程式;catch子句緊跟在try塊後面,
用來指定你想要捕獲的異常的型別;throw語句用來明確地丟擲一個異常;throws用來宣告一個方法可能丟擲的各種異常(當然宣告異常時允許無病呻吟);
finally為確保一段程式碼不管發生什麼異常狀況都要被執行;try語句可以巢狀,每當遇到一個try語句,異常的結構就會被放入異常棧中,直到所有的try語句都完成。
如果下一級的try語句沒有對某種異常進行處理,異常棧就會執行出棧操作,直到遇到有處理這種異常的try語句或者最終將異常拋給JVM。
闡述final、finally、finalize的區別。
答:
- final:修飾符(關鍵字)有三種用法:如果一個類被宣告為final,意味著它不能再派生出新的子類,即不能被繼承,因此它和abstract是反義詞。
將變數宣告為final,可以保證它們在使用中不被改變,被宣告為final的變數必須在宣告時給定初值,而在以後的引用中只能讀取不可修改。
被宣告為final的方法也同樣只能使用,不能在子類中被重寫。
- finally:通常放在try…catch…的後面構造總是執行程式碼塊,這就意味著程式無論正常執行還是發生異常,這裡的程式碼只要JVM不關閉都能執行,
可以將釋放外部資源的程式碼寫在finally塊中。
- finalize:Object類中定義的方法,Java中允許使用finalize()方法在垃圾收集器將物件從記憶體中清除出去之前做必要的清理工作。
這個方法是由垃圾收集器在銷燬物件時呼叫的,通過重寫finalize()方法可以整理系統資源或者執行其他清理工作。
Thread類的sleep()方法和物件的wait()方法都可以讓執行緒暫停執行,它們有什麼區別?
答:sleep()方法(休眠)是執行緒類(Thread)的靜態方法,呼叫此方法會讓當前執行緒暫停執行指定的時間,將執行機會(CPU)讓給其他執行緒,但是物件的鎖依然保持,
因此休眠時間結束後會自動恢復(執行緒回到就緒狀態,請參考第66題中的執行緒狀態轉換圖)。wait()是Object類的方法,
呼叫物件的wait()方法導致當前執行緒放棄物件的鎖(執行緒暫停執行),進入物件的等待池(wait pool),只有呼叫物件的notify()方法(或notifyAll()方法)
時才能喚醒等待池中的執行緒進入等鎖池(lock pool),如果執行緒重新獲得物件的鎖就可以進入就緒狀態。
執行緒的sleep()方法和yield()方法有什麼區別?
答:
① sleep()方法給其他執行緒執行機會時不考慮執行緒的優先順序,因此會給低優先順序的執行緒以執行的機會;yield()方法只會給相同優先順序或更高優先順序的執行緒以執行的機會;
② 執行緒執行sleep()方法後轉入阻塞(blocked)狀態,而執行yield()方法後轉入就緒(ready)狀態;
③ sleep()方法宣告丟擲InterruptedException,而yield()方法沒有宣告任何異常;
④ sleep()方法比yield()方法(跟作業系統CPU排程相關)具有更好的可移植性。
闡述JDBC操作資料庫的步驟。
答:下面的程式碼以連線本機的Oracle資料庫為例,演示JDBC操作資料庫的步驟。
載入驅動。
Class.forName(“oracle.jdbc.driver.OracleDriver”);
建立連線。
Connection con = DriverManager.getConnection(“jdbc:oracle:thin:@localhost:1521:orcl”, “scott”, “tiger”);
建立語句。
PreparedStatement ps = con.prepareStatement(“select * from emp where sal between ? and ?”);
ps.setInt(1, 1000);
ps.setInt(2, 3000);
執行語句。
ResultSet rs = ps.executeQuery();
處理結果。
while(rs.next()) {
System.out.println(rs.getInt(“empno”) + ” - ” + rs.getString(“ename”));
}
關閉資源。
finally {
if(con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
提示:關閉外部資源的順序應該和開啟的順序相反,也就是說先關閉ResultSet、再關閉Statement、在關閉Connection。上面的程式碼只關閉了Connection(連線),
雖然通常情況下在關閉連線時,連線上建立的語句和開啟的遊標也會關閉,但不能保證總是如此,因此應該按照剛才說的順序分別關閉。
此外,第一步載入驅動在JDBC 4.0中是可以省略的(自動從類路徑中載入驅動),但是我們建議保留。
JSP有哪些內建物件?作用分別是什麼?
答:JSP有9個內建物件:
- request:封裝客戶端的請求,其中包含來自GET或POST請求的引數;
- response:封裝伺服器對客戶端的響應;
- pageContext:通過該物件可以獲取其他物件;
- session:封裝使用者會話的物件;
- application:封裝伺服器執行環境的物件;
- out:輸出伺服器響應的輸出流物件;
- config:Web應用的配置物件;
- page:JSP頁面本身(相當於Java程式中的this);
- exception:封裝頁面丟擲異常的物件。
web.xml檔案中可以配置哪些內容?
答:web.xml用於配置Web應用的相關資訊,如:監聽器(listener)、過濾器(filter)、 Servlet、
相關引數、會話超時時間、安全驗證方式、錯誤頁面等,下面是一些開發中常見的配置
自定義JSP標籤包括以下幾個步驟:
- 編寫一個Java類實現實現Tag/BodyTag/IterationTag介面(開發中通常不直接實現這些介面而是繼承TagSupport/BodyTagSupport/SimpleTagSupport類,這是對預設適配模式的應用),重寫doStartTag()、doEndTag()等方法,定義標籤要完成的功能
- 編寫副檔名為tld的標籤描述檔案對自定義標籤進行部署,tld檔案通常放在WEB-INF資料夾下或其子目錄中
- 在JSP頁面中使用taglib指令引用該標籤庫
如何設定請求的編碼以及響應內容的型別?
答:通過請求物件(ServletRequest)的setCharacterEncoding(String)方法可以設定請求的編碼,
其實要徹底解決亂碼問題就應該讓頁面、伺服器、請求和響應、Java程式都使用統一的編碼,最好的選擇當然是UTF-8;
通過響應物件(ServletResponse)的setContentType(String)方法可以設定響應內容的型別,
當然也可以通過HttpServletResponsed物件的setHeader(String, String)方法來設定。
什麼是ORM?
答:物件關係對映(Object-Relational Mapping,簡稱ORM)是一種為了解決程式的面向物件模型與資料庫的關係模型互不匹配問題的技術;
簡單的說,ORM是通過使用描述物件和資料庫之間對映的元資料(在Java中可以用XML或者是註解),
選擇使用Spring框架的原因(Spring框架為企業級開發帶來的好處有哪些)?
答:可以從以下幾個方面作答:
- 非侵入式:支援基於POJO的程式設計模式,不強制性的要求實現Spring框架中的介面或繼承Spring框架中的類。
- IoC容器:IoC容器幫助應用程式管理物件以及物件之間的依賴關係,物件之間的依賴關係如果發生了改變只需要修改配置檔案而不是修改程式碼,因為程式碼的修改可能意味著專案的重新構建和完整的迴歸測試。有了IoC容器,程式設計師再也不需要自己編寫工廠、單例,這一點特別符合Spring的精神”不要重複的發明輪子”。
- AOP(面向切面程式設計):將所有的橫切關注功能封裝到切面(aspect)中,通過配置的方式將橫切關注功能動態新增到目的碼上,進一步實現了業務邏輯和系統服務之間的分離。另一方面,有了AOP程式設計師可以省去很多自己寫代理類的工作。
- MVC:Spring的MVC框架是非常優秀的,從各個方面都可以甩Struts 2幾條街,為Web表示層提供了更好的解決方案。
- 事務管理:Spring以寬廣的胸懷接納多種持久層技術,並且為其提供了宣告式的事務管理,在不需要任何一行程式碼的情況下就能夠完成事務管理。
- 其他:選擇Spring框架的原因還遠不止於此,Spring為Java企業級開發提供了一站式選擇,你可以在需要的時候使用它的部分和全部,更重要的是,你甚至可以在感覺不到Spring存在的情況下,在你的專案中使用Spring提供的各種優秀的功能。
闡述Spring框架中Bean的生命週期?
答:
① Spring IoC容器找到關於Bean的定義並例項化該Bean。
② Spring IoC容器對Bean進行依賴注入。
③ 如果Bean實現了BeanNameAware介面,則將該Bean的id傳給setBeanName方法。
④ 如果Bean實現了BeanFactoryAware介面,則將BeanFactory物件傳給setBeanFactory方法。
⑤ 如果Bean實現了BeanPostProcessor介面,則呼叫其postProcessBeforeInitialization方法。
⑥ 如果Bean實現了InitializingBean介面,則呼叫其afterPropertySet方法。
⑦ 如果有和Bean關聯的BeanPostProcessors物件,則這些物件的postProcessAfterInitialization方法被呼叫。
⑧ 當銷燬Bean例項時,如果Bean實現了DisposableBean介面,則呼叫其destroy方法。