友情連接:Java面試資料大全,Spring全家桶筆記前端
一、面向對象的特徵有哪些方面?java
- 抽象:抽象是將一類對象的共同特徵總結出來構造類的過程,包括數據抽象和行爲抽象兩方面。抽象只關注對象有哪些屬性和行爲,並不關注這些行爲的細節是什麼。程序員
- 繼承:繼承是從已有類獲得繼承信息建立新類的過程。提供繼承的類叫父類(超類、基類)、獲得繼承的類叫子類(派生類)。面試
- 封裝:一般認爲封裝是把數據和操做數據的方法綁定起來,對數據的訪問只能經過已定義的接口。能夠說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口(能夠想一想普通洗衣機和全自動洗衣機的差異,明顯全自動洗衣機封裝更好所以操做起來更簡單;咱們如今使用的智能手機也是封裝得足夠好的,由於幾個按鍵就搞定了全部的事情)。數據庫
- 多態性:多態性是指容許不一樣子類型的對象對同一消息做出不一樣的響應。簡單的說就是用一樣的對象引用調用一樣的方法可是作了不一樣的事情。實現多態須要作兩件事:1). 方法重寫(子類繼承父類並重寫父類中的方法);2). 對象造型(用父類型引用引用子類型對象,這樣一樣的引用調用一樣的方法就會根據子類對象的不一樣而表現出不一樣的行爲)編程
二、訪問修飾符public,private,protected,以及不寫(默認)時的區別?設計模式
修飾符數組
當前類瀏覽器
同 包緩存
子 類
其餘包
public
√
√
√
√
protected
√
√
√
×
default
√
√
×
×
private
√
×
×
×
三、String 是最基本的數據類型嗎?
答:不是。Java中的基本數據類型只有8個:byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type)和枚舉類型(enumeration type),剩下的都是引用類型(reference type)。
四、float f=3.4;是否正確?
答:不正確。3.4是雙精度數,將雙精度型(double)賦值給浮點型(float)屬於下轉型(down-casting,也稱爲窄化)會形成精度損失,所以須要強制類型轉換float f =(float)3.4; 或者寫成float f =3.4F;。
**五、short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?
**
答:對於short s1 = 1; s1 = s1 + 1;因爲1是int類型,所以s1+1運算結果也是int 型,須要強制轉換類型才能賦值給short型。而short s1 = 1; s1 += 1;能夠正確編譯,由於s1+= 1;至關於s1 = (short)(s1 + 1);其中有隱含的強制類型轉換。
**六、int和Integer有什麼區別?
**
答:Java是一個近乎純潔的面向對象編程語言,可是爲了編程的方便仍是引入了基本數據類型,可是爲了可以將這些基本數據類型當成對象操做,Java爲每個基本數據類型都引入了對應的包裝類型(wrapper class),int的包裝類就是Integer,從Java 5開始引入了自動裝箱/拆箱機制,使得兩者能夠相互轉換。
class
AutoUnboxingTest {
public
static
void
main(String[] args) {
Integer a =
new
Integer(
3
);
Integer b =
3
;
// 將3自動裝箱成Integer類型
int
c =
3
;
System.out.println(a == b);
// false 兩個引用沒有引用同一對象
System.out.println(a == c);
// true a自動拆箱成int類型再和c比較
}
}
最近還遇到一個面試題,也是和自動裝箱和拆箱有點關係的,代碼以下所示:
public
class
Test03 {
public
static
void
main(String[] args) {
Integer f1 =
100
, f2 =
100
, f3 =
150
, f4 =
150
;
System.out.println(f1 == f2);
System.out.println(f3 == f4);
}
}
若是不明就裏很容易認爲兩個輸出要麼都是true要麼都是false。首先須要注意的是f一、f二、f三、f4四個變量都是Integer對象引用,因此下面的==運算比較的不是值而是引用。裝箱的本質是什麼呢?當咱們給一個Integer對象賦一個int值的時候,會調用Integer類的靜態方法valueOf
public
static
Integer valueOf(
int
i) {
if
(i >= IntegerCache.low && i <= IntegerCache.high)
return
IntegerCache.cache[i + (-IntegerCache.low)];
return
new
Integer(i);
}
簡單的說,若是整型字面量的值在-128到127之間,那麼不會new新的Integer對象,而是直接引用常量池中的Integer對象,因此上面的面試題中f1==f2的結果是true,而f3==f4的結果是false。
七、&和&&的區別?
雖然兩者都要求運算符左右兩端的布爾值都是true整個表達式的值纔是true。&&之因此稱爲短路運算是由於,若是&&左邊的表達式的值是false,右邊的表達式會被直接短路掉,不會進行運算。不少時候咱們可能都須要用&&而不是&,例如在驗證用戶登陸時斷定用戶名不是null並且不是空字符串,應當寫爲:username != null &&!username.equals(「」),兩者的順序不能交換,更不能用&運算符,由於第一個條件若是不成立,根本不能進行字符串的equals比較,不然會產生NullPointerException異常。注意:邏輯或運算符(|)和短路或運算符(||)的差異也是如此。
八、解釋內存中的棧(stack)、堆(heap)和靜態區(static area)的用法。
棧空間操做起來最快可是棧很小,一般大量的對象都是放在堆空間
String str =
new
String(``"hello"``);
上面的語句中變量str放在棧上,用new建立出來的字符串對象放在堆上,而」hello」這個字面量放在靜態區。
**九、Math.round(11.5) 等於多少?Math.round(-11.5)等於多少?**
答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四捨五入的原理是在參數上加0.5而後進行下取整。
**十、switch 是否能做用在byte 上,是否能做用在long 上,是否能做用在String上?**
expr能夠是byte、short、char、int、enum、String類型,可是long類型不能
十一、用最有效率的方法計算2乘以8?
答: 2 << 3(左移3位至關於乘以2的3次方,右移3位至關於除以2的3次方)。
十二、數組有沒有length()方法?String有沒有length()方法?
答:數組沒有length()方法,有length 的屬性。String 有length()方法。JavaScript中,得到字符串的長度是經過length屬性獲得的,這一點容易和Java混淆。
1三、構造器(constructor)是否可被重寫(override)?
答:構造器不能被繼承,所以不能被重寫,但能夠被重載。
1四、兩個對象值相同(x.equals(y) == true),但卻可有不一樣的hash code,這句話對不對?
答:不對,若是兩個對象x和y知足x.equals(y) == true,它們的哈希碼(hash code)應當相同。Java對於eqauls方法和hashCode方法是這樣規定的:(1)若是兩個對象相同(equals方法返回true),那麼它們的hashCode值必定要相同;(2)若是兩個對象的hashCode相同,它們並不必定相同
1五、是否能夠繼承String類?
答:String 類是final類,不能夠被繼承。
**1六、當一個對象被看成參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,那麼這裏究竟是值傳遞仍是引用傳遞?
**
答:是值傳遞。Java語言的方法調用只支持參數的值傳遞。當一個對象實例做爲一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對象的屬性能夠在被調用過程當中被改變,但對對象引用的改變是不會影響到調用者的
**1七、String和StringBuilder、StringBuffer的區別?
**
答:Java平臺提供了兩種類型的字符串:String和StringBuffer/StringBuilder,它們能夠儲存和操做字符串。其中String是隻讀字符串,也就意味着String引用的字符串內容是不能被改變的。而StringBuffer/StringBuilder類表示的字符串對象能夠直接進行修改。StringBuilder是Java 5中引入的,它和StringBuffer的方法徹底相同,區別在於它是在單線程環境下使用的,由於它的全部方面都沒有被synchronized修飾,所以它的效率也比StringBuffer要高。
**1八、重載(Overload)和重寫(Override)的區別。重載的方法可否根據返回類型進行區分?
**
答:方法的重載和重寫都是實現多態的方式,區別在於前者實現的是編譯時的多態性,然後者實現的是運行時的多態性。重載發生在一個類中,同名的方法若是有不一樣的參數列表(參數類型不一樣、參數個數不一樣或者兩者都不一樣)則視爲重載;重寫發生在子類與父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好訪問,不能比父類被重寫方法聲明更多的異常(里氏代換原則)。重載對返回類型沒有特殊的要求。
1九、描述一下JVM加載class文件的原理機制?
答:JVM中類的裝載是由類加載器(ClassLoader)和它的子類來實現的,Java中的類加載器是一個重要的Java運行時系統組件,它負責在運行時查找和裝入類文件中的類。類的加載是指把類的.class文件中的數據讀入到內存中,一般是建立一個字節數組讀入.class文件
**20、抽象類(abstract class)和接口(interface)有什麼異同?
**
答:抽象類和接口都不可以實例化,但能夠定義抽象類和接口類型的引用。一個類若是繼承了某個抽象類或者實現了某個接口都須要對其中的抽象方法所有進行實現,不然該類仍然須要被聲明爲抽象類。接口比抽象類更加抽象,由於抽象類中能夠定義構造器,能夠有抽象方法和具體方法,而接口中不能定義構造器並且其中的方法所有都是抽象方法。抽象類中的成員能夠是private、默認、protected、public的,而接口中的成員全都是public的。抽象類中能夠定義成員變量,而接口中定義的成員變量實際上都是常量。有抽象方法的類必須被聲明爲抽象類,而抽象類未必要有抽象方法。
**2一、Java 中會存在內存泄漏嗎,請簡單描述。
**
答:理論上Java由於有垃圾回收機制(GC)不會存在內存泄露問題(這也是Java被普遍使用於服務器端編程的一個重要緣由);然而在實際開發中,可能會存在無用但可達的對象,這些對象不能被GC回收,所以也會致使內存泄露的發生。例如hibernate的Session(一級緩存)中的對象屬於持久態,垃圾回收器是不會回收這些對象的,然而這些對象中可能存在無用的垃圾對象,若是不及時關閉(close)或清空(flush)一級緩存就可能致使內存泄露
**2二、GC是什麼?爲何要有GC?
**
答:GC是垃圾收集的意思,垃圾回收能夠有效的防止內存泄露,有效的使用可使用的內存
**2三、String s = new String(「xyz」);建立了幾個字符串對象?
**
答:兩個對象,一個是靜態區的」xyz」,一個是用new建立在堆上的對象。
**2四、接口是否可繼承(extends)接口?抽象類是否可實現(implements)接口?抽象類是否可繼承具體類(concrete class)?
**
答:接口能夠繼承接口,並且支持多重繼承。抽象類能夠實現(implements)接口,抽象類可繼承具體類也能夠繼承抽象類。
2五、Java 中的final關鍵字有哪些用法?
答:(1)修飾類:表示該類不能被繼承;(2)修飾方法:表示方法不能被重寫;(3)修飾變量:表示變量只能一次賦值之後值不能被修改(常量)。
**2六、指出下面程序的運行結果。
**
class
A {
static
{
System.out.print(
"1"
);
}
public
A() {
System.out.print(
"2"
);
}
}
class
B
extends
A{
static
{
System.out.print(
"a"
);
}
public
B() {
System.out.print(
"b"
);
}
}
public
class
Hello {
public
static
void
main(String[] args) {
A ab =
new
B();
ab =
new
B();
}
}
答:執行結果:1a2b2b。建立對象時構造器的調用順序是:先初始化靜態成員,而後調用父類構造器,再初始化非靜態成員,最後調用自身構造器。
2七、數據類型之間的轉換:
- 如何將字符串轉換爲基本數據類型?
- 如何將基本數據類型轉換爲字符串?
答:
- 調用基本數據類型對應的包裝類中的方法parseXXX(String)或valueOf(String)便可返回相應基本類型;
- 一種方法是將基本數據類型與空字符串(」")鏈接(+)便可得到其所對應的字符串;另外一種方法是調用String 類中的valueOf()方法返回相應字符串
**2八、如何實現字符串的反轉及替換?
**
答:方法不少,能夠本身寫實現也可使用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
);
}
**2九、怎樣將GB2312編碼的字符串轉換爲ISO-8859-1編碼的字符串?
**
答:代碼以下所示:
String s1 =
"你好"
;
String s2 =
new
String(s1.getBytes(
"GB2312"
),
"ISO-8859-1"
);
30、利用java.text.DataFormat 的子類(如SimpleDateFormat類)中的format(Date)方法可將日期格式化
class
DateFormatTest {
public
static
void
main(String[] args) {
SimpleDateFormat oldFormatter =
new
SimpleDateFormat(
"yyyy/MM/dd"
);
Date date1 =
new
Date();
System.out.println(oldFormatter.format(date1));
}
}
3一、比較一下Java和JavaSciprt。
java是靜態語言,js是動態語言
- 基於對象和麪向對象:Java是一種真正的面向對象的語言,即便是開發簡單的程序,必須設計對象;JavaScript是種腳本語言,它能夠用來製做與網絡無關的,與用戶交互做用的複雜軟件。它是一種基於對象(Object-Based)和事件驅動(Event-Driven)的編程語言,於是它自己提供了很是豐富的內部對象供設計人員使用。
- 解釋和編譯:Java的源代碼在執行以前,必須通過編譯。JavaScript是一種解釋性編程語言,其源代碼不需通過編譯,由瀏覽器解釋執行。(目前的瀏覽器幾乎都使用了JIT(即時編譯)技術來提高JavaScript的運行效率)
- 強類型變量和類型弱變量:Java採用強類型變量檢查,即全部變量在編譯以前必須做聲明;JavaScript中變量是弱類型的,甚至在使用變量前能夠不做聲明,JavaScript的解釋器在運行時檢查推斷其數據類型。
- 代碼格式不同。
**3二、try{}裏有一個return語句,那麼緊跟在這個try後的finally{}裏的代碼會不會被執行,何時被執行,在return前仍是後?
**
答:會執行,在方法返回調用者前執行。
在finally中改變返回值的作法是很差的,由於若是存在finally代碼塊,try中的return語句不會立馬返回調用者,而是記錄下返回值待finally代碼塊執行完畢以後再向調用者返回其值,而後若是在finally中修改了返回值,就會返回修改後的值
3三、列出一些你常見的運行時異常?
答:
- ArithmeticException(算術異常)
- ClassCastException (類轉換異常)
- IllegalArgumentException (非法參數異常)
- IndexOutOfBoundsException (下標越界異常)
- NullPointerException (空指針異常)
- SecurityException (安全異常)
3四、類ExampleA繼承Exception,類ExampleB繼承ExampleA。
有以下代碼片段:
try
{
throw
new
ExampleB(
"b"
)
}
catch
(ExampleA e){
System.out.println(
"ExampleA"
);
}
catch
(Exception e){
System.out.println(
"Exception"
);
}
請問執行此段代碼的輸出是什麼?
答:輸出:ExampleA。(根據里氏代換原則[能使用父類型的地方必定能使用子類型],抓取ExampleA類型異常的catch塊可以抓住try塊中拋出的ExampleB類型的異常)
面試題 - 說出下面代碼的運行結果。(此題的出處是《Java編程思想》一書)
class
Annoyance
extends
Exception {}
class
Sneeze
extends
Annoyance {}
class
Human {
public
static
void
main(String[] args)
throws
Exception {
try
{
try
{
throw
new
Sneeze();
}
catch
( Annoyance a ) {
System.out.println(
"Caught Annoyance"
);
throw
a;
}
}
catch
( Sneeze s ) {
System.out.println(
"Caught Sneeze"
);
return
;
}
finally
{
System.out.println(
"Hello World!"
);
}
}
}
輸出:
Caught Annoyance
Caught Sneeze
Hello World!
try { throw new Annoyance(); } catch (Sneeze s) { System.out.println("Caught Sneeze"); return; } finally { System.out.println("Hello World!"); }
複製代碼
輸出:(父類throw出來的異常,子類並無捕獲到)
Hello World!
Exception in thread "main" com.xq.exceptions.Annoyance
at com.xq.exceptions.Human.main(ExceptionTest.java:14)
try { throw new Annoyance(); } catch (Sneeze s) { System.out.println("Caught Sneeze"); return; } catch (Exception e) { System.out.println("Caught Exception"); return; } finally { System.out.println("Hello World!"); }
複製代碼
輸出:(既然子類捕獲不了,那就使用Exception),能夠看到結果以下:
Caught Exception
Hello World!
**3五、List、Set、Map是否繼承自Collection接口?
**
答:List、Set 是,Map 不是。Map是鍵值對映射容器,與List和Set有明顯的區別,而Set存儲的零散的元素且不容許有重複元素(數學中的集合也是如此),List是線性結構的容器,適用於按數值索引訪問元素的情形。
3六、Collection和Collections的區別?
答:Collection是一個接口,它是Set、List等容器的父接口;Collections是個一個工具類,提供了一系列的靜態方法來輔助容器操做,這些方法包括對容器的搜索、排序、線程安全化等等。
**3七、List、Map、Set三個接口存取元素時,各有什麼特色?
**
答:List以特定索引來存取元素,能夠有重複元素。Set不能存放重複元素(用對象的equals()方法來區分元素是否重複)。Map保存鍵值對(key-value pair)映射,映射關係能夠是一對一或多對一
**3八、Thread類的sleep()方法和對象的wait()方法均可以讓線程暫停執行,它們有什麼區別?
**
答:sleep()方法(休眠)是線程類(Thread)的靜態方法,調用此方法會讓當前線程暫停執行指定的時間,將執行機會(CPU)讓給其餘線程,可是對象的鎖依然保持,所以休眠時間結束後會自動恢復。wait()是Object類的方法,調用對象的wait()方法致使當前線程放棄對象的鎖(線程暫停執行),進入對象的等待池(wait pool),只有調用對象的notify()方法(或notifyAll()方法)時才能喚醒等待池中的線程進入等鎖池(lock pool),若是線程從新得到對象的鎖就能夠進入就緒狀態。
3九、線程的sleep()方法和yield()方法有什麼區別?
答:
① sleep()方法給其餘線程運行機會時不考慮線程的優先級,所以會給低優先級的線程以運行的機會;yield()方法只會給相同優先級或更高優先級的線程以運行的機會;
② 線程執行sleep()方法後轉入阻塞(blocked)狀態,而執行yield()方法後轉入就緒(ready)狀態;
③ sleep()方法聲明拋出InterruptedException,而yield()方法沒有聲明任何異常;
④ sleep()方法比yield()方法(跟操做系統CPU調度相關)具備更好的可移植性。
**40、當一個線程進入一個對象的synchronized方法A以後,其它線程是否可進入此對象的synchronized方法B?
**答:不能。其它線程只能訪問該對象的非同步方法,同步方法則不能進入。由於非靜態方法上的synchronized修飾符要求執行方法時要得到對象的鎖,若是已經進入A方法說明對象鎖已經被取走,那麼試圖進入B方法的線程就只能在等鎖池(注意不是等待池哦)中等待對象的鎖。
**4一、請說出與線程同步以及線程調度相關的方法。
**答:
- wait():使一個線程處於等待(阻塞)狀態,而且釋放所持有的對象的鎖;
- sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要處理InterruptedException異常;
- notify():喚醒一個處於等待狀態的線程,固然在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM肯定喚醒哪一個線程,並且與優先級無關;
- notityAll():喚醒全部處於等待狀態的線程,該方法並非將對象的鎖給全部線程,而是讓它們競爭,只有得到鎖的線程才能進入就緒狀態;
**4二、編寫多線程程序有幾種實現方式?
**
答:一種是繼承Thread類;另外一種是實現Runnable接口。兩種方式都要經過重寫run()方法來定義線程的行爲,推薦使用後者,由於Java中的繼承是單繼承,一個類有一個父類,若是繼承了Thread類就沒法再繼承其餘類了,顯然使用Runnable接口更爲靈活。
4三、synchronized關鍵字的用法?
答:synchronized關鍵字能夠將對象或者方法標記爲同步,以實現對對象和方法的互斥訪問,能夠用synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時將synchronized做爲方法的修飾符。
**4四、舉例說明同步和異步。
**
答:若是系統中存在臨界資源(資源數量少於競爭資源的線程數量的資源),例如正在寫的數據之後可能被另外一個線程讀到,或者正在讀的數據可能已經被另外一個線程寫過了,那麼這些數據就必須進行同步存取(數據庫操做中的排他鎖就是最好的例子)。當應用程序在對象上調用了一個須要花費很長時間來執行的方法,而且不但願讓程序等待方法的返回時,就應該使用異步編程,在不少狀況下采用異步途徑每每更有效率。事實上,所謂的同步就是指阻塞式操做,而異步就是非阻塞式操做。
**4五、簡述synchronized 和java.util.concurrent.locks.Lock的異同?
**答:Lock是Java 5之後引入的新的API,和關鍵字synchronized相比主要相同點:Lock 能完成synchronized所實現的全部功能;主要不一樣點:Lock有比synchronized更精確的線程語義和更好的性能,並且不強制性的要求必定要得到鎖。synchronized會自動釋放鎖,而Lock必定要求程序員手工釋放,而且最好在finally 塊中釋放(這是釋放外部資源的最好的地方)
**4六、事務的ACID是指什麼?
**答:
- 原子性(Atomic):事務中各項操做,要麼全作要麼全不作,任何一項操做的失敗都會致使整個事務的失敗;
- 一致性(Consistent):事務結束後系統狀態是一致的;
- 隔離性(Isolated):併發執行的事務彼此沒法看到對方的中間狀態;
- 持久性(Durable):事務完成後所作的改動都會被持久化,即便發生災難性的失敗。經過日誌和同步備份能夠在故障發生後重建數據。
**4七、得到一個類的類對象有哪些方式?
**答:
- 方法1:類型.class,例如:String.class
- 方法2:對象.getClass(),例如:」hello」.getClass()
- 方法3:Class.forName(),例如:Class.forName(「java.lang.String」)
**4八、簡述一下面向對象的」六原則一法則」。
**答:
**- 單一職責原則:**一個類只作它該作的事情。(單一職責原則想表達的就是」高內聚」,寫代碼最終極的原則只有六個字」高內聚、低耦合」,就如同葵花寶典或辟邪劍譜的中心思想就八個字」欲練此功必先自宮」,所謂的高內聚就是一個代碼模塊只完成一項功能,在面向對象中,若是隻讓一個類完成它該作的事,而不涉及與它無關的領域就是踐行了高內聚的原則,這個類就只有單一職責。咱們都知道一句話叫」由於專一,因此專業」,一個對象若是承擔太多的職責,那麼註定它什麼都作很差。這個世界上任何好的東西都有兩個特徵,一個是功能單一,好的相機絕對不是電視購物裏面賣的那種一個機器有一百多種功能的,它基本上只能照相;另外一個是模塊化,好的自行車是組裝車,從減震叉、剎車到變速器,全部的部件都是能夠拆卸和從新組裝的,好的乒乓球拍也不是成品拍,必定是底板和膠皮能夠拆分和自行組裝的,一個好的軟件系統,它裏面的每一個功能模塊也應該是能夠輕易的拿到其餘系統中使用的,這樣才能實現軟件複用的目標。)
**- 開閉原則:**軟件實體應當對擴展開放,對修改關閉。(在理想的狀態下,當咱們須要爲一個軟件系統增長新功能時,只須要從原來的系統派生出一些新類就能夠,不須要修改原來的任何一行代碼。要作到開閉有兩個要點:①抽象是關鍵,一個系統中若是沒有抽象類或接口系統就沒有擴展點;②封裝可變性,將系統中的各類可變因素封裝到一個繼承結構中,若是多個可變因素混雜在一塊兒,系統將變得複雜
**- 依賴倒轉原則:**面向接口編程。
**- 里氏替換原則:**任什麼時候候均可以用子類型替換掉父類型。(關於里氏替換原則的描述,Barbara Liskov女士的描述比這個要複雜得多,但簡單的說就是能用父類型的地方就必定能使用子類型。里氏替換原則能夠檢查繼承關係是否合理,若是一個繼承關係違背了里氏替換原則,那麼這個繼承關係必定是錯誤的,須要對代碼進行重構。例如讓貓繼承狗,或者狗繼承貓,又或者讓正方形繼承長方形都是錯誤的繼承關係,由於你很容易找到違反里氏替換原則的場景。須要注意的是:子類必定是增長父類的能力而不是減小父類的能力,由於子類比父類的能力更多,把能力多的對象當成能力少的對象來用固然沒有任何問題。)
**- 接口隔離原則:**接口要小而專,毫不能大而全。(臃腫的接口是對接口的污染,既然接口表示能力,那麼一個接口只應該描述一種能力,接口也應該是高度內聚的。例如,琴棋書畫就應該分別設計爲四個接口,而不該設計成一個接口中的四個方法,由於若是設計成一個接口中的四個方法,那麼這個接口很難用,畢竟琴棋書畫四樣都精通的人仍是少數,而若是設計成四個接口,會幾項就實現幾個接口,這樣的話每一個接口被複用的可能性是很高的。Java中的接口表明能力、表明約定、表明角色,可否正確的使用接口必定是編程水平高低的重要標識。)
**- 合成聚合複用原則:**優先使用聚合或合成關係複用代碼。
**- 迪米特法則:**迪米特法則又叫最少知識原則,一個對象應當對其餘對象有儘量少的瞭解。(迪米特法則簡單的說就是如何作到」低耦合」,門面模式和調停者模式就是對迪米特法則的踐行。對於門面模式能夠舉一個簡單的例子,你去一家公司洽談業務,你不須要了解這個公司內部是如何運做的,你甚至能夠對這個公司一無所知,去的時候只須要找到公司入口處的前臺美女,告訴她們你要作什麼,她們會找到合適的人跟你接洽,前臺的美女就是公司這個系統的門面。再複雜的系統均可覺得用戶提供一個簡單的門面,Java Web開發中做爲前端控制器的Servlet或Filter不就是一個門面嗎,瀏覽器對服務器的運做方式一無所知,可是經過前端控制器就可以根據你的請求獲得相應的服務。調停者模式也能夠舉一個簡單的例子來講明,例如一臺計算機,CPU、內存、硬盤、顯卡、聲卡各類設備須要相互配合才能很好的工做,可是若是這些東西都直接鏈接到一塊兒,計算機的佈線將異常複雜,在這種狀況下,主板做爲一個調停者的身份出現,它將各個設備鏈接在一塊兒而不須要每一個設備之間直接交換數據,這樣就減少了系統的耦合度和複雜度,以下圖所示。迪米特法則用通俗的話來將就是不要和陌生人打交道,若是真的須要,找一個本身的朋友,讓他替你和陌生人打交道。)
**4九、簡述一下你瞭解的設計模式。
**
答:所謂設計模式,就是一套被反覆使用的代碼設計經驗的總結(情境中一個問題通過證明的一個解決方案)。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
幾個經常使用的設計模式:
**- 工廠模式:**工廠類能夠根據條件生成不一樣的子類實例,這些子類有一個公共的抽象父類而且實現了相同的方法,可是這些方法針對不一樣的數據進行了不一樣的操做(多態方法)。當獲得子類的實例後,開發人員能夠調用基類中的方法而沒必要考慮到底返回的是哪個子類的實例。
**- 代理模式:**給一個對象提供一個代理對象,並由代理對象控制原對象的引用。
**- 適配器模式:**把一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口不匹配而沒法在一塊兒使用的類可以一塊兒工做。
**- 單例模式:**一個類只有一個實例,即一個類只有一個對象實例。
懶漢式單例模式,線程不安全,致命的是在多線程不能正常工做
public
class
Singleton {
private
static
Singleton instance =
null
;
private
Singleton() {}
public
static
synchronized
Singleton getInstance(){
if
(instance ==
null
) instance =
new
Singleton();
return
instance;
}
}
餓漢式單例模式,避免了多線程的同步問題
public
class
Singleton {
private
Singleton(){}
private
static
Singleton instance =
new
Singleton();
public
static
Singleton getInstance(){
return
instance;
}
}
50、用Java寫一個冒泡排序。
for(int i=0;i<arr.length-1;i++){//外層循環控制排序趟數
for(int j=0;j<arr.length-1-i;j++){//內層循環控制每一趟排序多少次
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
複製代碼
5一、用Java寫一個二分查找。
非遞歸實現:
public static int biSearch(int []array,int a){
int lo=0;
int hi=array.length-1;
int mid;
while(lo<=hi){
mid=(lo+hi)/2;
if(array[mid]==a){
return mid+1;
}else if(array[mid]<a){
lo=mid+1;
}else{
hi=mid-1;
}
}
return -1;
}
複製代碼
遞歸實現:
public static int sort(int []array,int a,int lo,int hi){
if(lo<=hi){
int mid=(lo+hi)/2;
if(a==array[mid]){
return mid+1;
}
else if(a>array[mid]){
return sort(array,a,mid+1,hi);
}else{
return sort(array,a,lo,mid-1);
}
}
return -1;
}
複製代碼
5二、Servlet的運行過程?
Web容器加載Servlet並將其實例化後,Servlet生命週期開始,容器運行其init()方法進行Servlet的初始化;請求到達時調用Servlet的service()方法,service()方法會根據須要調用與請求對應的doGet或doPost等方法;當服務器關閉或項目被卸載時服務器會將Servlet實例銷燬,此時會調用Servlet的destroy()方法。
5三、轉發(forward)和重定向(redirect)的區別?
答:forward是容器中控制權的轉向,是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL 的響應內容讀取過來,而後把這些內容再發給瀏覽器,瀏覽器根本不知道服務器發送的內容是從哪兒來的,因此它的地址欄中仍是原來的地址。redirect就是服務器端根據邏輯,發送一個狀態碼,告訴瀏覽器從新去請求那個地址,所以從瀏覽器的地址欄中能夠看到跳轉後的連接地址,很明顯redirect沒法訪問到服務器保護起來資源,可是能夠從一個網站redirect到其餘網站。forward更加高效,因此在知足須要時儘可能使用forward(經過調用RequestDispatcher對象的forward()方法,該對象能夠經過ServletRequest對象的getRequestDispatcher()方法得到),而且這樣也有助於隱藏實際的連接;在有些狀況下,好比須要訪問一個其它服務器上的資源,則必須使用重定向(經過HttpServletResponse對象調用其sendRedirect()方法實現)。
5四、JSP有哪些內置對象?做用分別是什麼?
答:JSP有9個內置對象:
- request:封裝客戶端的請求,其中包含來自GET或POST請求的參數;
- response:封裝服務器對客戶端的響應;
- pageContext:經過該對象能夠獲取其餘對象;
- session:封裝用戶會話的對象;
- application:封裝服務器運行環境的對象;
- out:輸出服務器響應的輸出流對象;
- config:Web應用的配置對象;
- page:JSP頁面自己(至關於Java程序中的this);
- exception:封裝頁面拋出異常的對象。
5五、講解JSP中的四種做用域。
答:JSP中的四種做用域包括page、request、session和application,具體來講:
- page表明與一個頁面相關的對象和屬性。
- request表明與Web客戶機發出的一個請求相關的對象和屬性。一個請求可能跨越多個頁面,涉及多個Web組件;須要在頁面顯示的臨時數據能夠置於此做用域。
- session表明與某個用戶與服務器創建的一次會話相關的對象和屬性。跟某個用戶相關的數據應該放在用戶本身的session中。
- application表明與整個Web應用程序相關的對象和屬性,它實質上是跨越整個Web應用程序,包括多個頁面、請求和會話的一個全局做用域。