Java基礎總結--面試答案個人總結
答案為自己總結
1、面向物件的特徵有哪些方面?
封裝,繼承,多型
封裝: 就是類的私有化。將程式碼及處理資料繫結在一起的一種程式設計機制,該機制保證程式和資料不受外部干擾。
繼承: 就是保留父類的屬性,開擴新的東西。通過子類可以實現繼承,子類繼承父類的所有狀態和行為,同時新增自身的狀態和行為。Java中的類不支援多繼承(一個兒子只能有一個爹),介面支援多繼承,可以實現多個介面
多型: 是允許將父物件設定成為和一個和多個它的子物件相等的技術。包括過載和重寫。過載為編譯時多型,重寫是執行時多型。
2、訪問修飾符public,private,protected,以及不寫(預設)時的區別?
3、String 是最基本的資料型別嗎?
不是,String是引用資料型別
4、float f=3.4;是否正確?
不對, 3.4預設是int型別, int型別不能自動轉換成float型別
float f = 3.4f
float的指數範圍為-127~128,而double的指數範圍為-1023~1024
5、short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?
前者正確,後者有誤
short型別的s1和int型的1相加,會自動提升為int型,但是左邊用short接受,編譯就會報錯
但是 s1 += 1反編譯過來其實是 s1 = (short) s1 + 1,所以不會有誤
6、Java有沒有goto?
有,但作為保留字(像break,return但是是沒有用到的關鍵字)
7、int和Integer有什麼區別?
8種基本資料型別: byte,short,int,long,float,double,char,true/false
int是基本資料型別,integer是引用資料型別
int使用時可以先不賦值,integer使用時要先賦值
8、&和&&的區別?
&和&&的兩端表示式同時為真時,表示式的結果為真,只要有一端為假,那麼表示式結果為假
& :兩個條件比較時,不管前者為true或false,後者都會執行; 無論左邊結果是什麼,右邊還是繼續運算;
&&: 只有當前者為true時,後者才會執行; 當左邊為假,右邊不再進行運算
| 和 || 兩端表示式同時為假時,表示式的結果為假,只要有一端為真,那麼表示式結果為真
| : 無論左邊結果是什麼,右邊還是繼續運算;
||: 當左邊為真,右邊不再進行運算。
9、解釋記憶體中的棧(stack)、堆(heap)和靜態區(static area)的用法。
堆區:專門用來儲存物件的例項(new 建立的物件和陣列),實際上也只是儲存物件例項的屬性值,屬性的型別和物件本身的型別標記等,並不儲存物件的方法(方法是指令,儲存在Stack中)
1.儲存的全部是物件,每個物件都包含一個與之對應的class的資訊。(class的目的是得到操作指令)2.jvm只有一個堆區(heap)被所有執行緒共享,堆中不存放基本型別和物件引用,只存放物件本身.
3.一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由OS回收 。
棧區:物件例項在Heap 中分配好以後,需要在Stack中儲存一個4位元組的Heap記憶體地址,用來定位該物件例項在Heap 中的位置,便於找到該物件例項。
1.每個執行緒包含一個棧區,棧中只儲存基礎資料型別的物件和自定義物件的引用(不是物件),物件都存放在堆區中
2.每個棧中的資料(原始型別和物件引用)都是私有的,其他棧不能訪問。
3.棧分為3個部分:基本型別變數區、執行環境上下文、操作指令區(存放操作指令)。
4.由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等.
靜態區/方法區:
1.方法區又叫靜態區,跟堆一樣,被所有的執行緒共享。方法區包含所有的class和static變數。
2.方法區中包含的都是在整個程式中永遠唯一的元素,如class,static變數。
3.全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。
10、Math.round(11.5) 等於多少?Math.round(-11.5)等於多少?
Math.round() 將括號內的數+0.5之後,向下取值,即為12
Math.round(-11.5) 為 -10
11、switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?
*switch可作用於char byte short int 以及他們對應的包裝類
* switch不可作用於long double float boolean,包括他們的包裝類
* switch中可以是字串型別,String(jdk1.7之後才可以作用在string上)
* switch中可以是列舉型別
12、用最有效率的方法計算2乘以8?
2 << 3,
因為將一個數左移n 位,就相當於乘以了2 的n 次方,那麼,一個數乘以8 只要將其左移3 位即可,而位運算cpu 直接支援的,效率最高,所以,2 乘以8 等於幾的最效率的方法是2 << 3。
13、陣列有沒有length()方法?String有沒有length()方法?
有,沒有
String有length屬性
14、在Java中,如何跳出當前的多重巢狀迴圈?
可以在外面的迴圈語句前定義一個標號,然後在裡層迴圈體的程式碼中使用帶有標號的break 語句,即可跳出外層迴圈
如: 定義 ok: 標號
使用時在內層迴圈巢狀使用帶有標號的break break ok; 即可跳出當前多重迴圈
15、構造器(constructor)是否可被重寫(override)?
不可以,可以被過載
重寫: 方法名,引數,返回值均相同,方法體不同
過載: 方法名相同, 引數型別和個數不同, 返回型別可以相同也可以不同
16、兩個物件值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?
對,equals比較的是內容值, ==比較的是地址值
17、是否可以繼承String類?
不可以,String類是被final修飾過的
18、當一個物件被當作引數傳遞到一個方法後,此方法可改變這個物件的屬性,並可返回變化後的結果,那麼這裡到底是值傳遞還是引用傳遞?
值傳遞
19、String和StringBuilder、StringBuffer的區別?
String 字串常量
StringBuffer 字串變數(執行緒安全)
StringBuilder 字串變數(非執行緒安全)
執行速度: StringBuilder > StringBuffer > String
1. String最慢的原因:
String為字串常量,而StringBuilder和StringBuffer均為字串變數,即String物件一旦建立之後該物件是不可更改的,但後兩者的物件是變數,是可以更改的。以下面一段程式碼為例:
String str="abc";
System.out.println(str);
str=str+"de";
System.out.println(str);
如果執行這段程式碼會發現先輸出“abc”,然後又輸出“abcde”,好像是str這個物件被更改了,其實,這只是一種假象罷了,JVM對於這幾行程式碼是這樣處理的,首先建立一個String物件str,並把“abc”賦值給str,然後在第三行中,其實JVM又建立了一個新的物件也名為str,然後再把原來的str的值和“de”加起來再賦值給新的str,而原來的str就會被JVM的垃圾回收機制(GC)給回收掉了,所以,str實際上並沒有被更改,也就是前面說的String物件一旦建立之後就不可更改了。所以,Java中對String物件進行的操作實際上是一個不斷建立新的物件並且將舊的物件回收的一個過程,所以執行速度很慢。
而StringBuilder和StringBuffer的物件是變數,對變數進行操作就是直接對該物件進行更改,而不進行建立和回收的操作,所以速度要比String快很多。
另外,有時候我們會這樣對字串進行賦值
String str="abc"+"de";
StringBuilder stringBuilder=new StringBuilder().append("abc").append("de");
System.out.println(str);
System.out.println(stringBuilder.toString());
這樣輸出結果也是“abcde”和“abcde”,但是String的速度卻比StringBuilder的反應速度要快很多,這是因為第1行中的操作和
String str="abcde";
是完全一樣的,所以會很快,而如果寫成下面這種形式
String str1="abc";
String str2="de";
String str=str1+str2;
那麼JVM就會像上面說的那樣,不斷的建立、回收物件來進行這個操作了。速度就會很慢。
執行緒安全: StringBuilder是執行緒不安全的,而StringBuffer是執行緒安全的
如果一個StringBuffer物件在字串緩衝區被多個執行緒使用時,StringBuffer中很多方法可以帶有synchronized關鍵字,所以可以保證執行緒是安全的,但StringBuilder的方法則沒有該關鍵字,所以不能保證執行緒安全,有可能會出現一些錯誤的操作。所以如果要進行的操作是多執行緒的,那麼就要使用StringBuffer,但是在單執行緒的情況下,還是建議使用速度比較快的StringBuilder。
3. 總結
String:適用於少量的字串操作的情況
StringBuilder:適用於單執行緒下在字元緩衝區進行大量操作的情況
StringBuffer:適用多執行緒下在字元緩衝區進行大量操作的情況
20、過載(Overload)和重寫(Override)的區別。過載的方法能否根據返回型別進行區分?
重寫: 方法名,引數,返回值均相同,方法體不同
過載: 方法名相同, 引數型別和個數不同, 返回型別可以相同也可以不同
21、描述一下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的引用。
22、char 型變數中能不能存貯一箇中文漢字,為什麼?
* char型變數是用來儲存Unicode編碼的字元的,unicode編碼字符集中包含了漢字,
* 所以,char型變數中當然可以儲存漢字啦。不過,如果某個特殊的漢字沒有被包含在
* unicode編碼字符集中,那麼,這個char型變數中就不能儲存這個特殊漢字。補充
* 說明:unicode編碼佔用兩個位元組,所以,char型別的變數也是佔用兩個位元組
23、抽象類(abstract class)和介面(interface)有什麼異同?
相同: 他們都不能被例項化; 介面的實現類或抽象類的子類都必須實現了介面或者抽象類的方法才能被例項化
不同:
1. 介面只有方法定義,不能在介面中寫具體的實現,實現介面的類要實現介面所有的方法,抽象類可以有定義與具體的實現
2. 介面要實現,抽象類要繼承,一個類可以實現多個介面, 但只能繼承一個抽象類
3. 介面設計理念是"has - a"的關係, 抽象類的設計理念強調是"is - a"的關係
4. 介面中定義變數預設值是public static final 且要賦初值,方法必須是public,static,且只能是這兩個; 抽象類中可以有自己的資料成員變數,也可以有非抽象的成員方法,而且成員變數預設為default。
這些成員變數可以在子類中被重新定義,也可以重新賦值,抽象方法(有abstract修飾)不能用peivate,static,synchronized,native等訪問修飾符修飾,同時方法以分號結尾,並且不帶花括號
5. 介面被運用於比較常用的功能,便於日後的維護或者新增刪除方法;而抽象類更傾向於充當公共類的角色,不適用於對裡面的程式碼進行修改
24、靜態巢狀類(Static Nested Class)和內部類(Inner Class)的不同?
25、Java 中會存在記憶體洩漏嗎,請簡單描述。
會,例如建立了一個物件,但是一直沒有用,但這個物件卻一直被引用,GC無法對他進行回收,就會出現記憶體洩漏(遞迴)
26、抽象的(abstract)方法是否可同時是靜態的(static),是否可同時是本地方法(native),是否可同時被synchronized修飾?
不可以
27、闡述靜態變數和例項變數的區別。
靜態變數: 由static修飾,可以直接類名 呼叫,也可以物件呼叫, 而且所有物件的同一個類變數 都是共享同一塊記憶體空間。
例項變數: 沒有static修飾,必須建立物件後使用物件呼叫, 而且所有物件的同一個例項變數是共享不同的記憶體空間的。
靜態變數是所有變數共有的,某一個物件將他的值改變了,其他物件再次取到的值就是改變後的值
例項變數則是私有的,某一物件將值改變,不影響其他物件的值
在建立例項物件的時候,記憶體中會為每一個例項物件的每一個非靜態成員變數開闢一段記憶體空間,用來儲存這個物件所有的非靜態成員變數值。即使兩個不同的例項物件是屬於同一個類,它們的同名非靜態成員變數在記憶體中佔用的空間是不同的。
靜態成員變數有所不同。所有的例項物件都共用一個靜態變數,記憶體中只有同一處空間存放這個靜態變數值的。因此,如果一個物件把靜態變數值改了,另外一個物件再取靜態變數值就是改過之後的值了。
28、是否可以從一個靜態(static)方法內部發出對非靜態(non-static)方法的呼叫?
不可以, 靜態方法是可以直接呼叫的, 而非靜態方法只能先建立物件才能呼叫, 靜態方法在呼叫非靜態的時候有可能非靜態方法還沒有建立物件
29、如何實現物件克隆?
基本資料型別可以直接用=號賦值克隆,但是物件就不行了
int a = 10;
int b = a; 則把a克隆給b
要想實現物件克隆
1. 實現Cloneable介面,呼叫Cloneable的clone方法(重寫clone方法為public)
2. 實現Serializable介面,通過物件的序列化和反序列化實現克隆,可以實現真正的深度克隆,程式碼如下.
30、String s = new String("xyz");建立了幾個字串物件?
2個物件.
JVM首先是在字串常量池中找"xzy" 字串,如果沒有建立字串常量,然後放到常量池中,若已存在,則不需要建立;當遇到 new 時,還會在記憶體(不是字串常量池中)上建立一個新的String物件,儲存"xzy",並將記憶體上的String物件引用地址返回
31、介面是否可繼承(extends)介面?抽象類是否可實現(implements)介面?抽象類是否可繼承具體類(concrete class)?
可以繼承介面,
抽象類可以實現抽象類
抽象類可以繼承具體抽象類,也可以繼承抽象類
32、一個".java"原始檔中是否可以包含多個類(不是內部類)?有什麼限制?
可以有多個類,但只能有一個public類
33、Anonymous Inner Class(匿名內部類)是否可以繼承其它類?是否可以實現介面?
匿名內部類不能繼承其他類,不可以實現介面,但他可以作為介面供其他類實現
34、內部類可以引用它的包含類(外部類)的成員嗎?有沒有什麼限制?
如果不是靜態內部類,完全可以。那沒有什麼限制!
在靜態內部類下,不可以訪問外部類的普通成員變數,而只能訪問外部類中的靜態成員
35、Java 中的final關鍵字有哪些用法?
(1)修飾類:表示該類不能被繼承;
(2)修飾方法:表示方法不能被重寫;
(3)修飾變數:表示變數只能賦值一次且賦值以後值不能被修改(常量)。
36、資料型別之間的轉換:
基本資料型別可以將低階的自動轉換為高階的資料型別
37、如何實現字串的反轉及替換?
可用字串構造一 StringBuffer 物件,然後呼叫 StringBuffer 中的 reverse方法即可實現字串的反轉,呼叫 replace 方法即可實現字串的替換。
38、怎樣將GB2312編碼的字串轉換為ISO-8859-1編碼的字串?
String result = new String(s.getBytes("GB2312"),"iso-8859-1");
String類中getBytes(”編碼“)方法可以將一個數用指定的編碼轉成一個位元組陣列,String中通過指定的 charset解碼指定的 byte 陣列,構造一個新的 String
39、日期和時間:
40、列印昨天的當前時刻。
1. 使用calendar類
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -1);
2. java8中的方法
LocalDateTime today = LocalDateTime.now();
LocalDateTime yesterday = today.minusDays(1);
41、比較一下Java和JavaSciprt。
Java是面向物件的一門語言,javaScript是指令碼語言,其中可以寫Java程式碼
42、什麼時候用斷言(assert)?
43、Error和Exception有什麼區別?
Error類和Exception類的父類都是throwable類
Error類一般是指與虛擬機器相關的問題,如系統崩潰,虛擬機器錯誤,記憶體空間不足,方法呼叫棧溢等。對於這類錯誤的導致的應用程式中斷,僅靠程式本身無法恢復和和預防,遇到這樣的錯誤,建議讓程式終止。
Exception類表示程式可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該儘可能處理異常,使程式恢復執行,而不應該隨意終止異常。
Exception類又分為執行時異常(Runtime Exception)和受檢查的異常(Checked Exception ),執行時異常;ArithmaticException,IllegalArgumentException,編譯能通過,但是一執行就終止了,程式不會處理執行時異常,出現這類異常,程式會終止。而受檢查的異常,要麼用try。。。catch捕獲,要麼用throws字句宣告丟擲,交給它的父類處理,否則編譯不會通過。
44、try{}裡有一個return語句,那麼緊跟在這個try後的finally{}裡的程式碼會不會被執行,什麼時候被執行,在return前還是後?
會執行, 在return後執行
45、Java語言如何進行異常處理,關鍵字:throws、throw、try、catch、finally分別如何使用?
try塊表示程式正常的業務執行程式碼。如果程式在執行try塊的程式碼時出現了“非預期”情況,JVM將會生成一個異常物件,這個異常物件將會被後面相應的catch塊捕獲。
catch塊表示一個異常捕獲塊。當程式執行try塊引發異常時,這個異常物件將會被後面相應的catch塊捕獲。
throw用於手動地丟擲異常物件。throw後面需要一個異常物件。
throws用於在方法簽名中宣告丟擲一個或多個異常類,throws關鍵字後可以緊跟一個或多個異常類。
finally塊代表異常處理流程中總會執行的程式碼塊。
對於一個完整的異常處理流程而言,try塊是必須的,try塊後可以緊跟一個或多個catch塊,最後還可以帶一個finally塊。
try塊中可以丟擲異常。
46、執行時異常與受檢異常有何異同?
RuntimeException在預設情況下會得到自動處理。所以通常用不著捕獲RuntimeException,但在自己的封裝裡,也許仍然要選擇丟擲一部分RuntimeException。
除了runtimeException以外的異常,都屬於checkedException,它們都在java.lang庫內部定義。Java編譯器要求程式必須捕獲或宣告丟擲這種異常。
一個方法必須通過throws語句在方法的宣告部分說明它可能丟擲但並未捕獲的所有checkedException。
47、列出一些你常見的執行時異常?
ClassCastException,IndexOutOfBoundsException,
NullPointerException, NumberFormatException,
StringIndexOutOfBoundsException
48、闡述final、finally、finalize的區別。
final用於宣告屬性,方法和類,分別表示屬性不可交變,方法不可覆蓋,類不可繼承。
finally是異常處理語句結構的一部分,表示總是執行。
finalize是Object類的一個方法,在垃圾收集器執行的時候會呼叫被回收物件的此方法,供垃圾收集時的其他資源回收,例如關閉檔案等。
49、類ExampleA繼承Exception,類ExampleB繼承ExampleA。
請問執行此段程式碼的輸出是什麼?
50、List、Set、Map是否繼承自Collection介面?
list,set 是, map不是
51、闡述ArrayList、Vector、LinkedList的儲存效能和特性。
ArrayList 和Vector他們底層的實現都是一樣的,都是使用陣列方式儲存資料,此陣列元素數大於實際儲存的資料以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及陣列元素移動等記憶體操作,所以索引資料快而插入資料慢。
Vector中的方法由於添加了synchronized修飾,因此Vector是執行緒安全的容器,但效能上較ArrayList差,因此已經是Java中的遺留容器。
LinkedList使用雙向連結串列實現儲存(將記憶體中零散的記憶體單元通過附加的引用關聯起來,形成一個可以按序號索引的線性結構,這種鏈式儲存方式與陣列的連續儲存方式相比,記憶體的利用率更高),按序號索引資料需要進行前向或後向遍歷,但是插入資料時只需要記錄本項的前後項即可,所以插入速度較快。
Vector屬於遺留容器(Java早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器),已經不推薦使用,但是由於ArrayList和LinkedListed都是非執行緒安全的,如果遇到多個執行緒操作同一個容器的場景,則可以通過工具類Collections中的synchronizedList方法將其轉換成執行緒安全的容器後再使用(這是對裝潢模式的應用,將已有物件傳入另一個類的構造器中建立新的物件來增強實現)。
52、Collection和Collections的區別?
Collection是集合的介面,而Collections是工具類
53、List、Map、Set三個介面存取元素時,各有什麼特點?
list: 可存入重複資料 add()新增, get(index)取
map: key不可重複,value可以重複 put()存 get(key)取
set: 不允許重複 add方法有一個boolean的返回值,當集合中沒有某個元素,此時add方法可成功加入該元素時,則返回true;當集合含有與某個元素equals相等的元素時,此時add方法無法加入該元素,返回結果為false。
54、TreeMap和TreeSet在排序時如何比較元素?Collections工具類中的sort()方法如何比較元素?
TreeSet要求存放的物件所屬的類必須實現Comparable介面,該介面提供了比較元素的compareTo()方法,當插入元素時會回撥該方法比較元素的大小。TreeMap要求存放的鍵值對對映的鍵必須實現Comparable介面從而根據鍵對元素進行排序。
Collections工具類的sort方法有兩種過載的形式,第一種要求傳入的待排序容器中存放的物件必須實現Comparable介面以實現元素的比較;第二種不強制性的要求容器中的元素必須可比較,但是要求傳入第二個引數,引數是Comparator介面的子型別(需要重寫compare方法實現元素的比較),相當於一個臨時定義的排序規則,其實就是通過介面注入比較元素大小的演算法,也是對回撥模式的應用(Java中對函數語言程式設計的支援)。
55、Thread類的sleep()方法和物件的wait()方法都可以讓執行緒暫停執行,它們有什麼區別?
sleep()方法(休眠)是執行緒類(Thread)的靜態方法,呼叫此方法會讓當前執行緒暫停執行指定的時間,將執行機會(CPU)讓給其他執行緒,但是物件的鎖依然保持,因此休眠時間結束後會自動恢復(執行緒回到就緒狀態,請參考第66題中的執行緒狀態轉換圖)。
wait()是Object類的方法,呼叫物件的wait()方法導致當前執行緒放棄物件的鎖(執行緒暫停執行),進入物件的等待池(wait pool),只有呼叫物件的notify()方法(或notifyAll()方法)時才能喚醒等待池中的執行緒進入等鎖池(lock pool),如果執行緒重新獲得物件的鎖就可以進入就緒狀態。
56、執行緒的sleep()方法和yield()方法有什麼區別?
sleep()方法和yield()方法都是Thread類的靜態方法,都會使當前處於執行狀態的執行緒放棄CPU,把執行機會讓給別的執行緒。兩者的區別在於:
1. sleep()方法會給其他執行緒執行的機會,不考慮其他執行緒的優先順序,因此會給較低優先順序執行緒一個執行的機會;yield()方法只會給相同優先順序或者更高優先順序的執行緒一個執行的機會。
2. 當執行緒執行了sleep(long millis)方法,將轉到阻塞狀態,引數millis指定睡眠時間;當執行緒執行了yield()方法,將轉到就緒狀態。
3. sleep()方法宣告丟擲InterruptedException異常,而yield()方法沒有宣告丟擲任何異常。
4. sleep()方法比yield()方法具有更好的可移植性。不能依靠yield()方法來提高程式的併發效能。
57、當一個執行緒進入一個物件的synchronized方法A之後,其它執行緒是否可進入此物件的synchronized方法B?
不可以訪問該物件的其他synchronized方法,
58、請說出與執行緒同步以及執行緒排程相關的方法。
- wait():使一個執行緒處於等待(阻塞)狀態,並且釋放所持有的物件的鎖;
- sleep():使一個正在執行的執行緒處於睡眠狀態,是一個靜態方法,呼叫此方法要處理InterruptedException異常;
- notify():喚醒一個處於等待狀態的執行緒,當然在呼叫此方法的時候,並不能確切的喚醒某一個等待狀態的執行緒,而是由JVM確定喚醒哪個執行緒,而且與優先順序無關;
- notityAll():喚醒所有處於等待狀態的執行緒,該方法並不是將物件的鎖給所有執行緒,而是讓它們競爭,只有獲得鎖的執行緒才能進入就緒狀態;
59、編寫多執行緒程式有幾種實現方式?
extends Thread
implements Runnable
implements Callable
Runnable和Callable的區別是,
(1)Callable規定的方法是call(),Runnable規定的方法是run()。
(2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值得
(3)call方法可以丟擲異常,run方法不可以
(4)執行Callable任務可以拿到一個Future物件,表示非同步計算的結果。
另外不推薦繼承Thread類,因為Java是單繼承的,繼承了Thread之後就不能繼承其他類了,但是可以實現多個介面
60、synchronized關鍵字的用法?
synchronized修飾方法和synchronized修飾程式碼塊
61、舉例說明同步和非同步。
同步: 傳送一個請求的時候,等待響應,不能傳送另一個請求
非同步: 傳送完一個請求,不用等待其響應,可以傳送另一請求
比如發簡訊和打電話, 發簡訊就屬於非同步方式,傳送完後不用關心對方是否收到已檢視,而打電話則不同,對方未接通,通話就不能連線
62、啟動一個執行緒是呼叫run()還是start()方法?
start方法,run方法, start方法內部實現了run方法
63、什麼是執行緒池(thread pool)?
沒有執行緒池的時候,每次需要用的時候都要建立一次, 增加了伺服器負擔, 但是執行緒池的出現,獲取物件的時候只需要從執行緒池中拿一個,用完了再放回去,不需要頻繁的建立物件
執行緒池顧名思義就是事先建立若干個可執行的執行緒放入一個池(容器)中,需要的時候從池中獲取執行緒不用自行建立,使用完畢不需要銷燬執行緒而是放回池中,從而減少建立和銷燬執行緒物件的開銷。
64、執行緒的基本狀態以及狀態之間的關係?
基本狀態有6種:
新建: new語句建立執行緒的物件處於等待狀態,和其他Java物件一樣,只分配了記憶體空間
等待: 執行緒在new之後,start之前,處於等待狀態
就緒: 當一個執行緒物件建立後,其他執行緒呼叫他的start方法, 該執行緒處於就緒狀態,處於這個狀態的執行緒存在Java的可執行池中,等待分配CPU的使用權
執行: 佔用CPU的執行權,執行程式程式碼, 如果計算機只有一個CPU,那麼任何時刻只有這一個執行緒處於執行狀態,只有就緒狀態的執行緒才有機會進入這個狀態
阻塞: 執行緒因為某些原因放棄CPU,暫時停止執行. 當執行緒處於阻塞狀態時,Java虛擬機器不會給其分配CPU,直到執行緒重新處於就緒狀態,才有可能重新獲取CPU的執行權
死亡: 當執行緒執行完run()方法中的程式碼,或者遇到了未捕獲的異常,就會退出run()方法,此時就進入死亡狀態,該執行緒結束生命週期。
處於阻塞狀態的原因:
1、等待阻塞:執行的執行緒執行wait()方法,JVM會把該執行緒放入等待池中。
2、同步阻塞:執行的執行緒在獲取物件同步鎖時,若該同步鎖被別的執行緒佔用,則JVM會把執行緒放入鎖池中。
3、其他阻塞:執行的執行緒執行Sleep()方法,或者發出I/O請求時,JVM會把執行緒設為阻塞狀態。當Sleep()狀態超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。
65、簡述synchronized 和java.util.concurrent.locks.Lock的異同?
相同之處: lock能完成synchronized所有的功能
不同之處: synchronized可以自動釋放鎖,而lock需要手動再次釋放鎖(unLock()),並且必須在finally語句中(一旦出現異常也可以及時釋放鎖), lock比synchronized有更精確的執行緒語義和更好的效能。lock還有更強大的功能,比如他的tryLock()方法可以非阻塞方式去拿鎖
tryLock()方法相比synchronized更靈活
呼叫tryLock方法時,若獲取了鎖,立即返回true,否則返回false
tryLock(Long timeout, TimeUnit timeUnit) ,若獲取鎖,立即返回true,若沒有獲取鎖,等待給定的時間timeOut,若等待給定時間後仍未獲取鎖,返回false,若獲取鎖,返回true
66、Java中如何實現序列化,有什麼意義?
實現java.io.Serializable介面
序列化就是把物件或屬性轉換成二進位制檔案, 用於socket間傳輸,而不會出現亂序的問題,保證資料傳輸準確性
67、Java中有幾種型別的流?
從輸入輸出方面講兩種: 輸入流. 輸出流
從流的編碼方式講: 位元組流, 字元流
位元組流: InputStream 和OutPutStream
字元流: InputStreamReader 和OutPutStreamReader
68、寫一個方法,輸入一個檔名和一個字串,統計這個字串在這個檔案中出現的次數。
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
String line;
StringBuilder stringBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
stringBuilder = stringBuilder.append(line); //把檔案內容讀取StringBuilder中
}
int a = 0;
while((a = stringBuilder.indexOf(name)) != -1) { //獲取name在檔案中下標值
stringBuilder = stringBuilder.delete(a, a + name.length()); //把符合下標之前的刪除
count++;
}
69、如何用Java程式碼列出一個目錄下所有的檔案?
String fileName = "D:/mybatis";
List<String> list = new ArrayList<>();
File file = new File(fileName);
for (File tmp :file.listFiles()) {
if (tmp.isDirectory()) {
for (File tmp2:tmp.listFiles()) {
list.add(tmp2.getName());
}
}else if (tmp.isFile()) {
list.add(tmp.getName());
}
}
70、用Java的套接字程式設計實現一個多執行緒的回顯(echo)伺服器。
71、XML文件定義有幾種形式?它們之間有何本質區別?解析XML文件有哪幾種方式?
dtd文件定義型別和schema模式
本質區別:schema本身是xml的,可以被XML解析器解析(這也是從DTD上發展schema的根本目的)
普通區別:
1.schema 是內容開放模型,可擴充套件,功能性強,而DTD可擴充套件性差。
2.shema 支援豐富的資料型別,而 DTD不支援元素的資料型別,對屬性的型別定義也很有限。
3.schema 支援名稱空間機制,而DTD不支援。
4.schema 可針對不同情況對整個XML 文件或文件區域性進行驗證;而 DTD缺乏這種靈活性。
5.schema 完全遵循XML規範,符合XML語法,可以和DOM結合使用,功能強大;而DTD 語法本身有自身的語法和要求,難以學習。
解析方式:
DOM解析, SAX解析, DOM4J解析,JDOM解析
72、你在專案中哪些地方用到了XML?
儲存配置資訊, 比如使用jdbc作為資料來源連線資料庫的時候,如果資料庫的地址配置修改了,只需更改xml配置檔案即可,不用去修改原始碼, 以及一系列的配置資訊,全域性引數,路徑等,還有整合spring的配置檔案, 配置資料供程式載入使用
資料儲存,相當於小型資料庫,儲存dom4j
73、闡述JDBC操作資料庫的步驟。
1. 註冊驅動
Class.forName(“com.mysql.jdbc.Driver”); Class.forName函式的作用是根據類的名字將類裝載到虛擬機器中(並未例項化);這種方式也不會對具體的驅動類產生依賴 推薦使用反射
或者直接註冊 DriverManager.registerDriver(com.mysql.jdbc.Driver);
2. 建立連線 Connection conn=DriverManager.getConnection(url,uid,pwd);
3. 建立執行sql語句的物件 PreparedStatement ps=conn.prepareStatement(strSql);(推薦PreparedStatement 防止sql注入)
4. 執行語句
查詢:st.executeQuery(strSql);或者ps. executeQuery();
非查詢(增、刪、改):st.executeUpdate(strSql);或ps.executeUpdate();
5. 處理執行結果
查詢:返回值用ResultSet接收,例:ResultSet rs=st.executeQuery(strsql)
非查詢(增、刪、改):返回值為int
6. 釋放資源
依次釋放ResultSet、Statement(或PreparedStatement)、Connection物件,釋放順序與建立順序相反(類似“棧”結構)。
注意,Connection是非常稀有的資源,用完必須馬上釋放,它的使用原則是儘量晚的建立,儘量早的釋放,以減少佔用資源的時間。
建立連線池更好的提高效率,不用頻繁的建立連線,每次需要的時候在連線池中取一個,用完之後放回去
74、Statement和PreparedStatement有什麼區別?哪個效能更好?
從安全方面考慮, PreparedStatement, 防止sql注入發生
在執行可變引數的一條sql時,PreparedStatement比Statement效率要高,因為預編譯一次sql要比多次編譯一條sql效率高
對於多次重複執行的sql,PreparedStatement效率要高很多
程式碼的可讀性和可維護性
75、使用JDBC操作資料庫時,如何提升讀取資料的效能?如何提升更新資料的效能?
提升讀資料的效能,可以使用j結果集物件ResultSet的setFetchSize()來設定每次讀取資料的大小條數
提升更新資料的效能可以通過PreparedStatement來預編譯sql語句,使用批處理
76、在進行資料庫程式設計時,連線池有什麼作用?
由於建立連線和釋放連線都有很大的開銷(尤其是資料庫伺服器不在本地時,每次建立連線都需要進行TCP的三次握手,釋放連線需要進行TCP四次握手,造成的開銷是不可忽視的)。
為了提升系統訪問資料庫的效能,可以事先建立若干連線置於連線池中,需要時直接從連線池獲取,使用結束時歸還連線池而不必關閉連線,從而避免頻繁建立和釋放連線所造成的開銷,這是典型的用空間換取時間的策略(浪費了空間儲存連線,但節省了建立和釋放連線的時間)。
77、什麼是DAO模式?
DataSource即和資料庫打交道的, 資料連線,
通常的模式MVC模式, 表現層(controller), 業務邏輯層(service), 資料結構層(dao)
78、事務的ACID是指什麼?
原子性(atomicity)、一致性(consistency)、隔離性 (isolation)和永續性(durability)的縮寫。
原子性表示事務執行過程中的任何失敗都將導致事務所做的任何修改失效。
一致性表示當事務執行失敗時,所有被該事務影響的資料都應該恢復到事務執行前的狀態。
隔離性表示在事務執行過程中對資料的修改,在事務提交之前對其他事務不可見。
永續性表示已提交的資料在事務執行失敗時,資料的狀態都應該正確
通俗的講就是事務操作就是要麼全部成功, 要麼全部不執行(銀行扣轉賬務)
79、JDBC中如何進行事務處理?
JDBC的資料庫操作中,事務相關操作就是不可分割的原子性操作, 操作成功後預設使用commit()提交, 否則使用rollback()回滾事務,也可以設定手動提交setAutoCommit(false)禁止自動提交
80、JDBC能否處理Blob和Clob?
可以, Blob是指大二進位制物件(Binary Large Object),而Clob是指大字元物件(Character Large Objec),Blob是為儲存大的二進位制資料而設計的,而Clob是為儲存大的文字資料而設計的。JDBC的PreparedStatement和ResultSet都提供了相應的方法來支援Blob和Clob操作。
81、簡述正則表示式及其用途。
在編寫處理字串的程式時,經常會有查詢符合某些複雜規則的字串的需要。正則表示式就是用於描述這些規則的工具。換句話說,正則表示式就是記錄文字規則的程式碼。
82、Java中是如何支援正則表示式操作的?
Java中的String類提供了支援正則表示式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。
此外,Java中可以用Pattern類表示正則表示式物件,它提供了豐富的API進行各種正則表示式操作
83、獲得一個類的類物件有哪些方式?
型別.class String.class;
Class.forName(java.lang.String);
物件.getClass() String a = "a" ; a.getClass(); A a = new A(); a.getClass();
84、如何通過反射建立物件?
Class<?> clazz = Class.forName(String className);
Object obj = clazz.newInstance();
85、如何通過反射獲取和設定物件私有欄位的值?
Class<?> clazz = Class.forName(String className);
Object obj = clazz.newInstance();
獲取私有變數的值
Field field = obj.getDeclaredField(fieldName);
field.setAccessible(true); // 引數值為true,禁止訪問控制檢查
設定私有變數的值
Field field = obj.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, value);
訪問私有方法
Method method = obj.getDeclaredMethod(methodName,Class[] classes);
method.setAccessible(true);
method.invoke(Object,args);
Class<?> clazz = Class.forName("com.test.testdemo.User");
//建立物件的例項
User user = (User) clazz.newInstance();
//直接呼叫物件的方法
user.say("hahaha");
Method[] methods = clazz.getMethods(); //獲取所有方法
Method method1 = clazz.getMethod("say", String.class); //獲取指定方法
method.setAccessible(true);
method1.invoke(user, "1"); //執行方法 或者是clazz.newInstance()
//獲取私有屬性
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields) {
field.setAccessible(true);
System.out.println(field.getName());
}
//獲取指定私有屬性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
86、如何通過反射呼叫物件的方法?
2種方式
1. Class<?> clazz = Class.forName("com.test.testdemo.User");
//建立物件的例項
User user = (User) clazz.newInstance();
//直接呼叫物件的方法
user.say("hahaha");
2. Method[] methods = clazz.getMethods(); //獲取所有方法
Method method1 = clazz.getMethod("say", String.class); //獲取指定方法
method.setAccessible(true);
method1.invoke(user, "1"); //執行方法 或者是clazz.newInstance()
87、簡述一下面向物件的"六原則一法則"。
單一職責原則 : 高內聚思想, 即一個類只專注一件事, 或者專注於某個功能, 可以達到軟體複用的目的
開閉原則 : 軟體實體應當對擴充套件開放,對修改關閉。在理想的狀態下,當我們需要為一個軟體系統增加新功能時,只需要從原來的系統派生出一些新類就可以,不需要修改原來的任何一行程式碼。需要有抽象和封裝特性, 只需改超類就行
依賴倒轉原則 :面向介面程式設計。該原則說得直白和具體一些就是宣告方法的引數型別、方法的返回型別、變數的引用型別時,儘可能使用抽象型別而不用具體型別,因為抽象型別可以被它的任何一個子型別所替代
里氏替換原則 :任何時候都可以用子型別替換掉父型別。
介面隔離原則 :介面要小而專,絕不能大而全, 臃腫的介面是對介面的汙染, 介面定義應遵循高內聚,高可用
合成聚合複用原則: 優先使用聚合或合成關係複用程式碼。
迪米特法則: 迪米特法則又叫最少知識原則,一個物件應當對其他物件有儘可能少的瞭解。迪米特法則簡單的說就是如何做到"低耦合",門面模式和調停者模式就是對迪米特法則的踐行。
88、簡述一下你瞭解的設計模式。
23種設計模式: Abstract Factory(抽象工廠模式),Builder(建造者模式),Factory Method(工廠方法模式),Prototype(原始模型模式),Singleton(單例模式);Facade(門面模式),Adapter(介面卡模式),Bridge(橋樑模式),Composite(合成模式),Decorator(裝飾模式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(直譯器模式),Visitor(訪問者模式),Iterator(迭代子模式),Mediator(調停者模式),Memento(備忘錄模式),Observer(觀察者模式),State(狀態模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(責任鏈模式)。
- -工廠模式:工廠類可以根據條件生成不同的子類例項,這些子類有一個公共的抽象父類並且實現了相同的方法,但是這些方法針對不同的資料進行了不同的操作(多型方法)。當得到子類的例項後,開發人員可以呼叫基類中的方法而不必考慮到底返回的是哪一個子類的例項。
- -代理模式:給一個物件提供一個代理物件,並由代理物件控制原物件的引用。實際開發中,按照使用目的的不同,代理可以分為:遠端代理、虛擬代理、保護代理、Cache代理、防火牆代理、同步化代理、智慧引用代理。
- -介面卡模式:把一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起使用的類能夠一起工作。
- 模板方法模式:提供一個抽象類,將部分邏輯以具體方法或構造器的形式實現,然後宣告一些抽象方法來迫使子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法(多型實現),從而實現不同的業務邏輯。
89、用Java寫一個單例類。
public class Singleton {
//用Java寫一個單例類
//餓漢式
private Singleton(){} //私有構造方法
private static Singleton instance = new Singleton(); //不管怎麼樣,上來就先建立一個物件
public static Singleton getInstance(){
return instance;
}
}
//懶漢式
class Singleton2 {
private static Singleton2 instance = null;
private Singleton2() {} //私有構造方法
public static synchronized Singleton2 getInstance(){
if (instance == null) instance = new Singleton2(); //如果沒有就建立一個物件,以備後用
return instance;
}
}
90、什麼是UML?
統一建模語言(UML是 Unified Modeling Language的縮寫)是用來對軟體密集系統進行視覺化建模的一種語言。UML為面向物件開發系統的產品進行說明、視覺化、和編制文件的一種標準語言。
統一建模語言 (UML)是非專利的第三代建模和規約語言。 UML是在開發階段,說明,視覺化,構建和書寫一個面向物件軟體密集系統的製品的開放方法。UML展現了一系列最佳工程實踐,這些最佳實踐在對大規模,複雜系統進行建模方面,特別是在軟體架構層次已經被驗證有效。
91、UML中有哪些常用的圖?
活動圖,狀態圖,用例圖,類圖,時序圖,序列圖,物件圖,包圖等等
92、用Java寫一個氣泡排序。
int[] arr = { 9, 3, 7, 10, 2 };
// 定義外層迴圈
for (int i = 0; i < arr.length - 1; i++) {
// 定義內層迴圈
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] < arr[j + 1]) { // 比較相鄰元素
// 下面的三行程式碼用於交換兩個元素
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
System.out.print("第" + (i + 1) + "輪排序後:");
// 每輪比較結束列印陣列元素
for (int i2 = 0; i2 < arr.length; i2++) {
System.out.print(arr[i2] + " "); // 列印元素和空格
}
}
93、用Java寫一個折半查詢。
public static int Max = 20;
// 資料陣列源
public static int data[] = { 12, 16, 19, 22, 25, 32, 39, 39, 48, 55, 57,58,63, 68, 69, 70, 78, 84, 88, 90, 97 };
// 計數器
public static int count = 1;
Scanner sc = new Scanner(System.in);
int KeyValue = sc.nextInt();
int left = 0;// 左邊界變數
int right = Max - 1;// 右邊界變數
int middle;// 中位數變數
while (left <= right) {
middle = (left + right) / 2;
if (k < data[middle]) {
right = middle - 1;// 查詢前半段
} else if (k > data[middle]) {
left = middle + 1;// 查詢後半段
} else if (k == data[middle]) {
System.out.println("Data[" + middle + "] = " + data[middle]);
return true;
}
count++;
}
94、闡述Servlet和CGI的區別?
Servlet處於伺服器程序中,它通過多執行緒方式執行其service方法,一個例項可以服務於多個請求,並且其例項一般不會銷燬,而CGI對每一個請求都產生新的程序,服務完成後就銷燬,所以效率上低與Servlet。
servlet的生命週期: Servlet從被Web伺服器載入到它被銷燬的整個生命過程, 分為3個階段
初始化: 呼叫init()方法,
響應客戶端請求階段: 呼叫service()方法,
銷燬階段: 呼叫destory() 方法
95、Servlet介面中有哪些方法?
生命週期的三個方法:
init() : servlet例項化後,servlet容器會呼叫init()方法初始化物件, 在響應客戶端請求之前做一些準備,資料庫的連線,獲取配置資訊等. 每一個servlet例項只能呼叫一次init()方法
service() : 用來處理客戶端的請求, service()方法執行前,須確保init()方法正確完成,. 容器會構造一個使用者獲取客戶端請求引數的ServletRequest物件引數和一個用來響應客戶端請求的ServletResponse物件引數,把這兩個引數傳給service()方法, service方法中.servlet物件通過ServletRequest物件來獲取客戶端的相關資訊和請求資訊, 執行完請求後,通過ServletResponse物件設定響應資訊
destory(): 當容器檢測到一個Servlet物件應該從服務中被移除的時候,容器會呼叫該物件的destroy()方法,以便讓Servlet物件可以釋放它所使用的資源,儲存資料到持久儲存裝置中,例如將記憶體中的資料儲存到資料庫中,關閉資料庫的連線等. 當需要釋放記憶體或者容器關閉時,容器就會呼叫Servlet物件的destroy()方法,在Servlet容器呼叫destroy()方法前,如果還有其他的執行緒正在service()方法中執行容器會等待這些執行緒執行完畢或者等待伺服器設定的超時值到達。一旦Servlet物件的destroy()方法被呼叫,容器不回再把請求傳送給該物件。如果需要改Servlet再次為客戶端服務,容器將會重新產生一個Servlet物件來處理客戶端的請求。在destroy()方法呼叫之後,容器會釋放這個Servlet物件,在隨後的時間內,該物件會被java的垃圾收集器所回收
getServletConfig(): 該方法返回容器呼叫init()方法時傳遞給Servlet物件的ServletConfig物件,ServletConfig物件包含了Servlet的初始化引數。
getServletInfo(): 返回一個String型別的字串,其中包括了關於Servlet的資訊,例如,作者、版本和版權。該方法返回的應該是純文字字串,而不是任何型別的標記。
96、轉發(forward)和重定向(redirect)的區別?
請求轉發:
1. 是伺服器內部的重定向,伺服器直接訪問目標地址的 url網址,把裡面的東西讀取出來,但是客戶端並不知道,因此用forward的話,客戶端瀏覽器的網址是不會發生變化的。
2.關於request: 由於在整個定向的過程中用的是同一個request,因此forward會將request的資訊帶到被重定向的jsp或者servlet中使用。
重定向:
1. 是客戶端的重定向,是完全的跳轉。即伺服器返回的一個url給客戶端瀏覽器,然後客戶端瀏覽器會重新發送一次請求,到新的url裡面,因此瀏覽器中顯示的url網址會發生變化。
2.因為這種方式比forward多了一次網路請求,因此效率會低於forward。
97、JSP有哪些內建物件?作用分別是什麼?
Page,pageContext,request,response,session,application,out,config,exception
Page指的是JSP被翻譯成Servlet的物件的引用.
pageContext物件可以用來獲得其他8個內建物件,還可以作為JSP的域範圍物件使用.pageContext中存的值是當前的頁面的作用範圍
request代表的是請求物件,可以用於獲得客戶機的資訊,也可以作為域物件來使用,使用request儲存的資料在一次請求範圍內有效。
Session代表的是一次會話,可以用於儲存使用者的私有的資訊,也可以作為域物件使用,使用session儲存的資料在一次會話範圍有效
Application:代表整個應用範圍,使用這個物件儲存的資料在整個web應用中都有效。
Response是響應物件,代表的是從伺服器向瀏覽器響應資料.
Out:JSPWriter是用於向頁面輸出內容的物件
Config:指的是ServletConfig用於JSP翻譯成Servlet後 獲得Servlet的配置的物件.
Exception:在頁面中設定isErrorPage=”true”,即可使用,是Throwable的引用.用來獲得頁面的錯誤資訊。
-
GET在瀏覽器回退時是無害的,而POST會再次提交請求。
-
GET產生的URL地址可以被Bookmark,而POST不可以。
-
GET請求會被瀏覽器主動cache,而POST不會,除非手動設定。
-
GET請求只能進行url編碼,而POST支援多種編碼方式。
-
GET請求引數會被完整保留在瀏覽器歷史記錄裡,而P