Java常问面试题整理
java基礎面試題
1. 請你談談java語言的特點
簡單性
Java語言是一種相對簡單的編程語言,Java丟棄了C++中很難理解的運算符重載、多重繼承等模糊概念。特別是Java語言不使用指針,而是使用引用,并提供了自動的垃圾回收機制,使程序員不必為內存管理而擔憂。
面向對象性
Java語言提供了類、接口和繼承等原語,為了簡單起見,只支持類之間的單繼承,但支持接口之間的多繼承,并支持類與接口之間的實現機制。Java語言全面支持動態綁定,而C++語言只對虛函數使用動態綁定。總之,Java語言是一個純粹的面向對象程序設計的語言。
跨平臺性
Java語言編寫的程序可以運行在各種平臺之上。
安全性
Java語言不支持指針,一切對內存的訪問都必須通過對象的實例變量來實現,從而使應用更安全。
2. 面向對象的特征有哪些方面?
抽象:抽象是將一類對象的共同特征總結出來構造類的過程,包括數據抽象和行為抽象兩方面。抽象只關注對象有哪些屬性和行為,并不關注這些行為的細節是什么.
封裝:將對象的屬性和行為封裝起來,不需要讓外界知道具體實現細節。
繼承:繼承主要描述的是類與類之間的關系,通過繼承,可以在無需重新編寫原有類的情況下對原有類的功能進行擴展。
多態:指在一個類中定義的屬性和方法被其它類繼承后,它們可以具有不同的數據類型或表現出不同的行為,這使得同一個屬性和方法在不同的類中具有不同的語義。
3. 訪問修飾符 public,private,protected,以及不寫(默認)時的區別?
| 修飾符 | 當前類 | 同包 | 子類 | 其他包 |
|---|---|---|---|---|
| public | √ | √ | √ | √ |
| protected | √ | √ | √ | × |
| default | √ | √ | × | × |
| private | √ | × | × | × |
類的成員不寫訪問修飾時默認為 default。默認對于同一個包中的其他類相當于公開(public),對于不是同一個包中的其他類相當于私有(private)。受保護(protected)對子類相當于公開,對不是同一包中的沒有父子關系的類相當于私有。Java 中,外部類的修飾符只能是 public 或默認,類的成員(包括內部類)的修飾符可以是以上四種。
4. String 是最基本的數據類型嗎?
不是。Java 中的基本數據類型只有 8 個:byte、short、int、long、float、double、char、boolean;除了基本類型(primitive type),剩下的都是引用類型(referencetype),Java 5 以后引入的枚舉類型也算是一種比較特殊的引用類型。
5. float f=3.4;是否正確?
不正確。3.4 是雙精度數,將雙精度型(double)賦值給浮點型(float)屬于下轉型(down-casting,也稱為窄化)會造成精度損失,因此需要強制類型轉換float f =(float)3.4; 或者寫成 float f =3.4F;。
6. 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);復合運算符有隱含的強制類型轉換。
7. Java 有沒有 goto?
goto 是 Java 中的保留字,在目前版本的 Java 中沒有使用。
8. int 和 Integer 有什么區別?
int是基本數據類型,Integer是包裝類型。Java 是一個近乎純潔的面向對象編程語言,但是為了編程的方便還是引入了基本數據類型,但是為了能夠將這些基本數據類型當成對象操作,Java 為每一個基本數據類型都引入了對應的包裝類型(wrapper class),int 的包裝類就是 Integer, 從 Java 5 開始引入了自動裝箱/拆箱機制,使得二者可以相互轉換。
Java 為每個原始類型提供了包裝類型:
原始類型: boolean,char,byte,short,int,long,float,double
包裝類型:Boolean,Character,Byte,Short,Integer,Long,Float,Double
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比較
}
}
9. &和&&的區別?
&運算符有兩種用法:(1)按位與;(2)邏輯與。&&運算符是短路與運算。邏輯與跟短路與的差別是非常巨大的,雖然二者都要求運算符左右兩端的布爾值都是true 整個表達式的值才是 true。&&之所以稱為短路運算是因為,如果&&左邊的表達式的值是 false,右邊的表達式會被直接短路掉,不會進行運算。很多時候我們可能都需要用&&而不是&,例如在驗證用戶登錄時判定用戶名不是 null 而且不是空字符串,應當寫為:username != null &&!username.equals(“”),二者的順序不能交換,更不能用&運算符,因為第一個條件如果不成立,根本不能進行字符串的 equals 比較,否則會產NullPointerException 異常。注意:邏輯或運算符(|)和短路或運算符(||)的差別也是如此。
10. 解釋內存中的棧(stack)、堆(heap)和方法區(method area)的用法。
通常我們定義一個基本數據類型的變量,一個對象的引用,還有就是函數調用的現場保存都使用 JVM 中的棧空間;而通過 new 關鍵字和構造器創建的對象則放在堆空間,堆是垃圾收集器管理的主要區域,由于現在的垃圾收集器都采用分代收集算法,所以堆空間還可以細分為新生代和老生代,再具體一點可以分為 Eden、Survivor(又可分為 From Survivor 和 To Survivor)、Tenured;方法區和堆都是各個線程共享的內存區域,用于存儲已經被 JVM 加載的類信息、常量、靜態變量、JIT 編譯器編譯后的代碼等數據;程序中的字面量(literal)如直接書寫的 100、”hello”和常量都是放在常量池中,常量池是方法區的一部分,。棧空間操作起來最快但是棧很小,通常大量的對象都是放在堆空間,棧和堆的大小都可以通過 JVM的啟動參數來進行調整,棧空間用光了會引發 StackOverflowError,而堆和常量池空間不足則會引發 OutOfMemoryError。
String str = new String("hello");
上面的語句中變量 str 放在棧上,用 new 創建出來的字符串對象放在堆上,而”hello”這個字面量是放在方法區的。
11. Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在參數上加 0.5 然后進行下取整。
12. switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。從 Java5 開始,Java 中引入了枚舉類型,expr 也可以是 enum 類型,從 Java 7 開始,expr 還可以是字符串(String),但是長整型(long)在目前所有的版本中都是不可以的。
13. 用最有效率的方法計算 2 乘以 8?
2 << 3(左移 3 位相當于乘以 2 的 3 次方,右移 3 位相當于除以 2 的 3 次方)。
14. 數組有沒有 length()方法?String 有沒有 length()方法?
數組沒有 length()方法,有 length 的屬性。String 有 length()方法。JavaScript中,獲得字符串的長度是通過 length 屬性得到的,這一點容易和 Java 混淆。
15. 在 Java 中,如何跳出當前的多重嵌套循環?
在最外層循環前加一個標記如 A,然后用 break A;可以跳出多重循環。(Java 中支持帶標簽的 break 和 continue 語句,作用有點類似于 C 和 C++中的 goto 語 句,但是就像要避免使用 goto 一樣,應該避免使用帶標簽的 break 和 continue,因為它不會讓你的程序變得更優雅,很多時候甚至有相反的作用,所以這種語法其實不知道更好)
16. 構造器(constructor)是否可被重寫(override)?
構造器不能被繼承,因此不能被重寫,但可以被重載。
17. 兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?
不對,如果兩個對象 x 和 y 滿足 x.equals(y) == true,它們的哈希碼(hash code)應當相同。Java 對于 eqauls 方法和 hashCode 方法是這樣規定的:
(1)如果兩個對象相同(equals 方法返回 true),那么它們的 hashCode 值一定要相同;
(2)如果兩個對象的 hashCode 相同,它們并不一定相同。當然,你未必要按照要求去做,但是如果你違背了上述原則就會發現在使用容器時,相同的對象可以出現在 Set 集合中,同時增加新元素的效率會大大下降(對于使用哈希存儲的系統,如果哈希碼頻繁的沖突將會造成存取性能急劇下降)。
18. 是否可以繼承 String 類?
String 類是 final 類,不可以被繼承。
19. 當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里到底是值傳遞還是引用傳遞?
是值傳遞。Java 語言的方法調用只支持參數的值傳遞。當一個對象實例作為一個參數被傳遞到方法中時,參數的值就是對該對象的引用。對象的屬性可以在被調用過程中被改變,但對對象引用的改變是不會影響到調用者的。
20. String 和 StringBuilder、StringBuffer 的區別?
Java 平臺提供了兩種類型的字符串:String 和 StringBuffer/StringBuilder,它們可以儲存和操作字符串。其中 String 是只讀字符串,也就意味著 String 引用的字符串內容是不能被改變的。而StringBuffer/StringBuilder 類表示的字符串對象可以直接進行修改。StringBuilder 是 Java 5 中引入的,它和 StringBuffer 的方法完全相同,區別在于它是在單線程環境下使用的,因為它的所有方面都沒有被synchronized 修飾,因此它的效率也比 StringBuffer 要高。StringBuilder 線程不安全,StringBuffer線程安全。
面試題 1 - 什么情況下用+運算符進行字符串連接比調用StringBuffer/StringBuilder 對象的 append 方法連接字符串性能更好?
面試題 2 - 請說出下面程序的輸出。
class StringEqualTest {
public static void main(String[] args) {
String s1 = "Programming";
String s2 = new String("Programming");
String s3 = "Program";
String s4 = "ming";
String s5 = "Program" + "ming";
String s6 = s3 + s4;
System.out.println(s1 == s2);
System.out.println(s1 == s5);
System.out.println(s1 == s6);
System.out.println(s1 == s6.intern());
System.out.println(s2 == s2.intern());
}
}
補充:解答上面的面試題需要清除兩點:1. String 對象的 intern 方法會得到字符串對象在常量池中對應的版本的引用(如果常量池中有一個字符串與 String 對象的 equals 結果是 true),如果常量池中沒有對應的字符串,則該字符串將被添加到常量池中,然后返回常量池中字符串的引用;2. 字符串的+操作其本質是創建了 StringBuilder 對象進行 append 操作,然后將拼接后的 StringBuilder 對象用toString 方法處理成 String 對象,這一點可以用 javap -c StringEqualTest.class命令獲得 class 文件對應的 JVM 字節碼指令就可以看出來。
21. 重載(Overload)和重寫(Override)的區別。重載的方法能否根據返回類型進行區分?
* 方法重載的規則:
* 方法名稱必須相同。
* 參數列表必須不同(個數不同、或類型不同、參數排列順序不同等)。
* 方法的返回類型可以相同也可以不相同。
* 僅僅返回類型不同不足以成為方法的重載。
* 方法重寫的規則:重寫的前提是存在繼承關系。
1.子類方法的參數列表必須和父類中被重寫的方法的參數列表相同(參數個數和參數類型),否則只能實現方法的重載。
2.子類方法的返回值類型必須和父類中被重寫的方法返回值類型相同,否則只能實現方法重載。
3.在Java規定,子類方法的訪問權限不能比父類中被重寫的方法的訪問權限更小,必須大于或等于父類的訪問權限。
4.在重寫的過程中,如果父類中被重寫的方法拋出異常,則子類中的方法也要拋出異常。但是拋出的異常也有一定的約束--->子類不能拋出比父類更多
的異常,只能拋出比父類更小的異常,或者不拋出異常。例如:父類方法拋出Exception,那么子類就只能拋出IOException或者拋出比Exception小
的異常或者不拋出異常。
22. 描述一下 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 所指定的目錄中記載類,是用戶自定義加載器的默認父加載器。
23. char 型變量中能不能存貯一個中文漢字,為什么?
char 類型可以存儲一個中文漢字,因為 Java 中使用的編碼是 Unicode(不選擇任何特定的編碼,直接使用字符在字符集中的編號,這是統一的唯一方法),一個 char 類型占 2 個字節(16 比特),char型變量是用來存儲Unicode編碼的字符的,unicode編碼字符集中包含了漢字,不過,如果某個特殊的漢字沒有被包含在unicode編碼字符集中,那么,這個char型變量中就不能存儲這個特殊漢字。
24. 抽象類(abstract class)和接口(interface)有什么異同?
抽象類可以有構造方法,接口中不能有構造方法。
抽象類中可以有普通成員變量,接口中沒有普通成員變量
抽象類中可以包含非抽象的普通方法,接口中的所有方法必須都是抽象的,不能有非抽象的普通方法。
抽象類中的抽象方法的訪問類型可以是public,protected,但接口中的抽象方法只能是public類型的,并且默認即為public abstract類型。
抽象類中可以包含靜態方法,接口中不能包含靜態方法
抽象類和接口中都可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型可以任意,但接口中定義的變量只能是public static final類型,并且默認即為public static final類型。
一個類可以實現多個接口,但只能繼承一個抽象類。
25. 抽象的(abstract)方法是否可同時是靜態的(static),是否可同時是本地方法(native),是否可同時被 synchronized修飾?
都不能。抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。本地方法是由本地代碼(如 C 代碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。synchronized 和方法的實現細節有關,抽象方法不涉及實現細節,因此也是相互矛盾的。
26. 闡述靜態變量和實例變量的區別。
靜態變量是被 static 修飾符修飾的變量,也稱為類變量,它屬于類,不屬于類的任何一個對象,一個類不管創建多少個對象,靜態變量在內存中有且僅有一個拷貝;實例變量必須依存于某一實例,需要先創建對象然后通過對象才能訪問到它。靜態變量可以實現讓多個對象共享內存。
補充:在 Java 開發中,上下文類和工具類中通常會有大量的靜態成員。
27. 是否可以從一個靜態(static)方法內部發出對非靜態(non-static)方法的調用?
不可以,靜態方法只能訪問靜態成員,因為非靜態方法的調用要先創建對象,在調用靜態方法時可能對象并沒有被初始化。
28. 如何實現對象克隆?
有兩種方式:
1). 實現 Cloneable 接口并重寫 Object 類中的 clone()方法;
2). 實現 Serializable 接口,通過對象的序列化和反序列化實現克隆,可以實現真正的深度克隆。
29. GC 是什么?為什么要有 GC?
GC 是垃圾收集的意思,內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會導致程序或系統的不穩定甚至崩潰,Java 提供的 GC 功能可以自動監測對象是否超過作用域從而達到自動回收內存的目的,Java 語言沒有提供釋放已分配內存的顯示操作方法。Java 程序員不用擔心內存管理,因為垃圾收集器會自動進行管理。要請求垃圾收集,可以調用下面的方法之一:
System.gc() 或Runtime.getRuntime().gc() ,但 JVM 可以屏蔽掉顯示的垃圾回收調用。垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作為一個單獨的低優先級的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。在 Java 誕生初期,垃圾回收是 Java最大的亮點之一,因為服務器端的編程需要有效的防止內存泄露問題,然而時過境遷,如今 Java 的垃圾回收機制已經成為被詬病的東西。移動智能終端用戶通常覺得 iOS 的系統比 Android 系統有更好的用戶體驗,其中一個深層次的原因就在于 Android 系統中垃圾回收的不可預知性。
30. String s = new String(“xyz”);創建了幾個字符串對象?
兩個對象,一個是靜態區的”xyz”,一個是用 new 創建在堆上的對象。
31. 接口是否可繼承(extends)接口?抽象類是否可實現(implements)接口?抽象類是否可繼承具體類(concreteclass)?
接口可以繼承接口,而且支持多重繼承。抽象類可以實現(implements)接口,抽象類可以繼承具體類。抽象類中可以有靜態的main方法。只要記住抽象類與普通類的唯一區別就是不能創建實例對象和允許有abstract方法。
32. 一個”.java”源文件中是否可以包含多個類(不是內部類)?有什么限制?
可以,但一個源文件中最多只能有一個公開類(public class)而且文件名必須和公開類的類名完全保持一致。
33. Anonymous Inner Class(匿名內部類)是否可以繼承其它類?是否可以實現接口?
可以繼承其他類或實現其他接口,在 Swing 編程和 Android 開發中常用此方式來實現事件監聽和回調。
34. 內部類可以引用它的包含類(外部類)的成員嗎?有沒有什么限制?
一個內部類對象可以訪問創建它的外部類對象的成員,包括私有成員。
35. Java 中的 final 關鍵字有哪些用法?
(1) 修飾類:表示該類不能被繼承;
(2) 修飾方法:表示方法不能被重寫;
(3) 修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。
36. 指出下面程序的運行結果
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。創建對象時構造器的調用順序是:先初始化靜態成員,然后調用父類構造器,再初始化非靜態成員,最后調用自身構造器。
37. 如何將字符串轉換為基本數據類型?如何將基本數據類型轉換為字符串?
調用基本數據類型對應的包裝類中的方法 parseXXX(String)或valueOf(String)即可返回相應基本類型;
一種方法是將基本數據類型與空字符串("")連接(+)即可獲得其所對應的字符串;另一種方法是調用 String 類中的 valueOf()方法返回相應字符串
38. 如何實現字符串的反轉及替換?
使用StringBuffer或StringBuilder 中的 reverse方法即可實現字符串的反轉,調用 replace 方法即可實現字符串的替換。
39. 怎樣將 GB2312 編碼的字符串轉換為 ISO-8859-1 編碼的字符串?
String s1 = "你好";
String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");
40. 比較一下 Java 和 JavaSciprt。
基于對象和面向對象:Java 是一種真正的面向對象的語言,即使是開發簡單的程序,必須設計對象;JavaScript 是種腳本語言,它可以用來制作與網絡無關的,與用戶交互作用的復雜軟件。它是一種基于對象(Object-Based)和事件驅動(Event-Driven)的編程語言,因而它本身提供了非常豐富的內部對象供設計人員使用。
解釋和編譯:Java 的源代碼在執行之前,必須經過編譯。JavaScript 是一種解釋性編程語言,其源代碼不需經過編譯,由瀏覽器解釋執行。(目前的瀏覽器幾乎都使用了 JIT(即時編譯)技術來提升 JavaScript 的運行效率)
強類型變量和類型弱變量:Java 采用強類型變量檢查,即所有變量在編譯之前必須作聲明;JavaScript 中變量是弱類型的,甚至在使用變量前可以不作聲明,JavaScript 的解釋器在運行時檢查推斷其數據類型。
Java 和 JavaScript最重要的區別是一個是靜態語言,一個是動態語言。目前的編程語言的發展趨勢是函數式語言和動態語言。在 Java 中類(class)是一等公民,而 JavaScript 中函數(function)是一等公民,因此 JavaScript 支持函數式編程,可以使用 Lambda函數和閉包(closure),當然 Java 8 也開始支持函數式編程,提供了對 Lambda表達式以及函數式接口的支持。
41. Error 和 Exception 有什么區別?
Error 表示Java運行時產生的系統內部錯誤或資源耗盡的錯誤,是比較嚴重的,僅靠修改程序本身是不能恢復執行的。
Exception 表示需要捕捉或者需要程序進行處理的異常,是一種設計或實現問題;也就是說,它表示如果程序運行正常,從不會發生的情況。
42. 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。
43. 列出一些你常見的運行時異常?
ArithmeticException(算術異常)
ClassCastException (類轉換異常)
IllegalArgumentException (非法參數異常)
IndexOutOfBoundsException (下標越界異常)
NullPointerException (空指針異常)
SecurityException (安全異常)
44. 闡述 final、finally、finalize 的區別。
final:修飾符(關鍵字)有三種用法:如果一個類被聲明為 final,意味著它不能再派生出新的子類,即不能被繼承,因此它和 abstract 是反義詞。將變量聲明為 final,可以保證它們在使用中不被改變,被聲明為 final 的變量必須在聲明時給定初值,而在以后的引用中只能讀取不可修改。被聲明為 final 的方法也同樣只能使用,不能在子類中被重寫。
finally:通常放在 try…catch…的后面構造總是執行代碼塊,這就意味著程序無論正常執行還是發生異常,這里的代碼只要 JVM 不關閉都能執行,可以將釋放外部資源的代碼寫在 finally 塊中。
finalize:Object 類中定義的方法,Java 中允許使用 finalize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在銷毀對象時調用的,通過重寫 finalize()方法可以整理系統資源或者執行其他清理工作。
45. Collection 和 Collections 的區別?
Collection 是一個接口,它是 Set、List 等容器的父接口;Collections 是個一個工具類,提供了一系列的靜態方法來輔助容器操作,這些方法包括對容器的搜索、排序、線程安全化等等
46. List、Map、Set 三個接口存取元素時,各有什么特點?
List 以特定索引來存取元素,存取有序,可以有重復元素。
Set 元素無序,不能存放重復元素(用對象的equals()方法來區分元素是否重復)。
Map Map集合是一個雙列集合, 一個元素包含兩個值(一個key, 一個value)Map集合中的元素, key和value的數據類型可以相同,也可以不同。Map集合中的元素, key是不允許重復的,value是可以重復的。Map集合中的元素, key和value是一一對應
47. "=="和equals()的區別
"=="是一個比較運算符,基本數據類型比較的是值,引用數據類型比較的是地址值。(比較地址值即是指是否為同一個對象的引用)
equals()是一個方法,只能比較引用數據類型。重寫前比較的是地址值,重寫后比一般是比較對象的屬性。
48. 闡述 ArrayList、Vector、LinkedList 的存儲性能和特性。
ArrayList 和 Vector 都是使用數組方式存儲數據,因為是數組實現,所以具有查找快(因為數組的每個元素的首地址是可以得到的,數組是0序的,所以: 被訪問元素的首地址=首地址+元素類型字節數*下標),增刪慢(因為往數組中間增刪元素時,會導致后面所有元素地址的改變)的特點。Vector 中的方法由于添加了 synchronized 修飾,因此 Vector 是線程安全的容器,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。因此已經是 Java 中的遺留容器。LinkedList 使用雙向鏈表實現存儲(將內存中零散的內存單元通過附加的引用關聯起來,形成一個可以按序號索引的線性結構,這種鏈式存儲方式與數組的連續存儲方式相比,內存的利用率更高),按序號索引數據需要進行前向或后向遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入速度較快。Vector 屬于遺留容器(Java 早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遺留容器),已經不推薦使用,但是由于 ArrayList 和 LinkedListed 都是非線程安全的,如果遇到多個線程操作同一個容器的場景,則可以通過工具類Collections 中的 synchronizedList 方法將其轉換成線程安全的容器后再使用(這是對裝潢模式的應用,將已有對象傳入另一個類的構造器中創建新的對象來增強實現)
補充:LinkedList 查詢速度慢,增刪快 特點分析:
向鏈表數據結構中添加元素的時候,一個元素會被分成兩部分;一部分存儲的是當前元素,另一部分存儲的是下一個元素的內存地址;如上圖所示:第一個元素被分成兩部分,一部分存儲的就是當前元素"張三",另一部分存儲的是下一個元素"李四"的內存地址;而"李四"元素的第二部分存儲的是"王五"元素的內存地址;這樣一環扣一環,就形成了鏈表結構;
查詢速度慢:是因為每個元素的內存地址都是不連續的,所以查詢的時候需要遍歷所有的元素;如果元素比較多,就會很慢;
增加元素快:假如在"張三"元素和"李四"元素之間添加一個元素"狗娃",因為每一個元素對象在內存中都有自己的地址,
所以只需要在"張三"元素的第二部分存儲"狗娃"元素的內存地址,然后再將"狗娃"元素第二部分
存儲"李四"元素的內存地址,這樣就添加成功了;對別的元素不需要任何操作,所以說增加元素快;
刪除元素快:假如要刪除元素"王五",那么只需要將"李四"元素的第二部分存儲"王五"下一個元素的內存地址就可以了;
"王五"元素的內存地址沒有被任何元素存儲的時候,會自動被當做垃圾回收;所以刪除元素快;
49. TreeMap 和 TreeSet 在排序時如何比較元素?Collections 工具類中的 sort()方法如何比較元素?
TreeSet 要求存放的對象所屬的類必須實現 Comparable 接口,該接口提供了比較元素的 compareTo()方法,當插入元素時會回調該方法比較元素的大小。TreeMap 要求存放的鍵值對映射的鍵必須實現 Comparable 接口從而根據鍵對元素進行排序。Collections 工具類的 sort 方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對象比較實現 Comparable 接口以實現元素的比較;第二種不強制性的要求容器中的元素必須可比較,但是要求傳入第二個參數,參數是Comparator 接口的子類型(需要重寫 compare 方法實現元素的比較),相當于一個臨時定義的排序規則,其實就是通過接口注入比較元素大小的算法,也是對回調模式的應用(Java 中對函數式編程的支持)。
50. Thread 類的 sleep()方法和對象的 wait()方法都可以讓線程暫停執行,它們有什么區別?
sleep()方法(休眠)是線程類(Thread)的靜態方法,調用此方法會讓當前線程暫停執行指定的時間,將執行機會(CPU)讓給其他線程,但是對象的鎖依然保持,因此休眠時間結束后會自動恢復。wait()是 Object 類的方法,調用對象的 wait()方法導致當前線程放棄對象的鎖(線程暫停執行),進入對象的等待池(wait pool),只有調用對象的 notify()方法(或 notifyAll()方法)時才能喚醒等待池中的線程進入等鎖池(lock pool),如果線程重新獲得對象的鎖就可以進入就緒狀態。
補充:可能不少人對什么是進程,什么是線程還比較模糊,對于為什么需要多線程編程也不是特別理解。簡單的說:進程是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,是操作系統進行資源分配和調度的一個獨立單位;線程是進程的一個實體,是 CPU 調度和分派的基本單位,是比進程更小的能獨立運行的基本單位。線程的劃分尺度小于進程,這使得多線程程序的并發性高;進程在執行時通常擁有獨立的內存單元,而線程之間可以共享內存。使用多線程的編程通常能夠帶來更好的性能和用戶體驗,但是多線程的程序對于其他程序是不友好的,因為它可能占用了更多的 CPU 資源。當然,也不是線程越多,程序的性能就越好,因為線程之間的調度和切換也會浪費 CPU 時間。時下很時髦的 Node.js就采用了單線程異步 I/O 的工作模式。
51. 線程的 sleep()方法和 yield()方法有什么區別?
sleep()方法給其他線程運行機會時不考慮線程的優先級,因此會給低優先級的線程以運行的機會;yield()方法只會給相同優先級或更高優先級的線程以運行的機會;
線程執行 sleep()方法后轉入阻塞(blocked)狀態,而執行 yield()方法后轉入就緒(ready)狀態;
sleep()方法聲明拋出 InterruptedException,而 yield()方法沒有聲明任何異常;
sleep()方法比 yield()方法(跟操作系統 CPU 調度相關)具有更好的可移植性。
52. 當一個線程進入一個對象的 synchronized 方法 A 之后,其它線程是否可進入此對象的 synchronized 方法 B?
不能。其它線程只能訪問該對象的非同步方法,同步方法則不能進入。因為非靜態方法上的 synchronized 修飾符要求執行方法時要獲得對象的鎖,如果已經進入 A 方法說明對象鎖已經被取走,那么試圖進入 B 方法的線程就只能在等鎖池(注意不是等待池哦)中等待對象的鎖。
52. 請說出與線程同步以及線程調度相關的方法。
wait():使一個線程處于等待(阻塞)狀態,并且釋放所持有的對象的鎖;
sleep():使一個正在運行的線程處于睡眠狀態,是一個靜態方法,調用此方法要處理 InterruptedException 異常;
notify():喚醒一個處于等待狀態的線程,當然在調用此方法的時候,并不能確切的喚醒某一個等待狀態的線程,而是由 JVM 確定喚醒哪個線程,而且與優先級無關;
notityAll():喚醒所有處于等待狀態的線程,該方法并不是將對象的鎖給所有線程,而是讓它們競爭,只有獲得鎖的線程才能進入就緒狀態;
53. 編寫多線程程序有幾種實現方式?
實現多線程有兩種實現方法:一種是繼承 Thread 類;另一種是實現Runnable 接口。兩種方式都要通過重寫 run()方法來定義線程的行為,推薦使用后者,因為 Java 中的繼承是單繼承,一個類有一個父類,如果繼承了 Thread 類就無法再繼承其他類了,顯然使用 Runnable 接口更為靈活。
54. synchronized 關鍵字的用法?
synchronized 關鍵字可以將對象或者方法標記為同步,以實現對對象和方法的互斥訪問,可以用 synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時將 synchronized 作為方法的修飾符。
55. 舉例說明同步和異步。
如果系統中存在臨界資源(資源數量少于競爭資源的線程數量的資源),例如正在寫的數據以后可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那么這些數據就必須進行同步存取(數據庫操作中的排他鎖就是最好的例子)。當應用程序在對象上調用了一個需要花費很長時間來執行的方法,并且不希望讓程序等待方法的返回時,就應該使用異步編程,在很多情況下采用異步途徑往往更有效率。事實上,所謂的同步就是指阻塞式操作,而異步就是非阻塞式操作。
56. 啟動一個線程是調用 run()還是 start()方法?
啟動一個線程是調用 start()方法,使線程所代表的虛擬處理機處于可運行狀態,這意味著它可以由 JVM 調度并執行,這并不意味著線程就會立即運行。run()方法是線程啟動后要進行回調(callback)的方法。
57. 什么是線程池(thread pool)?
在面向對象編程中,創建和銷毀對象是很費時間的,因為創建一個對象要獲取內存資源或者其它更多資源。在 Java 中更是如此,虛擬機將試圖跟蹤每一個對象,以便能夠在對象銷毀后進行垃圾回收。所以提高服務程序效率的一個手段就是盡可能減少創建和銷毀對象的次數,特別是一些很耗資源的對象創建和銷毀,這就是”池化資源”技術產生的原因。線程池顧名思義就是事先創建若干個可執行的線程放入一個池(容器)中,需要的時候從池中獲取線程不用自行創建,使用完畢不需要銷毀線程而是放回池中,從而減少創建和銷毀線程對象的開銷。
58. 簡述 synchronized 和 java.util.concurrent.locks.Lock的異同?
Lock 是 Java 5 以后引入的新的 API,和關鍵字 synchronized 相比主要相同點:Lock 能完成 synchronized 所實現的所有功能;
主要不同點:Lock 有比synchronized 更精確的線程語義和更好的性能,而且不強制性的要求一定要獲得鎖。synchronized 會自動釋放鎖,而 Lock 一定要求程序員手工釋放,并且最好在 finally 塊中釋放(這是釋放外部資源的最好的地方)。
59. Java 中如何實現序列化,有什么意義?
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。可以對流化后的對象進行讀寫操作,也可將流化后的對象傳輸于網絡之間。序列化是為了解決對象流讀寫操作時可能引發的問題(如果不進行序列化可能會存在數據亂序的問題)。要實現序列化,需要讓一個類實現 Serializable 接口,該接口是一個標識性接口,標注該類對象是可被序列化的,然后使用一個輸出流來構造一個對象輸出流并通過 writeObject(Object)方法就可以將實現對象寫出(即保存其狀態);如果需要反序列化則可以用一個輸入流建立對象輸入流,然后通過 readObject 方法從流中讀取對象。序列化除了能夠實現對象的持久化之外,還能夠用于對象的深度克隆。
60. Java 中有幾種類型的流?
字節流和字符流。字節流繼承于 InputStream、OutputStream,字符流繼承于Reader、Writer。在 java.io 包中還有許多其他的流,主要是為了提高性能和使用方便。關于 Java 的 I/O 需要注意的有兩點:一是兩種對稱性(輸入和輸出的對稱性,字節和字符的對稱性);二是兩種設計模式(適配器模式和裝潢模式)。
61. 你在項目中哪些地方用到了 XML?
XML 的主要作用有兩個方面:數據交換和信息配置。
62. 闡述 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();
} } }
63. Statement 和 PreparedStatement 有什么區別?哪個性能更好?
與Statement相比,PreparedStatement 接口代表預編譯的語句,它主要的優勢在于可以減少 SQL 的編譯錯誤并增加 SQL 的安全性(減少 SQL 注入攻擊的可能性)。PreparedStatement 中的 SQL 語句是可以帶參數的,避免了用字符串連接拼接 SQL 語句的麻煩和不安全;當批量處理 SQL 或頻繁執行相同的查詢時,PreparedStatement 有明顯的性能上的優勢,由于數據庫可以將編譯優化后的SQL 語句緩存起來,下次執行相同結構的語句時就會很快(不用再次編譯和生成執行計劃)。
64. 使用 JDBC 操作數據庫時,如何提升讀取數據的性能?如何提升更新數據的性能?
要提升讀取數據的性能,可以指定通過結果集(ResultSet)對象的 setFetchSize()方法指定每次抓取的記錄數(典型的空間換時間策略);要提升更新數據的性能可以使用PreparedStatement 語句構建批處理,將若干 SQL 語句置于一個批處理中執行。
65. 在進行數據庫編程時,連接池有什么作用?
由于創建連接和釋放連接都有很大的開銷(尤其是數據庫服務器不在本地時,每次建立連接都需要進行 TCP 的三次握手,釋放連接需要進行 TCP 四次握手,造成的開銷是不可忽視的),為了提升系統訪問數據庫的性能,可以事先創建若干連接置于連接池中,需要時直接從連接池獲取,使用結束時歸還連接池而不必關閉連接,從而避免頻繁創建和釋放連接所造成的開銷,這是典型的用空間換取時間的策略(浪費了空間存儲連接,但節省了創建和釋放連接的時間)。池化技術在Java 開發中是很常見的,在使用線程時創建線程池的道理與此相同。基于 Java 的開源數據庫連接池主要有:C3P0、Proxool、DBCP、BoneCP、Druid 等。
66. 什么是 DAO 模式?
DAO(Data Access Object)顧名思義是一個為數據庫或其他持久化機制提供了抽象接口的對象,在不暴露底層持久化方案實現細節的前提下提供了各種數據訪問操作。在實際的開發中,應該將所有對數據源的訪問操作進行抽象化后封裝在一個公共 API 中。用程序設計語言來說,就是建立一個接口,接口中定義了此應用程序中將會用到的所有事務方法。在這個應用程序中,當需要和數據源進行交互的時候則使用這個接口,并且編寫一個單獨的類來實現這個接口,在邏輯上該類對應一個特定的數據存儲。DAO 模式實際上包含了兩個模式,一是 DataAccessor(數據訪問器),二是 Data Object(數據對象),前者要解決如何訪問數據的問題,而后者要解決的是如何用對象封裝數據。
67. 事務的 ACID 是指什么?
原子性(Atomic):事務中各項操作,要么全做要么全不做,任何一項操作的失敗都會導致整個事務的失敗;
一致性(Consistent):事務結束后系統狀態是一致的;
隔離性(Isolated):并發執行的事務彼此無法看到對方的中間狀態;
持久性(Durable):事務完成后所做的改動都會被持久化,即使發生災難性的失敗。通過日志和同步備份可以在故障發生后重建數據。
68. 關于事務,在面試中被問到的概率是很高的,可以問的問題也是很多的。首先需要知道的是,只有存在并發數據訪問時才需要事務。當多個事務訪問同一數據時,可能會存在 5 類問題,包括 3 類數據讀取問題(臟讀、不可重復讀和幻讀)和 2 類數據更新問題(第 1 類丟失更新和第 2 類丟失更新)。
臟讀(Dirty Read):A 事務讀取 B 事務尚未提交的數據并在此基礎上操作,而 B事務執行回滾,那么 A 讀取到的數據就是臟數據。
| 時間 | 轉賬事務 A | 取款事務 B |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為1000元 | |
| T4 | 取出 500 元余額修改為 500 元 | |
| T5 | 查詢賬戶余額為 500 元(臟讀) | |
| T6 | 撤銷事務余額恢復為 1000 元 | |
| T7 | 匯入 100 元把余額修改為 600 元 | |
| T8 | 提交事務 |
不可重復讀(Unrepeatable Read):事務 A 重新讀取前面讀取過的數據,發現該數據已經被另一個已提交的事務 B 修改過了。
| 時間 | 轉賬事務 A | 取款事務 B |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為1000元 | |
| T4 | 查詢賬戶余額為 1000元 | |
| T5 | 取出 100元余額修改為 900元 | |
| T6 | 提交事務 | |
| T7 | 查詢賬戶余額為 900 元(不可重復讀) |
幻讀(Phantom Read):事務 A 重新執行一個查詢,返回一系列符合查詢條件的行,發現其中插入了被事務 B 提交的行。
| 時間 | 統計金額事務 A | 轉賬事務 B |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 統計總存款為 10000 元 | |
| T4 | 新增一個存款賬戶存入 100 元 | |
| T5 | 提交事務 | |
| T6 | 再次統計總存款為 10100 元(幻讀) |
第 1 類丟失更新:事務 A 撤銷時,把已經提交的事務 B 的更新數據覆蓋了。
| 時間 | 取款事務 A | 轉賬事務 B |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為1000元 | |
| T4 | 查詢賬戶余額為 1000 元 | |
| T5 | 匯入 100 元修改余額為 1100 元 | |
| T6 | 提交事務 | |
| T7 | 匯入 100 元把余額修改為 900元 | |
| T8 | 撤銷事務 | |
| T9 | 余額恢復為 1000 元(丟失更新) |
第 2 類丟失更新:事務 A 覆蓋事務 B 已經提交的數據,造成事務 B 所做的操作丟失。
| 時間 | 轉賬事務 A | 取款事務 B |
|---|---|---|
| T1 | 開始事務 | |
| T2 | 開始事務 | |
| T3 | 查詢賬戶余額為1000元 | |
| T4 | 查詢賬戶余額為 1000 元 | |
| T5 | 取出 100 元將余額修改為 900 元 | |
| T6 | 提交事務 | |
| T7 | 匯入 100 元把余額修改為 1100元 | |
| T8 | 提交事務 | |
| T9 | 查詢賬戶余額為 1100 元(丟失更新) |
ANSI/ISOSQL 92 標準定義了 4 個等級的事務隔離級別,如下表所示:
| 隔離級別 | 臟讀 | 不可 | 幻讀 | 第一類丟失更新 | 第二類丟失更新 |
|---|---|---|---|---|---|
| READ UNCOMMITED | 允許 | 允許 | 允許 | 不允許 | 允許 |
| READ COMMITTED | 不允許 | 允許 | 允許 | 不允許 | 允許 |
| REPEATABLE READ | 不允許 | 不允許 | 允許 | 不允許 | 不允許 |
| SERIALIZABLE | 不允許 | 不允許 | 不允許 | 不允許 | 不允許 |
需要說明的是,事務隔離級別和數據訪問的并發性是對立的,事務隔離級別越高并發性就越差。所以要根據具體的應用來確定合適的事務隔離級別,這個地方沒有萬能的原則。
68. JDBC 中如何進行事務處理?
Connection 提供了事務處理的方法,通過調用 setAutoCommit(false)可以設置手動提交事務;當事務完成后用 commit()顯式提交事務;如果在事務處理過程中發生異常則通過 rollback()進行事務回滾。
69. 簡述正則表達式及其用途。
在編寫處理字符串的程序時,經常會有查找符合某些復雜規則的字符串的需要。正則表達式就是用于描述這些規則的工具。換句話說,正則表達式就是記錄文本規則的代碼。
70. Java 中是如何支持正則表達式操作的?
Java 中的 String 類提供了支持正則表達式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。
71. 獲得一個類的類對象有哪些方式?
方法 1:類型.class,例如:String.class
方法 2:對象.getClass(),例如:”hello”.getClass()
方法 3:Class.forName(),例如:Class.forName(“java.lang.String”)
72. 如何通過反射創建對象?
方法 1:通過類對象調用 newInstance()方法,例如:String.class.newInstance()
方法 2:通過類對象的 getConstructor()或 getDeclaredConstructor()方法獲得構造器(Constructor)對象并調用其 newInstance()方法創建對象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);
73. 如何通過反射獲取和設置對象私有字段的值?
可以通過類對象的 getDeclaredField()方法字段(Field)對象,然后再通過字段對象的 setAccessible(true)將其設置為可以訪問,接下來就可以通過 get/set 方法來獲取/設置字段的值了。
74. 簡述一下你了解的設計模式。
工廠模式:工廠類可以根據條件生成不同的子類實例,這些子類有一個公共的抽象父類并且實現了相同的方法,但是這些方法針對不同的數據進行了不同的操作(多態方法)。當得到子類的實例后,開發人員可以調用基類中的方法而不必考慮到底返回的是哪一個子類的實例。
代理模式:給一個對象提供一個代理對象,并由代理對象控制原對象的引用。實際開發中,按照使用目的的不同,代理可以分為:遠程代理、虛擬代理、保護代理、Cache 代理、防火墻代理、同步化代理、智能引用代理。
適配器模式:把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起使用的類能夠一起工作。
模板方法模式:提供一個抽象類,將部分邏輯以具體方法或構造器的形式實現,然后聲明一些抽象方法來迫使子類實現剩余的邏輯。不同的子類可以以不同的方式實現這些抽象方法(多態實現),從而實現不同的業務邏輯。
75. 什么是 UML?
UML 是統一建模語言(Unified Modeling Language)的縮寫,它發表于 1997年,綜合了當時已經存在的面向對象的建模語言、方法和過程,是一個支持模型化和軟件系統開發的圖形化語言,為軟件開發的所有階段提供模型化和可視化支持。使用 UML 可以幫助溝通與交流,輔助應用設計和文檔的生成,還能夠闡釋系統的結構和行為。
76. UML 中有哪些常用的圖?
用例圖(用來捕獲需求,描述系統的功能,通過該圖可以迅速的了解系統的功能模塊及其關系)
類圖(描述類以及類與類之間的關系,通過該圖可以快速了解系統)
時序圖(描述執行特定任務時對象之間的交互關系以及執行順序,通過該圖可以了解對象能接收的消息也就是說對象能夠向外界提供的服務)。
77. Java 中應該使用什么數據類型來代表價格?
如果不是特別關心內存和性能的話,使用 BigDecimal,否則使用預定義精度的double 類型。
BigDecimal:不論是float 還是double都是浮點數,而計算機是二進制的,浮點數會失去一定的精確度。Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數進行精確的運算。BigDecimal所創建的是對象,我們不能使用傳統的+、-、*、/等算術運算符直接對其對象進行數學運算,而必須調用其相對應的方法。方法中的參數也必須是BigDecimal的對象。構造器是類的特殊方法,專門用來創建對象,特別是帶有參數的對象。
78. 怎么將 byte 轉換為 String?
可以使用 String 接收 byte[] 參數的構造器String?(byte[] bytes)來進行轉換,需要注意的點是要使用的正確的編碼,否則會使用平臺默認編碼,這個編碼可能跟原來的編碼相同,也可能不同。
79. 我們能將 int 強制轉換為 byte 類型的變量嗎?如果該值大于 byte 類型的范圍,將會出現什么現象?
是的,我們可以做強制轉換,但是 Java 中 int 是 32 位的,而 byte 是 8 位 的,所以,如果強制轉化是,int 類型的高 24 位將會被丟棄,byte 類型的范圍是從 -128 到 128。
80. 存在兩個類,B 繼承 A,C 繼承 B,我們能將 B 轉換為C 么?如 C = (C) B;
假如:A、B、C分別對應動物、貓、黑貓。只知道B是貓,但不一定是黑貓,所以B不能轉換為C。
81. 哪個類包含 clone 方法?是 Cloneable 還是 Object?
java.lang.Cloneable 是一個標示性接口,不包含任何方法,clone 方法在object 類中定義。并且需要知道 clone() 方法是一個本地方法,這意味著它是由c 或 c++ 或 其他本地語言實現的。
82. Java 中 ++ 操作符是線程安全的嗎?
不是線程安全的操作。它涉及到多個指令,如讀取變量值,增加,然后存儲回內存,這個過程可能會出現多個線程交差。
83. a = a + b 與 a += b 的區別
+= 隱式的將加操作的結果類型強制轉換為持有結果的類型。如果兩這個整型相加,如 byte、short 或者 int,首先會將它們提升到 int 類型,然后在執行加法操作。如果加法操作的結果比 a 的最大值要大,則 a+b 會出現編譯錯誤,但是a += b 沒問題。
84. 能在不進行強制轉換的情況下將一個 double 值賦值給long 類型的變量嗎?
不行,因為 double 類型的范圍比 long 類型更廣,所以必須要進行強制轉換。
85. 3*0.1 == 0.3 將會返回什么?true 還是 false?
false,因為有些浮點數不能完全精確的表示出來。
86. int 和 Integer 哪個會占用更多的內存?
Integer 對象會占用更多的內存。Integer 是一個對象,需要存儲對象的元數據。int 是一個原始類型的數據,所以占用的空間更少。
87. 為什么 Java 中的 String 是不可變的(Immutable)?
Java 中的 String 不可變是因為 Java 的設計者認為字符串使用非常頻繁,將字符串設置為不可變可以允許多個客戶端之間共享相同的字符串。
88. 我們能在 Switch 中使用 String 嗎?
從 Java 7 開始,我們可以在 switch case 中使用字符串。
89. Java 中堆和棧有什么區別?
JVM 中堆和棧屬于不同的內存區域,使用目的也不同。棧常用于保存方法幀和局部變量,而對象總是在堆上分配。棧通常都比堆小,也不會在多個線程之間共享,而堆被整個 JVM 的所有線程共享。
90. a.hashCode() 有什么用?與 a.equals(b) 有什么關系?
hashCode() 方法是相應對象整型的 hash 值。它常用于基于 hash 的集合類, 如 Hashtable、HashMap、LinkedHashMap 等等。它與 equals() 方法關系特別緊密。根據 Java 規范,兩個使用 equal() 方法來判斷相等的對象,必須具有相同的 hash code。
91. List、Set、Map 和 Queue 之間的區別
List: 以特定索引來存取元素,存取有序,可以有重復元素。
Set: 元素無序,不能存放重復元素(用對象的equals()方法來區分元素是否重復)。
Map: Map集合是一個雙列集合, 一個元素包含兩個值(一個key, 一個value)Map集合中的元素, key和value的數據類型可以相同,也可以不同。Map集合中的元素, key是不允許重復的,value是可以重復的。Map集合中的元素, key和value是一一對應
Queue: 用于模擬隊列這種數據結構,隊列的頭部保存著隊列中存放時間最長的元素,隊列的尾部保存著隊列中存放時間最短的元素,新元素插入會隊列的尾部
92. poll() 方法和 remove() 方法的區別?
poll() 和 remove() 都是從隊列中取出一個元素,但是 poll() 在獲取元素失敗的時候會返回空,但是 remove() 失敗的時候會拋出異常。
93. Java 中 LinkedHashMap 和 PriorityQueue 的區別是什么?
PriorityQueue保證最高或者最低優先級的的元素總是在隊列頭部,但是LinkedHashMap維持的順序是元素插入的順序。當遍歷一個PriorityQueue時,沒有任何順序保證,但是LinkedHashMap會保證遍歷順序是元素插入的順序。
94. ArrayList 與 LinkedList 的不區別?
ArrayList是實現了基于動態數組的數據結構,LinkedList基于鏈表的數據結構。
對于隨機訪問get和set,ArrayList優于LinkedList,因為LinkedList要移動指針。
對于新增和刪除操作add和remove,LinedList比較占優勢,因為ArrayList要移動數據。
95. 用哪兩種方式來實現集合的排序?
可以使用有序集合,如 TreeSet 或 TreeMap,你也可以使用有順序的的集合, 如 list,然后通過 Collections.sort() 來排序。
96. Java 中怎么打印數組?
可以使用 Arrays.toString() 和 Arrays.deepToString() 方法來打印數組。由于數組沒有實現 toString() 方法,所以如果將數組傳遞給 System.out.println()方法,將無法打印出數組的內容,但是 Arrays.toString() 可以打印每個元素。
97. Hashtable 與 HashMap 有什么不同之處?
a) Hashtable 是 JDK 1 遺留下來的類,而 HashMap 是后來增加的。
b)Hashtable 是同步的,比較慢,但 HashMap 沒有同步策略,所以會更快。
c)Hashtable 不允許有個空的 key,但是 HashMap 允許出現一個 null key。
98. 我們能自己寫一個容器類,然后使用 for-each 循環碼?
可以,你可以寫一個自己的容器類。如果你想使用 Java 中增強的循環來遍歷,你只需要實現 Iterable 接口。如果你實現 Collection 接口,默認就具有該屬性。
99. ArrayList 和 HashMap 的默認大小是多數?
在 Java 7 中,ArrayList 的默認大小是 10 個元素,HashMap 的默認大小是16 個元素(必須是 2 的冪)。
// from ArrayList.java JDK 1.7
private static final int DEFAULT_CAPACITY = 10;
//from HashMap.java JDK 7
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
100. 有沒有可能兩個不相等的對象有有相同的 hashcode?
有可能,兩個不相等的對象可能會有相同的 hashcode 值,這就是為什么在hashmap 中會有沖突。相等 hashcode 值的規定只是說如果兩個對象相等,必須有相同的 hashcode 值,但是沒有關于不相等對象的任何規定。
101. 有沒有可能兩個不相等的對象有有相同的 hashcode?
不能,根據 hash code 的規定,這是不可能的。
102. TCP 協議與 UDP 協議有什么區別?
基于連接與無連接;
對系統資源的要求(TCP較多,UDP少);
UDP程序結構較簡單;
流模式與數據報模式 ;
TCP保證數據正確性,UDP可能丟包,TCP保證數據順序,UDP不保證。
MySQL面試題
1、MySQL 中有哪幾種鎖?
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,并發度最低。
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,并發度也最高。
頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。
2、MySQL 中有哪些不同的表格?
HEAP
HEAP表是MySQL中存取數據最快的表。這是因為他們使用存儲在動態內存中的一個散列索引,不過如果MySQL或服務器崩潰,這些內存數據將會丟失。
ISAM
ISAM表是早期MySQL版本的缺省表類型,知道MyISAM開發出來。建議不要再使用它。
MERGE
MERGE是一個有趣的新類型,在3.23.25之后出現。一個MERGE表實際上又一個MyISAM表的集合,合并而成的一個表,主要是為了效率的考慮,因為這樣不僅僅可以提高速度,搜索效率,修復效率而且還節省了磁盤空間。
MyISAM
MyISAM基于ISAM代碼,可以說是ISAM的衍生品,不過增加了不少好用的擴展。它是MySQL的默認數據表類型,基于了傳統的ISAM類型,ISAM是Indexed Sequential Access Method(有索引的順序訪問方法)的縮寫,一般來說,它是存儲記錄和文件的標準方法。與其他存儲引擎相比,MyISAM具有檢查和修復表格的大多數工具。ISAM表格可以被壓縮,而且它們支持全文索引,不過它們不是事物安全的,也不支持外健。如果事物會滾將會造成不完全會滾,從而不具備原子性。假如忽略事物以及訪問并發性的話,并且需要執行大量的select檢索語句的話,MyISAM將是最好的選擇。
InnoDB
InnoDB是MySQL4.0之后推出的一種比較新的數據表類型,這種類型是事物安全的。它與BDB類型具有相同的特性,它們還支持外健。InnoDB表格速度很快具有比BDB還豐富的特性,因此如果需要一個事物安全的存儲引擎,建議使用它。如果你的數據執行大量的insert或者update,處于性能方面的考慮,同樣應該使用InnoDb表。對于支持事物的InnoDB類型的表來說,影響速度的主要原因是autcommit設置是打開的,而且程序沒有顯式調用begin開始事物,導致每插入一條都自動提交,嚴重影響了速度。可以在執行sql前調用begin,多條sql想成一個事物,將大大提高性能。
3、簡述在 MySQL 數據庫中 MyISAM 和 InnoDB 的區別
MyISAM
不支持事務,但是每次查詢都是原子的;支持表級鎖,即每次操作是對整個表加鎖;存儲表的總行數;一個 MYISAM 表有三個文件:索引文件、表結構文件、數據文件;采用菲聚集索引,索引文件的數據域存儲指向數據文件的指針。輔索引與主索引基本一致,但是輔索引不用保證唯一性。
InnoDB
支持 ACID 的事務,支持事務的四種隔離級別;支持行級鎖及外鍵約束:因此可以支持寫并發;不存儲總行數:一個 InnoDb 引擎存儲在一個文件空間(共享表空間,表大小不受操作系統控制,一個表可能分布在多個文件里),也有可能為多個(設置為獨立表空,表大小受操作系統文件大小限制,一般為 2G),受操作系統文件大小的限制;主鍵索引采用聚集索引(索引的數據域存儲數據文件本身),輔索引的數據域存儲主鍵的值;因此從輔索引查找數據,需要先通過輔索引找到主鍵值,再訪問輔索引;最好使用自增主鍵,防止插入數據時,為維持 B+樹結構,文件的大調整。
4、MySQL 中 InnoDB 支持的四種事務隔離級別名稱,以及逐級之間的區別?
SQL 標準定義的四個隔離級別為:
read uncommited :讀到未提交數據
read committed:臟讀,不可重復讀
repeatable read:可重讀
serializable :串行事物
5、CHAR 和 VARCHAR 的區別?
區別一:char 表示定長,長度固定,varchar表示變長,即長度可變。char如果插入的長度小于定義長度時,則用空格填充;varchar小于定義長度時,還是按實際長度存儲,插入多長就存多長。因為其長度固定,char的存取速度還是要比varchar要快得多,方便程序的存儲與查找;但是char也為此付出的是空間的代價,因為其長度固定,所以會占據多余的空間,可謂是以空間換取時間效率。varchar則剛好相反,以時間換空間。
區別二:存儲的容量不同,對 char 來說,最多能存放的字符個數 255,和編碼無關。而 varchar 呢,最多能存放 65532 個字符。varchar的最大有效長度由最大行大小和使用的字符集確定。整體最大長度是 65,532字節。
6、主鍵和候選鍵有什么區別?
表格的每一行都由主鍵唯一標識,一個表只有一個主鍵。主鍵也是候選鍵。按照慣例,候選鍵可以被指定為主鍵,并且可以用于任何外鍵引用。
7、myisamchk 是用來做什么的?
它用來壓縮 MyISAM 表,這減少了磁盤或內存使用。
8、MyISAM Static 和 MyISAM Dynamic 有什么區別?
在 MyISAM Static 上的所有字段有固定寬度。動態 MyISAM 表將具有像 TEXT,BLOB 等字段,以適應不同長度的數據類型。MyISAM Static 在受損情況下更容易恢復。
9、如果一個表有一列定義為 TIMESTAMP,將發生什么?
每當行被更改時,時間戳字段將獲取當前時間戳。
10、列設置為 AUTO INCREMENT 時,如果在表中達到最大值,會發生什么情況?
它會停止遞增,任何進一步的插入都將產生錯誤,因為密鑰已被使用。
11、怎樣才能找出最后一次插入時分配了哪個自動增量?
LAST_INSERT_ID 將返回由 Auto_increment 分配的最后一個值,并且不需要指定表名稱。
12、你怎么看到為表格定義的所有索引?
索引是通過以下方式為表格定義的:SHOW INDEX FROM ;
13、LIKE 聲明中的%和_是什么意思?
%對應于 0 個或更多字符,_只是 LIKE 語句中的一個字符。
14、如何在 Unix 和 MySQL 時間戳之間進行轉換?
UNIX_TIMESTAMP 是從 MySQL 時間戳轉換為 Unix 時間戳的命令
FROM_UNIXTIME 是從 Unix 時間戳轉換為 MySQL 時間戳的命令
15、列對比運算符是什么?
在 SELECT 語句的列比較中使用=,<>,<=,<,> =,>,<<,>>,<=>,AND,OR 或 LIKE 運算符。
16、BLOB 和 TEXT 有什么區別?
BLOB 是一個二進制對象,可以容納可變數量的數據。TEXT 是一個不區分大小寫的 BLOB。
BLOB 和 TEXT 類型之間的唯一區別在于對 BLOB 值進行排序和比較時區分大小寫,對 TEXT 值不區分大小寫。
17、MySQL_fetch_array 和 MySQL_fetch_object 的區別是什么?
MySQL_fetch_array() – 將結果行作為關聯數組或來自數據庫的常規數組返回。
MySQL_fetch_object – 從數據庫返回結果行作為對象。
18、MySQL 如何優化 DISTINCT?
DISTINCT 在所有列上轉換為 GROUP BY,并與 ORDER BY 子句結合使用。SELECT DISTINCT t1.a FROM t1,t2 where t1.a=t2.a;
19、如何顯示前 50 行?
在 MySQL 中,使用以下代碼查詢顯示前 50 行:SELECT * FROM LIMIT 0,50;
20、可以使用多少列創建索引?
任何標準表最多可以創建 16 個索引列。
21、NOW()和 CURRENT_DATE()有什么區別?
NOW()命令用于顯示當前年份,月份,日期,小時,分鐘和秒。
CURRENT_DATE()僅顯示當前年份,月份和日期。
22、什么是非標準字符串類型?
TINYTEXT
TEXT
MEDIUMTEXT
LONGTEXT
23、MySQL 支持事務嗎?
在缺省模式下,MySQL 是 autocommit 模式的,所有的數據庫更新操作都會即時提交,所以在缺省情況下,MySQL 是不支持事務的。
但是如果你的 MySQL 表類型是使用 InnoDB Tables 或 BDB tables 的話,你的MySQL 就可以使用事務處理,使用 SETAUTOCOMMIT=0 就可以使 MySQL 允許在非 autocommit 模式,在非autocommit 模式下,你必須使用 COMMIT 來提交你的更改,或者用 ROLLBACK來回滾你的更改。
24、優化數據庫的方法
1、選取最適用的字段屬性,盡可能減少定義字段寬度,盡量把字段設置 NOTNULL,例如’省份’、’性別’最好適用 ENUM
2、使用連接(JOIN)來代替子查詢
3、適用聯合(UNION)來代替手動創建的臨時表
4、事務處理
5、鎖定表、優化事務處理
6、適用外鍵,優化鎖定表
7、建立索引
8、優化查詢語句
25、簡單描述 MySQL 中,索引,主鍵,唯一索引,聯合索引的區別,對數據庫的性能有什么影響(從讀寫兩方面)
索引是一種特殊的文件(InnoDB 數據表上的索引是表空間的一個組成部分),它們包含著對數據表里所有記錄的引用指針。
普通索引(由關鍵字 KEY 或 INDEX 定義的索引)的唯一任務是加快對數據的訪問速度。
普通索引允許被索引的數據列包含重復的值。如果能確定某個數據列將只包含彼此各不相同的值,在為這個數據列創建索引的時候就應該用關鍵字 UNIQUE 把它定義為一個唯一索引。也就是說,唯一索引可以保證數據記錄的唯一性。
主鍵,是一種特殊的唯一索引,在一張表中只能定義一個主鍵索引,主鍵用于唯一標識一條記錄,使用關鍵字 PRIMARY KEY 來創建。
索引可以覆蓋多個數據列,如像 INDEX(columnA, columnB)索引,這就是聯合索引。
索引可以極大的提高數據的查詢速度,但是會降低插入、刪除、更新表的速度,因為在執行這些寫操作時,還要操作索引文件。
26、數據庫中的事務是什么?
事務(transaction)是作為一個單元的一組有序的數據庫操作。如果組中的所有操作都成功,則認為事務成功,即使只有一個操作失敗,事務也不成功。如果所有操作完成,事務則提交,其修改將作用于所有其他數據庫進程。如果一個操作失敗,則事務將回滾,該事務所有操作的影響都將取消。
事務特性:
1、原子性:即不可分割性,事務要么全部被執行,要么就全部不被執行。
2、一致性或可串性。事務的執行使得數據庫從一種正確狀態轉換成另一種正確狀態
3、隔離性。在事務正確提交之前,不允許把該事務對數據的任何改變提供給任何其他事務,
4、持久性。事務正確提交后,其結果將永久保存在數據庫中,即使在事務提交后有了其他故障,事務的處理結果也會得到保存。
或者這樣理解:
事務就是被綁定在一起作為一個邏輯工作單元的 SQL 語句分組,如果任何一個語句操作失敗那么整個操作就被失敗,以后操作就會回滾到操作前狀態,或者是上有個節點。為了確保要么執行,要么不執行,就可以使用事務。要將有組語句作為事務考慮,就需要通過 ACID 測試,即原子性,一致性,隔離性和持久性。
27、SQL 注入漏洞產生的原因?如何防止?
SQL 注入產生的原因:
程序開發過程中不注意規范書寫 sql 語句和對特殊字符進行過濾,導致客戶端可以通過全局變量 POST 和 GET 提交一些 sql 語句正常執行。
防止 SQL 注入的方式:
開啟配置文件中的 magic_quotes_gpc 和 magic_quotes_runtime 設置,執行 sql 語句時使用 addslashes 進行 sql 語句轉換,Sql 語句書寫盡量不要省略雙引號和單引號。過濾掉 sql 語句中的一些關鍵詞:update、insert、delete、select、 * 。提高數據庫表和字段的命名技巧,對一些重要的字段根據程序的特點命名,取不易被猜到的。
28、為表中得字段選擇合適得數據類型
字段類型優先級: 整形>date,time>enum,char>varchar>blob,text優先考慮數字類型,其次是日期或者二進制類型,最后是字符串類型,同級別得數據類型,應該優先選擇占用空間小的數據類型
29、存儲時期
Datatime:以 YYYY-MM-DD HH:MM:SS 格式存儲時期時間,精確到秒,占用 8 個字節得存儲空間,datatime 類型與時區無關
Timestamp:以時間戳格式存儲,占用 4 個字節,范圍小 1970-1-1 到 2038-1-19,顯示依賴于所指定得時區,默認在第一個列行的數據修改時可以自動得修改timestamp 列得值
Date:(生日)占用得字節數比使用字符串.datatime.int 儲存要少,使用 date 只需要 3 個字節,存儲日期月份,還可以利用日期時間函數進行日期間得計算
Time:存儲時間部分得數據
注意:不要使用字符串類型來存儲日期時間數據(通常比字符串占用得儲存空間小,在進行查找過濾可以利用日期得函數)
使用 int 存儲日期時間不如使用 timestamp 類型
30、對于關系型數據庫而言,索引是相當重要的概念,請回答有關索引的幾個問題:
1、索引的目的是什么?
快速訪問數據表中的特定信息,提高檢索速度,創建唯一性索引,保證數據庫表中每一行數據的唯一性。加速表和表之間的連接,使用分組和排序子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間。
2、索引對數據庫系統的負面影響是什么?
負面影響:
創建索引和維護索引需要耗費時間,這個時間隨著數據量的增加而增加;索引需要占用物理空間,不光是表需要占用數據空間,每個索引也需要占用物理空間;當對表進行增、刪、改、的時候索引也要動態維護,這樣就降低了數據的維護速度。
3、為數據表建立索引的原則有哪些?
在最頻繁使用的、用以縮小查詢范圍的字段上建立索引。在頻繁使用的、需要排序的字段上建立索引
4、什么情況下不宜建立索引?
對于查詢中很少涉及的列或者重復值比較多的列,不宜建立索引。對于一些特殊的數據類型,不宜建立索引,比如文本字段(text)等
31、解釋 MySQL 外連接、內連接與自連接的區別
先說什么是交叉連接: 交叉連接又叫笛卡爾積,它是指不使用任何條件,直接將一個表的所有記錄和另一個表中的所有記錄一一匹配。
內連接 則是只有條件的交叉連接,根據某個條件篩選出符合條件的記錄,不符合條件的記錄不會出現在結果集中,即內連接只連接匹配的行。
外連接 其結果集中不僅包含符合連接條件的行,而且還會包括左表、右表或兩個表中的所有數據行,這三種情況依次稱之為左外連接,右外連接,和全外連接。
左外連接,也稱左連接,左表為主表,左表中的所有記錄都會出現在結果集中,對于那些在右表中并沒有匹配的記錄,仍然要顯示,右邊對應的那些字段值以NULL 來填充。右外連接,也稱右連接,右表為主表,右表中的所有記錄都會出現在結果集中。左連接和右連接可以互換,MySQL 目前還不支持全外連接。
32、Myql 中的事務回滾機制概述
事務是用戶定義的一個數據庫操作序列,這些操作要么全做要么全不做,是一個不可分割的工作單位,事務回滾是指將該事務已經完成的對數據庫的更新操作撤銷。要同時修改數據庫中兩個不同表時,如果它們不是一個事務的話,當第一個表修改完,可能第二個表修改過程中出現了異常而沒能修改,此時就只有第二個表依舊是未修改之前的狀態,而第一個表已經被修改完畢。而當你把它們設定為一個事務的時候,當第一個表修改完,第二表修改出現異常而沒能修改,第一個表和第二個表都要回到未修改的狀態,這就是所謂的事務回滾
33、SQL 語言包括哪幾部分?每部分都有哪些操作關鍵字?
SQL 語言包括數據定義(DDL)、數據操縱(DML),數據控制(DCL)和數據查詢(DQL)四個部分。
數據定義:Create Table,Alter Table,Drop Table, Craete/Drop Index 等
數據操縱:Select ,insert,update,delete,
數據控制:grant,revoke
數據查詢:select
34、什么是鎖?
數據庫是一個多用戶使用的共享資源。當多個用戶并發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的情況。若對并發操作不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的一致性。加鎖是實現數據庫并發控制的一個非常重要的技術。當事務在對某個數據對象進行操作前,先向系統發出請求,對其加鎖。加鎖后事務就對該數據對象有了一定的控制,在該事務釋放鎖之前,其他的事務不能對此數據對象進行更新操作。基本鎖類型:鎖包括行級鎖和表級鎖
35、什么叫視圖?游標是什么?
視圖是一種虛擬的表,具有和物理表相同的功能。可以對視圖進行增,改,查,操作,視圖通常是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得我們獲取數據更容易,相比多表查詢。
游標:是對查詢出來的結果集作為一個單元來有效的處理。游標可以定在該單元中的特定行,從結果集的當前行檢索一行或多行。可以對結果集當前行做修改。一般不使用游標,但是需要逐條處理數據的時候,游標顯得十分重要。
36、什么是存儲過程?用什么來調用?
存儲過程是一個預編譯的 SQL 語句,優點是允許模塊化的設計,就是說只需創建一次,以后在該程序中就可以調用多次。如果某次操作需要執行多次 SQL,使用存儲過程比單純 SQL 語句執行要快。可以用一個命令對象來調用存儲過程。
37、如何通俗地理解三個范式?
第一范式:1NF 是對屬性的原子性約束,要求屬性具有原子性,不可再分解;
第二范式:2NF 是對記錄的惟一性約束,要求記錄有惟一標識,即實體的惟一性;
第三范式:3NF 是對字段冗余性的約束,即任何字段不能由其他字段派生出來,它要求字段沒有冗余。。
范式化設計優缺點:
優點:
可以盡量得減少數據冗余,使得更新快,體積小
缺點:對于查詢需要多個表進行關聯,減少寫得效率增加讀得效率,更難進行索引優化
反范式化:
優點:可以減少表得關聯,可以更好得進行索引優化
缺點:數據冗余以及數據異常,數據得修改需要更多的成本
38、什么是基本表?什么是視圖?
基本表是本身獨立存在的表,在 SQL 中一個關系就對應一個表。 視圖是從一個或幾個基本表導出的表。視圖本身不獨立存儲在數據庫中,是一個虛表。
39、試述視圖的優點?
(1) 視圖能夠簡化用戶的操作
(2) 視圖使用戶能以多種角度看待同一數據;
(3) 視圖為數據庫提供了一定程度的邏輯獨立性;
(4) 視圖能夠對機密數據提供安全保護。
40、NULL 是什么意思
NULL 這個值表示 UNKNOWN(未知):它不表示“”(空字符串)。對 NULL 這個值的任何比較都會生產一個 NULL 值。您不能把任何值與一個 NULL 值進行比較,并在邏輯上希望獲得一個答案。
使用 IS NULL 來進行 NULL 判斷
41、主鍵、外鍵和索引的區別?
定義:
主鍵–唯一標識一條記錄,不能有重復的,不允許為空
外鍵–表的外鍵是另一表的主鍵, 外鍵可以有重復的, 可以是空值
索引–該字段沒有重復值,但可以有一個空值
作用:
主鍵–用來保證數據完整性
外鍵–用來和其他表建立聯系用的
索引–是提高查詢排序的速度
個數:
主鍵–主鍵只能有一個
外鍵–一個表可以有多個外鍵
索引–一個表可以有多個唯一索引
42、你可以用什么來確保表格里的字段只接受特定范圍里的值?
Check 限制,它在數據庫表格里被定義,用來限制輸入該列的值。
觸發器也可以被用來限制數據庫表格里的字段能夠接受的值,但是這種辦法要求
觸發器在表格里被定義,這可能會在某些情況下影響到性能。
43、說說對 SQL 語句優化有哪些方法?(選擇幾條)
1、Where 子句中:where 表之間的連接必須寫在其他 Where 條件之前,那些可以過濾掉最大數量記錄的條件必須寫在 Where 子句的末尾.HAVING 最后。
2、用 EXISTS 替代 IN、用 NOT EXISTS 替代 NOT IN。
3、 避免在索引列上使用計算
4、避免在索引列上使用 IS NULL 和 IS NOT NULL
5、對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
6、應盡量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描
7、應盡量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描
總結
以上是生活随笔為你收集整理的Java常问面试题整理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的世界手机版凋零风暴怎么造
- 下一篇: shortcuts 快捷键