問題1:
代碼如下:
public class Test
{
Test t = new Test();
public static void main(String[] args)
{
Test t = new Test();
}
}
程序爲何會報錯誤:Exception in thread "main" java.lang.StackOverflowError;
原因:
1.JAVA中初始化的順序:加載類、靜態成員變量初始化、靜態代碼塊、非靜態成員變量初始化、構造方法;後兩個是對象的初始化時初始化的;
2.在main方法裏new Test(),new了一個Test對象,想要完成Test對象的初始化,就得初始化它的非靜態成員變量,於是又new了一個Test對象,想要完成第二個Test對象的初始化,你就得初始化它的非靜態成員變量,如此一直遞歸下去,一直new Test對象,棧的內存就滿了;
3.可以添加一點代碼,如下,看程序的執行過程;
public class Test
{
public Test()
{
System.out.println("我在實例化");
}
Test t = new Test();
public static void main(String[] args)
{
System.out.println("begin");
Test t = new Test();
}
}
問題2:
請在程序中指定位置添加一段代碼;
public class RightDemo
{
public static void main(String[] args)
{
int i = 0;
{
// 添加一段代碼使得控制檯輸出right
}
if (i + 1 < i)
{
System.out.println("right");
}
else
{
System.out.println("wrong");
}
}
}
答案:i = Integer.MAX_VALUE;
原因:此題考察的是 Integer.MAX_VALUE+1==Integer.MIN_VALUE;即int類型的最大值加1等於int類型的最小值;
問題3:
爲什麼要使用數據庫連接池?
原因:
(1)JAVA語言通過JDBC技術訪問數據庫,但使用JDBC會有一些問題,首先,每一次web請求都要建立一次數據庫連接,建立連接是一個費時的活動,每次都得花費0.05s~1s的時間,而且系統還要分配內存資源;這個時間對於一次或幾次數據庫操作,或許感覺不出系統有多大的開銷。可是對於現在的Web應用,尤其是大型電子商務網站,同時有幾百人甚至幾千人在線是很正常的事。在這種情況下,頻繁的進行數據庫連接操作勢必佔用很多的系統資源,網站的響應速度必定下降,嚴重的甚至會造成服務器的崩潰。
(2)不是危言聳聽,這就是制約某些電子商務網站發展的技術瓶頸問題。其次,對於每一次數據庫連接,使用完後都得斷開。否則,如果程序出現異常而未能關閉,將會導致數據庫系統中的內存泄漏,最終將不得不重啓數據庫。還有,這種開發不能控制被創建的連接對象數,系統資源會被毫無顧及的分配出去,如連接過多,也可能導致內存泄漏,服務器崩潰。
(3)因此,引用了數據庫連接池技術。數據庫連接池的基本思想就是爲數據庫連接建立一個“緩衝池”。預先在緩衝池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩衝池”中取出一個,使用完畢之後再放回去。我們可以通過設定連接池最大連接數來防止系統無盡的與數據庫連接。更爲重要的是我們可以通過連接池的管理機制監視數據庫的連接的數量﹑使用情況,爲系統開發﹑測試及性能調整提供依據;
(4)通俗的介紹JDBC和連接池就是:連接池裏就是JDBC的Connection實例,只不過加了超時等管理,節省資源而已;
(5)連接池和JDBC的比喻:想吃蘋果,兩種方式:1,一次買5個放冰箱裏,每次吃的時候從冰箱裏拿一個吃;2,想吃的時候買一個;
(6)優點:最主要的就是連接的重複使用,提高性能:
問題4:
一段可讀性很差的for循環:
class Fu
{
boolean show(char a)
{
System.out.println(a);
return true;
}
}
public class Demo extends Fu
{
public static void main(String[] args)
{
int i = 0;
Fu f = new Demo();
Demo d = new Demo();
for (f.show('A'); f.show('B') && (i < 2); f.show('C'))
{
i++;
d.show('D');
}
}
boolean show(char a)
{
System.out.println(a);
return false;
}
}
解釋一下:
我們常規的for循環中表達式一般不是boolean型,所以感覺可讀性很差;
從main方法開始,直接看循環,第一步,f.show('A'),調用Demo類的show方法,打印A;第二步,f.show('B')調用Demo類的show方法,打印B,並且返回值爲false,所有這個表達式f.show('B') && (i<2)返回false,條件不成立,終止循環;這個題考察的就是for的執行過程和多態的應用;
問題5:
一段Java的源代碼:
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
這是java 源代碼中關於HashMap的定義,我想知道的是,爲什麼HashMap的父類AbstractMap已經implements了Map<K,V>接口,而在HashMap的定義中又再一次的聲明implements Map<K,V>接口呢,這麼做有什麼意義呢?
原因:
從編譯和運行的角度來說,沒有意義。
但是從讀者的角度來說,有意義。
你可以考慮一下如下場景:
1,你定義了一個接口,裏面有10個抽象方法(接口裏面的都是抽象方法)
2,你有9個抽象類,抽象類1繼承接口,實現了1個方法(可以只實現接口的部分方法)
3,抽象類2繼承抽象類1,同時又多實現了一個方法
4,依次類推,每個抽象類依次繼承上面的抽象類,每個都多實現一個方法。
5,最後你的實現類實現抽象類9,把最後一個未實現的方法實現了。
那麼問題來了
這時候你讀源代碼或者文檔的時候,你根本不知道你這個類實現了什麼接口,如果想知道的話,就要依次把抽象類9,8。。。一直找到抽象類1的時候,你才知道你的這個實現類實際上是實現了你第一步定義的接口,這樣是不是對讀者很不友好?
如果每一層都明確聲明實現了第一步的接口,那麼你看實現類或者任一層次的抽象類的時候,你都不需要再找別的繼承關係的類了,因爲你可以直接跳到接口去看定義就可以了。
這就是對讀者友好的體現,代碼主要是給人看的,對於機器來說,他只需要2進制字節就可以了;
Why does Atomiclnteger implements Serializable
why does LinkedHashSet extends HashSet and implements Set
其中一篇文章的答案是Java的Collections Framework的作者的觀點,這個夠官方了;