1.00 什么時候使用基于接口編程?
基于接口編程、Fascade層等等抽象封裝都是有開發(fā)和維護的代價的,是否使用歸根結底還是要看團隊人員的分工情況,技術方面確實需要時,比如不同開發(fā)語言下連接;手機app與服務系統(tǒng)連接等,自然就要用了。
1.01 Package是先分層還是先分模塊?
org.springside.模塊A.web 還是 org.springside.web.模塊A? 同上,還是看團隊人員的分工情況。如果是每人從頭到尾負責一個獨立模塊的可以先分模塊,反之,按層進行分工并注重層內(nèi)重用的,可以考慮先分層。
1.02 怎么處理日志問題?有那些可行的方案?
首先要定義一個項目的異常處理類,然后所有需要處理異常的類就用該類來處理。日志的操作和處理就在該類中操作;
方案一:在service層的try catch中設置錯誤日志打?。?/p>
方案二:在filter攔截器中統(tǒng)一設置錯誤日志
1.03 反射機制
反射機制,就是當不確定類的類型時,采用java.lang.reflect方式定義轉換類的類型;
反射的功能很強大,但是使用不當可能會缺點大于優(yōu)點,反射使代碼邏輯混亂,會帶來維護的問題。眾所周知Java有個Object class,是所有Java classes的繼承根源。
1.04 面向對象理解
什么是OOP?什么是類?請對比類和對象實例之間的關系。OOP是面向對象編程縮寫。指的是用對象的觀點來組織與構建系統(tǒng),它綜合了功能抽象和數(shù)據(jù)抽象,這樣可以減少數(shù)據(jù)之間的耦合性和代碼的出錯幾率。使用面向對象編程技術可以使得軟件開發(fā)者按照現(xiàn)實世界里人們思考問題的模式編寫代碼,可以讓軟件開發(fā)者更好地利用代碼直接表達現(xiàn)實中存在的對象;類是同一類對象實例的共性的抽象,對象是類的實例化。對象通常作為計算機模擬思維,表示真實世界的抽象。類是靜態(tài)的,對象是動態(tài)的,類負責產(chǎn)生對象,可以將類當成生產(chǎn)對象的工廠。
1.05 基本數(shù)據(jù)類型
1、Java的數(shù)據(jù)類型可以劃分為4大類:整數(shù),浮點數(shù),字符型,布爾型。其中整數(shù)可以劃分為:byte,short,int,long.浮點數(shù)可以劃分為float,double。
2、char型變量中能不能存貯一個中文漢字?為什么?
答:是能夠定義成為一個中文的,因為java中以unicode編碼,一個char占16個字節(jié),所以放一個中文是沒問題的。
1.06 String與StringBuffer的區(qū)別。
String的長度是不可變的,StringBuffer的長度是可變的。如果你對字符串中的內(nèi)容經(jīng)常進行操作,特別是內(nèi)容要修改時,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法。
1.07數(shù)據(jù)類型大小及取值范圍
大小:byte 1個字節(jié)、short 2個字節(jié)、int 4個字節(jié)、long 8個字節(jié);char 2個字節(jié);float 4個字節(jié)、double 8個字節(jié);
取值范圍:
byte的取值范圍為-128~127,占用1個字節(jié)(-2的7次方到2的7次方-1)
short的取值范圍為-32768~32767,占用2個字節(jié)(-2的15次方到2的15次方-1)
int的取值范圍為(-2147483648~2147483647),占用4個字節(jié)(-2的31次方到2的31次方-1)
long的取值范圍為(-9223372036854774808~9223372036854774807),占用8個字節(jié)(-2的63次方到2的63次方-1)
可以看到byte和short的取值范圍比較小,而long的取值范圍太大,占用的空間多,基本上int可以滿足我們的日常的計算了,而且int也是使用的最多的整型類型了。
1.08 public、protected、private和不寫限定符有什么區(qū)別?
作用域
當前類
同一package
子孫類
其他package
public
√
√
√
√
protected
√
√
√
×
friendly(不寫時默認)
√
√
×
×
private
√
×
×
×
1.09 線程理解
1、請說出你所知道的線程同步的方法。
wait():是線程交互時,如果線程對一個同步對象x 發(fā)出一個wait()調(diào)用,該線程會暫停執(zhí)行,被調(diào)對象進入等待狀態(tài),直到被喚醒或等待時間到。
sleep():是使線程停止一段時間的方法。在sleep 時間間隔期滿后,線程不一定立即恢復執(zhí)行。這是因為在那個時刻,其它線程可能正在運行而且沒有被調(diào)度為放棄執(zhí)行,除非(a)“醒來”的線程具有更高的優(yōu)先級 (b)正在運行的線程因為其它原因而阻塞。 是一個靜態(tài)方法,調(diào)用此方法要捕捉InterruptedException異常。
notify():喚醒一個處于等待狀態(tài)的線程,注意的是在調(diào)用此方法的時候,并不能確切的喚醒某一個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且不是按優(yōu)先級。
Allnotity():喚醒所有處入等待狀態(tài)的線程,注意并不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。
2、線程實現(xiàn)方法有哪些?
方法一:定義一個類實現(xiàn)Runnable接口,重寫接口中的run()方法。在run()方法中加入具體的任務代碼或處理邏輯。調(diào)用Thread對象的start()方法,啟動線程,如:
方法二:定義一個類去繼承Thread父類,重寫父類中的run()方法。在run()方法中加入具體的任務代碼或處理邏輯。調(diào)用start方法,線程t啟動,隱含的調(diào)用run()方法。如:
3、什么時候使用Thread,什么時候使用Runable
采用繼承Thread類方式:
(1)優(yōu)點:編寫簡單,如果需要訪問當前線程,無需使用Thread.currentThread()方法,直接使用this,即可獲得當前線程。
(2)缺點:因為線程類已經(jīng)繼承了Thread類,所以不能再繼承其他的父類。
采用實現(xiàn)Runnable接口方式:
(1)優(yōu)點:線程類只是實現(xiàn)了Runable接口,還可以繼承其他的類。在這種方式下,可以多個線程共享同一個目標對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU代碼和數(shù)據(jù)分開,形成清晰的模型,較好地體現(xiàn)了面向對象的思想。
(2)缺點:編程稍微復雜,如果需要訪問當前線程,必須使用Thread.currentThread()方法。
4、當一個線程進入一個對象的一個synchronized方法后,其它線程是否可進入此對象的其它方法?不能,一個對象的一個synchronized方法只能由一個線程訪問。
5、多線程有哪些狀態(tài)?
新建、就緒(start方法調(diào)用后)、運行、睡眠(sleep方法)、等待(wait方法)、掛起、恢復、阻塞、死亡。
1.10 各種集合理解(幾種常見數(shù)據(jù)結構)
1、HashMap和Hashtable的區(qū)別:
HashMap允許一個null鍵值而Hashtable不可以;Hashtable是線程安全的,同步的,因此要比HashMap運行慢;
2、Collection 和 Collections的區(qū)別:
Collections是個java.util下的類,它包含有各種有關集合操作的靜態(tài)方法。Collection是個java.util下的接口,它是各種集合結構的父接口。
3、Set里的元素是不能重復的,那么用什么方法來區(qū)分重復與否呢? 是用==還是equals()? 它們有何區(qū)別?
Set里的元素是不能重復的,那么用iterator()方法來區(qū)分重復與否。equals()是判讀兩個Set是否相等。
4、ArrayList和Vector的區(qū)別
同步性:Vector是線程安全的,也就是說是同步的,而ArrayList是線程序不安全的,不是同步的;
數(shù)據(jù)增長:當需要增長時,Vector默認增長為原來一培,而ArrayList卻是原來的一半;
5、LinkList和ArrayList的區(qū)別,如果是在集合的開頭插入一個對象,使用哪種效率高些,在集合的末尾插入一個對象,使用哪種效率高些,為什么?
ArrayList隨機訪問的效率要比LinkList快,但是LinkList順序訪問的效率則高過ArrayList,另外LinkList在對元素進行插入和刪除操作時要比ArrayList的效率高,二者的最佳選擇方法是:首先選用ArrayList當發(fā)現(xiàn)“向元素中插入和刪除操作太多時”引發(fā)性能問題時,換用LinkList,當然處理固定元素還是選用數(shù)組.
LinkedList基于鏈表實現(xiàn),插入元素的性能會比ArrayList高.
ArrayList基于數(shù)組實現(xiàn),遍歷的性能高于LinkedList.
1.11 繼承、重寫、重載、多態(tài)
繼承是子類使用父類的方法,
重寫是繼承后重新實現(xiàn)父類的方法。
重載是在一個類里一系列參數(shù)不同名字相同的方法。
多態(tài)則是父類使用子類的方法。
子類繼承父類程序運行執(zhí)行順序:
父類:
public class TestStatic {
public static String name="china";
{
System.out.println("========方法體========");
}
static{
name="England";
System.out.println("========靜態(tài)程序塊======");
}
TestStatic(){
System.out.println("=========構造方法========");
}
public static void main(String[] args){
System.out.println("========主方法========"+name);
}
public void test(){
System.out.println("========測試方法=========");
}
}
子類:
public class TestExtendStatic extends TestStatic{
//public static String name="HUBEI";
{
System.out.println("========無名稱方法體========");
}
static{
//name="SUIZHOU";
System.out.println("========子類靜態(tài)程序塊======");
}
TestExtendStatic(){
System.out.println("=========子類構造方法========");
}
public void test(){
System.out.println("========子類測試方法=========");
}
public static void main(String[] args){
System.out.println("========子類主方法========"+name);
TestStatic ts = new TestExtendStatic();// 上轉型對象
ts.test();
}
}
輸出如下:
========靜態(tài)程序塊====== :父類static程序塊
========子類靜態(tài)程序塊====== :子類static程序塊 【不是靜態(tài)方法】
========子類主方法========England :子類主方法
========方法體======== :父類中非靜態(tài)代碼塊
=========構造方法======== :父類構造方法
========無名稱方法體======== :子類中非靜態(tài)代碼塊
=========子類構造方法======== :子類構造方法
========子類測試方法========= :子類測試方法
執(zhí)行順序: 父類靜態(tài)變量以及靜態(tài)程序塊 --- 子類的靜態(tài)變量以及靜態(tài)程序塊 --- 父類非靜態(tài)代碼塊 --- 父類中構造方法 --- 子類中非靜態(tài)代碼塊 ---子類中構造方法 --- 接下來才是 對象調(diào)用的方法。
只要是用new 創(chuàng)建對象,分配了內(nèi)存空間,不管是將引用賦給上轉型對象,還是賦給子類對象,上面方法都必須執(zhí)行。
即:TestStatic ts = new TestExtendStatic();// 上轉型對象
TestExtendStatic ts = new TestExtendStatic();// 子類對象
上面加粗程序都會執(zhí)行。
上面程序中 ts.test(); ts作為上轉型對象調(diào)用的是 子類繼承的父類中的方法,因為test()在子類中被重寫了,所以輸出的為子類中的語句。
如果將子類中 main 方法該成如下:
public static void main(String[] args){
System.out.println("========子類主方法========"+name);
TestStatic ts = new TestExtendStatic();
ts.test();
System.out.println("-------------------------");
ts = new TestExtendStatic();
ts.test();
}
輸出:
========靜態(tài)程序塊====== 父類中靜態(tài)程序塊
========子類靜態(tài)程序塊====== 子類中靜態(tài)程序塊
========子類主方法========England 子類中主方法
========方法體======== 父類中非靜態(tài)代碼塊
=========構造方法======== 父類中構造方法
========無名稱方法體======== 子類中非靜態(tài)程序塊
=========子類構造方法======== 子類中構造方法
========子類測試方法========= 對象具體調(diào)用的方法
------------------------- 靜態(tài)變量以及程序塊只執(zhí)行一次
========方法體======== 父類中非靜態(tài)代碼塊
=========構造方法======== 父類中構造方法
========無名稱方法體======== 子類中非靜態(tài)代碼塊
=========子類構造方法======== 子類中構造方法
========子類測試方法=========
如果將子類主方法 中更改為:
TestStatic ts = new TestStatic ();// 運用父類構造方法創(chuàng)建
ts.test();
輸出為:
========靜態(tài)程序塊====== 父類靜態(tài)程序塊
========子類靜態(tài)程序塊====== 子類靜態(tài)程序塊 【因為程序在子類中運行的,所以子類的靜態(tài)程序塊必須運行】
========方法體======== 父類非靜態(tài)程序塊
=========構造方法======== 父類構造方法
========測試方法========= 父類具體方法test()
如果將上述代碼放到父類中,就不會加載子類 靜態(tài)程序塊了。
1.12關聯(lián)與依賴差別,聚合與組合差別
關聯(lián):一個類受另外一個類的影響,一個Driver類里面只跟一個Car類變量,如driver(Car),強耦合關系;
依賴:一種使用關系,弱耦合,比如兩個方法driver(Car),driver(Plane);即重載;
聚合:是弱擁有關系,即A對象包含B對象,但B不是A的一部分;
組合:是一種強擁有關系,主要體現(xiàn)部分和整體的關系;
1.13 排序
1、java類自帶排序:
組成int數(shù)組,再調(diào)用Arrays.sort(int[] a)實現(xiàn)升序;降序可從尾部開始輸出;
2、方法二:重復for循環(huán)比較兩值大小存入ArrayList中;
1.14 JAVA序列化
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內(nèi)容進行流化??梢詫α骰蟮膶ο筮M行讀寫操作,也可將流化后的對象傳輸于網(wǎng)絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發(fā)的問題。
序 列化的實現(xiàn):將需要被序列化的類實現(xiàn)Serializable接口,該接口沒有需要實現(xiàn)的方法,implements Serializable只是為了標注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream)來構造一個 ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數(shù)為obj的對象寫出(即保存其狀態(tài)),要恢復的話則用輸入流。
1.15 面向對象的設計原則有那些?
LSP里氏替換原則:子類與父類對象間替換;
OCP開閉原則:擴展開放,更改封閉;
SRP單一職責原則:依賴不同的具體類,不要將不相關的方法放到一個具體類中,然后具體類再關聯(lián)。
ISP接口隔離原則:具體類不要實現(xiàn)無關接口中的方法,應使用具體類實現(xiàn)多個接口。
DIP依賴倒置原則:針對接口編程,不是針對實現(xiàn)編程
CARP組合/聚合復用原則:盡量使用組合/聚合,而不是使用繼承來達到復用目的
LoD迪米特法則:類間最少通信原則,采用中間類。
1.16 Java中的網(wǎng)絡通信有那些方式,有什么區(qū)別?
分別是TCP和UDP;
TCP是一種面向連接的保證可靠傳輸?shù)膮f(xié)議。通過TCP實現(xiàn)的傳輸,得到的是一個順序的無差錯的數(shù)據(jù)流。發(fā)送方和接收方成對的兩個socket之間必須建立連接,以便在TCP的基礎上進行通信, 而UDP是一種無連接的協(xié)議,每個數(shù)據(jù)都是一個獨立的信息,包括完整的源地址和目的地址 ,UDP是不可靠的。
1.17一個程序編譯完成后在內(nèi)存中是如何存儲的?
不存儲在內(nèi)存條上,存儲在硬盤上,當需要程序運行時,程序被加載到內(nèi)存條上。
1.18 IO流
在java使用流的機制進行數(shù)據(jù)的傳送,從文件到內(nèi)存是輸入流,從內(nèi)存到文件是輸出流,輸入流可以通過 read讀取,輸出流以write或print寫入,對于流可以是分為高層流和低層流,低層以一個字節(jié)或字符為單位進行處理,高層流以一批數(shù)據(jù)為單位進行處理。
FileInputStream(System.in)至InputSteamReader至BufferReader
OutputSteam(System.out)至printStream
FileReader至BufferedReader
FileWriter 至 PrintWriter或bufferWriter
分類:
字節(jié)(二進制)
FileInputStream(低層輸入流)
FileOutputStream(低層輸出流)
PrintStream(高層流) System.out.println()
字符(一個char)
FileReader
FileWriter
在java.io包中還有許多其他的流,主要是為了提高性能和使用方便
1.19為什么重寫equals()時也要重寫hashCode()?兩者什么關系
因為這兩個函數(shù)都可以重寫;完全可以hashcode相等的對象而equals確返回false;重寫hashCode是為了集合類存儲這些對象的時候有個比較規(guī)則;比如Map不允許重復元素,就是通過hashCode來檢測的;但是hashcode的實現(xiàn),一般要滿足幾個特征,比如:自反性,傳遞性什么的。
更多信息請查看IT技術專欄