{eval=Array;=+count(Array);}
如果是想找高質量面試題的話不妨看看動力節點官網上面試題也是非常全面新鮮的!
1、String類可以被繼承嗎?
String類在聲明時使用final關鍵字修飾,被final關鍵字修飾的類無法被繼承。
接下來我們可以看一下String類的源代碼片段:
public final class String implements java.io.Serializable, Comparable<String>,CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L;
● 為什么Java語言的開發者,把String類定義為final的呢?
因為只有當字符串是不可變的,字符串池才有可能實現。字符串池的實現可以在運行時節約很多heap空間,因為不同的字符串變量都指向池中的同一個字符串。但如果字符串是可變的,那么String interning將不能實現,因為這樣的話,如果變量改變了它的值,那么其它指向這個值的變量的值也會一起改變。如果字符串是可變的,那么會引起很嚴重的安全問題。譬如,數據庫的用戶名、密碼都是以字符串的形式傳入來獲得數據庫的連接,或者在socket編程中,主機名和端口都是以字符串的形式傳入。因為字符串是不可變的,所以它的值是不可改變的,否則黑客們可以鉆到空子,改變字符串指向的對象的值,造成安全漏洞。
因為字符串是不可變的,所以是多線程安全的,同一個字符串實例可以被多個線程共享。這樣便不用因為線程安全問題而使用同步。字符串自己便是線程安全的。
因為字符串是不可變的,所以在它創建的時候HashCode就被緩存了,不需要重新計算。這就使得字符串很適合作為Map中的鍵,字符串的處理速度要快過其它的鍵對象。這就是HashMap中的鍵往往都使用字符串。
● final關鍵字除了修飾類之外,還有哪些用法呢?
final修飾的變量,一旦賦值,不可重新賦值;
final修飾的方法無法被覆蓋;
final修飾的實例變量,必須手動賦值,不能采用系統默認值;
final修飾的實例變量,一般和static聯用,用來聲明常量;
注意:final不能和abstract關鍵字聯合使用。
總之,final表示最終的、不可變的。
2、& 和 && 的區別?
● &運算符是:邏輯與;&&運算符是:短路與。
● &和&&在程序中最終的運算結果是完全一致的,只不過&&存在短路現象,當&&運算符左邊的表達式結果為false的時候,右邊的表達式不執行,此時就發生了短路現象。如果是&運算符,那么不管左邊的表達式是true還是false,右邊表達式是一定會執行的。這就是他們倆的本質區別。
● 當然,&運算符還可以使用在二進制位運算上,例如按位與操作。
3、兩個對象值相同equals結果為true,但卻可有不同的 hashCode,這句話對不對?
不對,如果兩個對象x和y滿足x.equals(y) == true,它們的哈希值(hashCode)應當相同。Java 對于equals方法和hashCode方法是這樣規定的:
(1)如果兩個對象相同(equals方法返回true),那么它們的hashCode值一定要相同;
(2)如果兩個對象的 hashCode相同,它們并不一定相同。當然,你未必按照要求去做,但是如果你違背了上述原則就會發現在使用集合時,相同的對象可以出現在Set 集合中,同時增加新元素的效率會大大降低(對于使用哈希存儲的系統,如果哈希碼頻繁的沖突將會造成存取性能急劇下降)。
關于equals和hashCode方法,很多Java程序員都知道,但很多人也就是僅僅了解而已,在Joshua Bloch的大作《Effective Java》(《Effective Java》在很多公司,是Java程序員必看書籍,如果你還沒看過,那就趕緊去買一本吧)中是這樣介紹 equals 方法的:
首先equals方法必須滿足自反性(x.equals(x)必須返回true)、對稱性(x.equals(y)返回true 時,y.equals(x)也必須返回true)、傳遞性(x.equals(y)和y.equals(z)都返回true時,x.equals(z)也必須返回true)和一致性(當x和y引用的對象信息沒有被修改時,多次調用x.equals(y)應該得到同樣的返回值),而且對于任何非null值的引用x,x.equals(null)必須返回false。實現高質量的equals方法的訣竅包括:
使用==操作符檢查"參數是否為這個對象的引用";
使用 instanceof操作符檢查"參數是否為正確的類型";
對于類中的關鍵屬性,檢查參數傳入對象的屬性是否與之相匹配;
編寫完equals方法后,問自己它是否滿足對稱性、傳遞性、一致性;
重寫equals時總是要重寫hashCode;
不要將equals方法參數中的Object對象替換為其他的類型,在重寫時不要忘掉@Override注解。
4、在 Java 中,如何跳出當前的多重嵌套循環?
在最外層循環前加一個標記如outfor,然后用break outfor;可以跳出多重循環。例如以下代碼:
public class TestBreak {
public static void main(String[] args) {
outfor: for (int i = 0; i < 10; i++){
for (int j = 0; j < 10; j++){
if (j == 5){
break outfor;
}
System.out.println("j = " + j);
}
}
}
}
運行結果如下所示:
j = 0
j = 1
j = 2
j = 3
j = 4
5、重載(overload)和重寫(override)的區別?重載的方法能否根據返回類型進行區分?
方法的重載和重寫都是實現多態的方式,區別在于前者實現的是編譯時的多態性,而后者實現的是運行時的多態性。
重載發生在一個類中,同名的方法如果有不同的參數列表(類型不同、個數不同、順序不同)則視為重載。
重寫發生在子類與父類之間,重寫要求子類重寫之后的方法與父類被重寫方法有相同的返回類型,比父類被重寫方法更好訪問,不能比父類被重寫方法聲明更多的異常(里氏代換原則)。重載對返回類型沒有特殊的要求。
● 方法重載的規則:
方法名一致,參數列表中參數的順序,類型,個數不同。
重載與方法的返回值無關,存在于父類和子類,同類中。
可以拋出不同的異常,可以有不同修飾符。
● 方法重寫的規則:
參數列表、方法名、返回值類型必須完全一致;
構造方法不能被重寫;
聲明為 final 的方法不能被重寫;
聲明為 static 的方法不存在重寫(重寫和多態聯合才有意義);
訪問權限不能比父類更低;
重寫之后的方法不能拋出更寬泛的異常;
6、當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里是值傳遞還是引用傳遞?
是值傳遞。Java 語言的方法調用只支持參數的值傳遞。當一個對象實例作為一個參數被傳遞到方法中時,參數的值就是對該對象的內存地址。這個值(內存地址)被傳遞后,同一個內存地址指向堆內存當中的同一個對象,所以通過哪個引用去操作這個對象,對象的屬性都是改變的。
7、為什么方法不能根據返回類型來區分重載?
我們來看以下的代碼:
public void testMethod(){
doSome();
}
public void doSome(){
}
public int doSome(){
return 1;
}
在Java語言中,調用一個方法,即使這個方法有返回值,我們也可以不接收這個返回值,例如以上兩個方法doSome(),在testMethod()中調用的時候,Java編譯器無法區分調用的具體是哪個方法。所以對于編譯器來說,doSome()方法不是重載而是重復了,編譯器報錯。所以區分這兩個方法不能依靠方法的返回值類型。
8、抽象類(abstract class)和接口(interface)有什么異同?
不同點:
● 抽象類中可以定義構造器,接口不能;
● 抽象類可以有抽象方法和具體方法,接口不能有具體方法;
● 接口中的成員全都是 public 的,抽象類中的成員可以使用private、public、protected、默認等修飾;
● 抽象類中可以定義成員變量,接口中只能是常量;
● 有抽象方法的類必須被聲明為抽象類,而抽象類未必要有抽象方法;
● 抽象類中可以包含靜態方法,接口中不能有靜態方法;
● 一個類只能繼承一個抽象類,一個類可以實現多個接口;
相同點:
● 不能夠實例化;
● 可以將抽象類和接口類型作為引用類型;
● 一個類如果繼承了某個抽象類或者實現了某個接口都需要對其中的抽象方法全部進行實現,否則該類仍然需要被聲明為抽象類;
9、char 型變量中能不能存儲一個中文漢字,為什么?
char 類型可以存儲一個中文漢字,因為Java中使用的編碼是Unicode(不選擇任何特定的編碼,直接使用字符在字符集中的編號,這是統一的唯一方法),一個char 類型占2個字節(16 比特),所以放一個中文是沒問題的。
補充:使用Unicode 意味著字符在JVM內部和外部有不同的表現形式,在JVM內部都是 Unicode,當這個字符被從JVM內部轉移到外部時(例如存入文件系統中),需要進行編碼轉換。所以 Java 中有字節流和字符流,以及在字符流和字節流之間進行轉換的轉換流,如 InputStreamReader和OutputStreamReader,這兩個類是字節流和字符流之間的適配器類,承擔了編碼轉換的任務。
10、抽象的(abstract)方法是否可同時是靜態的(static), 是否可同時是本地方法(native),是否可同時被 synchronized?
都不能。
● 抽象方法需要子類重寫,而靜態的方法是無法被重寫的,因此二者是矛盾的。
● 本地方法是由本地代碼(如 C++ 代碼)實現的方法,而抽象方法是沒有實現的,也是矛盾的。
● synchronized 和方法的實現細節有關,抽象方法不涉及實現細節,因此也是相互矛盾的。
1、面向對象包括哪些特性,怎么理解的?
(1)封裝:通常認為封裝是把數據和操作數據的方法綁定起來,對數據的訪問只能通過已定義的接口。面向對象的本質就是將現實世界描繪成一系列完全自治、封閉的對象。我們在類中編寫的方法就是對實現細節的一種封裝;我們編寫一個類就是對數據和數據操作的封裝。可以說,封裝就是隱藏一切可隱藏的東西,只向外界提供最簡單的編程接口。
(2)繼承:繼承是從已有類得到繼承信息創建新類的過程。提供繼承信息的類被稱為父類(超類、基類);得到繼承信息的類被稱為子類(派生類)。繼承讓變化中的軟件系統有了一定的延續性,同時繼承也是封裝程序中可變因素的重要手段。
(3)多態:多態性是指允許不同子類型的對象對同一消息作出不同的響應。簡單的說就是用同樣的對象引用調用同樣的方法但是做了不同的事情。多態性分為編譯時的多態性和運行時的多態性。如果將對象的方法視為對象向外界提供的服務,那么運行時的多態性可以解釋為:當 A系統訪問B系統提供的服務時,B 系統有多種提供服務的方式,但一切對 A 系統來說都是透明的。方法重載(overload)實現的是編譯時的多態性(也稱為前綁定),而方法重寫(override)實現的是運行時的多態性(也稱為后綁定)。運行時的多態是面向對象最精髓的東西,要實現多態需要做兩件事:
第一:方法重寫(子類繼承父類并重寫父類中已有的或抽象的方法);
第二:對象造型(用父類型引用指向子類型對象,這樣同樣的引用調用同樣的方法就會根據子類對象的不同而表現出不同的行為)。
(4)抽象:抽象是將一類對象的共同特征總結出來構造類的過程,包括數據抽象和行為抽象兩方面。抽象只關注對象有哪些屬性和行為,并不關注這些行為的細節是什么。
2、訪問權限修飾符 public、private、protected, 以及不寫(默認)時的區別?
修飾符
當前類
同包
子類
其他包
public
√
√
√
√
protected
√
√
√
×
默認(缺省)
√
√
×
×
private
√
×
×
×
3、Java中為什么要用 clone?
在實際編程過程中,我們常常要遇到這種情況:有一個對象 A,在某一時刻 A 中已經包含了一些有效值,此時可能會需要一個和 A 完全相同新對象 B,并且此后對 B 任何改動都不會影響到 A 中的值,也就是說,A 與 B 是兩個獨立的對象,但 B 的初始值是由 A 對象確定的。在 Java 語言中,用簡單的賦值語句是不能滿足這種需求的。要滿足這種需求雖然有很多途徑,但clone()方法是其中最簡單,也是最高效的手段。
● 說到對象的克隆,涉及到深克隆和淺克隆?
淺克隆:創建一個新對象,新對象的屬性和原來對象完全相同,對于非基本類型屬性,仍指向原有屬性所指向的對象的內存地址。
深克隆:創建一個新對象,屬性中引用的其他對象也會被克隆,不再指向原有對象地址。
4、new一個對象的過程和clone一個對象的區別?
new 操作符的本意是分配內存。程序執行到 new 操作符時,首先去看 new 操作符后面的類型,因為知道了類型,才能知道要分配多大的內存空間。分配完內存之后,再調用構造函數,填充對象的各個域,這一步叫做對象的初始化,構造方法返回后,一個對象創建完畢,可以把他的引用(地址)發布到外部,在外部就可以使用這個引用操縱這個對象。
clone 在第一步是和 new 相似的,都是分配內存,調用 clone 方法時,分配的內存和原對象(即調用 clone 方法的對象)相同,然后再使用原對象中對應的各個域,填充新對象的域,填充完成之后,clone方法返回,一個新的相同的對象被創建,同樣可以把這個新對象的引用發布到外部。
5、Java中實現多態的機制是什么?
Java中的多態靠的是父類或接口定義的引用變量可以指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。
6、談談你對多態的理解?
多態就是指程序中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在編程時并不確定,而是在程序運行期間才確定,即一個引用變量到底會指向哪個類的實例對象,該引用變量發出的方法調用到底是哪個類中實現的方法,必須在程序運行期間才能決定。因為在程序運行時才確定具體的類,這樣,不用修改源代碼,就可以讓引用變量綁定到各種不同的對象上,從而導致該引用調用的具體方法隨之改變,即不修改程序代碼就可以改變程序運行時所綁定的具體代碼,讓程序可以選擇多個運行狀態,這就是多態性。
7、談談你對面向對象的理解?
所謂對象就是由一組數據結構和處理它們的方法組成的,重點“數據”包括對象的特性、狀態等的靜態信息;“方法” 也就是行為,包括該對象的對數據的操作、功能等能動信息。把相同行為的對象歸納為類,類是一個抽象的概念,對象是類的具體。簡單點說:對象就是類的實例。例如:小品演員就是一個類,趙本山就是一個對象。
面向對象的目的:解決軟件系統的可擴展性,可維護性和可重用性。
● 面向對象的三大特性:封裝、多態和繼承:
(1)封裝(對應可擴展性):隱藏對象的屬性和實現細節,僅對外公開接口,控制在程序中屬性的讀和修改的訪問級別。封裝是通過訪問控制符(public protected private)來實現。一個類就可看成一個封裝。
(2)繼承(重用性和擴展性):子類繼承父類,可以繼承父類的方法和屬性。可以對父類方向進行覆蓋(實現了多態)。但是繼承破壞了封裝,因為他是對子類開放的,修改父類會導致所有子類的改變,因此繼承一定程度上又破壞了系統的可擴展性,只有明確的IS-A關系才能使用。繼承要慎用,盡量優先使用組合。
(3)多態(可維護性和可擴展性):接口的不同實現方式即為多態。接口是對行為的抽象,剛才在封裝提到,找到變化部分并封裝起來,但是封裝起來后,怎么適應接下來的變化?這正是接口的作用,接口的主要目的是為不相關的類提供通用的處理服務,我們可以想象一下。比如鳥會飛,但是超人也會飛,通過飛這個接口,我們可以讓鳥和超人,都實現這個接口。
面向對象編程(OOP)其實就是一種設計思想,在程序設計過程中把每一部分都盡量當成一個對象來考慮,以實現軟件系統的可擴展性,可維護性和可重用性。
1、final、finally、finalize 的區別?
● final:用于聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,被其修飾的類不可繼承。
● finally:異常處理語句結構的一部分,表示總是執行。
● finalize:Object 類的一個方法,所以Java對象都有這個方法,當某Java對象沒有更多的引用指向的時候,會被垃圾回收器回收,該對象被回收之前,由垃圾回收器來負責調用此方法,通常在該方法中進行回收前的準備工作。該方法更像是一個對象生命周期的臨終方法,當該方法被系統調用則代表該對象即將“死亡”,但是需要注意的是,我們主動行為上去調用該方法并不會導致該對象“死亡”,這是一個被動的方法(其實就是回調方法),不需要我們調用。
按照異常需要處理的時機分為編譯時異常(也叫受控異常)也叫 CheckedException 和運行時異常(也叫非受控異常)也叫 UnCheckedException。Java認為Checked異常都是可以被處理的異常,所以Java程序必須顯式處理Checked異常。如果程序沒有處理Checked 異常,該程序在編譯時就會發生錯誤無法編譯。這體現了Java 的設計哲學:沒有完善錯誤處理的代碼根本沒有機會被執行。對Checked異常處理方法有兩種:
● 第一種:當前方法知道如何處理該異常,則用try...catch塊來處理該異常。
● 第二種:當前方法不知道如何處理,則在定義該方法時聲明拋出該異常。
運行時異常只有當代碼在運行時才發行的異常,編譯的時候不需要try…catch。Runtime如除數是0和數組下標越界等,其產生頻繁,處理麻煩,若顯示申明或者捕獲將會對程序的可讀性和運行效率影響很大。所以由系統自動檢測并將它們交給缺省的異常處理程序。當然如果你有處理要求也可以顯示捕獲它們。
Error類和Exception類的父類都是Throwable類,他們的區別如下:
● Error類一般是指與虛擬機相關的問題,如系統崩潰,虛擬機錯誤,內存空間不足,方法調用棧溢出等。對于這類錯誤的導致的應用程序中斷,僅靠程序本身無法恢復和預防,遇到這樣的錯誤,建議讓程序終止。
● Exception類表示程序可以處理的異常,可以捕獲且可能恢復。遇到這類異常,應該盡可能處理異常,使程序恢復運行,而不應該隨意終止異常。
●Exception類又分為未檢查異常(UnCheckedException)和受檢查的異常(CheckedException)。運行時異常ArithmeticException,IllegalArgumentException編譯能通過,但是一運行就終止了,程序不會處理運行時異常,出現這類異常,程序會終止。而受檢查的異常,要么用 try…catch 捕獲,要么用throws字句聲明拋出,交給它的父類處理,否則編譯不會通過。
1. public int getNum() {
2. try {
3. int a = 1 / 0;
4. return 1;
5. } catch (Exception e) {
6. return 2;
7. } finally {
8. return 3;
9. }
10.}
代碼走到第3行的時候遇到了一個MathException,這時第4行的代碼就不會執行了,代碼直接跳轉到catch語句中,走到第 6 行的時候,異常機制有一個原則:如果在catch中遇到了return或者異常等能使該函數終止的話那么有finally就必須先執行完finally代碼塊里面的代碼然后再返回值。因此代碼又跳到第8行,可惜第8行是一個return語句,那么這個時候方法就結束了,因此第6行的返回結果就無法被真正返回。如果finally僅僅是處理了一個釋放資源的操作,那么該道題最終返回的結果就是2。因此上面返回值是3。
Java對異常進行了分類,不同類型的異常分別用不同的Java類表示,所有異常的根類為 java.lang.Throwable,Throwable下面又派生了兩個子類:Error和Exception。
Error表示應用程序本身無法克服和恢復的一種嚴重問題。
Exception表示程序還能夠克服和恢復的問題,其中又分為系統異常和普通異常。
系統異常是軟件本身缺陷所導致的問題,也就是軟件開發人員考慮不周所導致的問題,軟件使用者無法克服和恢復這種問題,但在這種問題下還可以讓軟件系統繼續運行或者讓軟件死掉,例如,數組下標越界(ArrayIndexOutOfBoundsException),空指針異常(NullPointerException)、類轉換異常(ClassCastException)。
普通異常是運行環境的變化或異常所導致的問題,是用戶能夠克服的問題,例如,網絡斷線,硬盤空間不夠,發生這樣的異常后,程序不應該死掉。
Java為系統異常和普通異常提供了不同的解決方案,編譯器強制普通異常必須try..catch處理或用throws聲明繼續拋給上層調用方法處理,所以普通異常也稱為checked異常,而系統異常可以處理也可以不處理,所以編譯器不強制用try..catch處理或用throws聲明,所以系統異常也稱為unchecked異常。
● java.lang.NullPointerException 空指針異常;出現原因:調用了未經初始化的對象或者是不存在的對象。
● java.lang.ClassNotFoundException 指定的類找不到;出現原因:類的名稱和路徑加載錯誤;通常都是程序試圖通過字符串來加載某個類時可能引發異常。
● java.lang.NumberFormatException 字符串轉換為數字異常;出現原因:字符型數據中包含非數字型字符。
● java.lang.IndexOutOfBoundsException 數組角標越界異常,常見于操作數組對象時發生。
● java.lang.IllegalArgumentException 方法傳遞參數錯誤。
● java.lang.ClassCastException 數據類型轉換異常。
● java.lang.NoClassDefFoundException 未找到類定義錯誤。
● SQLException SQL 異常,常見于操作數據庫時的 SQL 語句錯誤。
● java.lang.InstantiationException 實例化異常。
● java.lang.NoSuchMethodException 方法不存在異常。
● throw:
throw 語句用在方法體內,表示拋出異常,由方法體內的語句處理。
throw是具體向外拋出異常的動作,所以它拋出的是一個異常實例,執行throw一定是拋出了某種異常。
● throws:
throws語句是用在方法聲明后面,表示如果拋出異常,由該方法的調用者來進行異常的處理。
throws主要是聲明這個方法會拋出某種類型的異常,讓它的使用者要知道需要捕獲的異常的類型。
● throws表示出現異常的一種可能性,并不一定會發生這種異常。
像我常用的就是牛客網、動力節點官網也有不少面試題,我就是在這培訓的,最近也剛刷完面試題,準備著去面試了!!檢驗我的時刻到了~現在就把之前老師給我的面試題整理下,還是挺多的,這個學校只教Java就很專業~
關于贏在面試的Java題系列基本收集整理完成了,所有題目都是經過精心挑選的,很基礎又考驗求職者的基本功,應該說被面試到的幾率很大。這里整理挑選出來供大家面試前拿來看一看。
hashCode() 方法對應對象整型的 hash 值。它常用于基于 hash 的集合類,如 Hashtable、HashMap、LinkedHashMap等等。它與 equals() 方法關系特別緊密。根據 Java 規范,兩個使用 equal() 方法來判斷相等的對象,必須具有相同的 hash code。
要把一段二進制數據數據逐一輸出到某個設備中,或者從某個設備中逐一讀取一段二進制數據,不管輸入輸出設備是什么,我們要用統一的方式來完成這些操作,用一種抽象的方式進行描述,這個抽象描述方式起名為IO流,對應的抽象類為OutputStream和InputStream,不同的實現類就代表不同的輸入和輸出設備,它們都是針對字節進行操作的。
計算機中的一切最終都是二進制的字節形式存在。對于經常用到的中文字符,首先要得到其對應的字節,然后將字節寫入到輸出流。讀取時,首先讀到的是字節,可是我們要把它顯示為字符,我們需要將字節轉換成字符。由于這樣的需求很廣泛,Java專門提供了字符流包裝類。
底層設備永遠只接受字節數據,有時候要寫字符串到底層設備,需要將字符串轉成字節再進行寫入。字符流是字節流的包裝,字符流則是直接接受字符串,它內部將串轉成字節,再寫入底層設備,這為我們向IO設備寫入或讀取字符串提供了一點點方便。
字符向字節轉換時,要注意編碼的問題,因為字符串轉成字節數組,其實是轉成該字符的某種編碼的字節形式,讀取也是反之的道理。
我們有時候將一個Java對象變成字節流的形式傳出去或者從一個字節流中恢復成一個Java對象,例如,要將Java對象存儲到硬盤或者傳送給網絡上的其他計算機,這個過程我們可以自己寫代碼去把一個Java對象變成某個格式的字節流再傳輸。
但是,jre本身就提供了這種支持,我們可以調用OutputStream的writeObject方法來做,如果要讓Java幫我們做,要被傳輸的對象必須實現serializable接口,這樣,Javac編譯時就會進行特殊處理,編譯的類才可以被writeObject方法操作,這就是所謂的序列化。需要被序列化的類必須實現Serializable接口,該接口是一個mini接口,其中沒有需要實現方法,implements Serializable只是為了標注該對象是可被序列化的。
例如,在web開發中,如果對象被保存在了Session中,tomcat在重啟時要把Session對象序列化到硬盤,這個對象就必須實現Serializable接口。如果對象要經過分布式系統進行網絡傳輸,被傳輸的對象就必須實現Serializable接口。
JVM中類的裝載是由ClassLoader和它的子類來實現的,Java ClassLoader是一個重要的Java運行時系統組件。它負責在運行時查找和裝入類文件的類。
Java的內存分為兩類,一類是棧內存,一類是堆內存。棧內存是指程序進入一個方法時,會為這個方法多帶帶分配一塊私屬存儲空間,用于存儲這個方法內部的局部變量,當這個方法結束時,分配給這個方法的棧會釋放,這個棧中的變量也將隨之釋放。
堆是與棧作用不同的內存,一般用于存放不在當前方法棧中的那些數據,例如,使用new創建的對象都放在堆里,所以,它不會隨方法的結束而消失。方法中的局部變量使用final修飾后,放在堆中,而不是棧中。
GC是垃圾收集的意思(Gabage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會導致程序或系統的不穩定甚至崩潰,Java提供的GC功能可以自動監測對象是否超過作用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操作方法。
Java語言中一個顯著的特點就是引入了垃圾回收機制,使c++程序員最頭疼的內存管理的問題迎刃而解,它使得Java程序員在編寫程序的時候不再需要考慮內存管理。由于垃圾回收機制,Java中的對象不再有"作用域"的概念,只有對象的引用才有"作用域"。
垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作為一個多帶帶的低級別的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。
回收機制有分代復制垃圾回收和標記垃圾回收,增量垃圾回收。
對于GC來說,當程序員創建對象時,GC就開始監控這個對象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象。通過這種方式確定哪些對象是"可達的",哪些對象是"不可達的"。當GC確定一些對象為"不可達"時,GC就有責任回收這些內存空間。
程序員可以手動執行System.gc(),通知GC運行,但是Java語言規范并不保證GC一定會執行。
throw 用于拋出 Java.lang.Throwable 類的一個實例化對象,意思是說你可以通過關鍵字 throw 拋出一個Exception,如:
throw new IllegalArgumentException(“XXXXXXXXX″)
而throws 的作用是作為方法聲明和簽名的一部分,方法被拋出相應的異常以便調用者能處理。Java 中,任何未處理的受檢查異常強制在 throws 子句中聲明。
先解釋什么是內存泄漏:所謂內存泄露就是指一個不再被程序使用的對象或變量一直被占據在內存中。Java中有垃圾回收機制,它可以保證當對象不再被引用的時候,對象將自動被垃圾回收器從內存中清除掉。
由于Java使用有向圖的方式進行垃圾回收管理,可以消除引用循環的問題,例如有兩個對象,相互引用,只要它們和根進程不可達,那么GC也是可以回收它們的。
Java中的內存泄露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發生內存泄露,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是Java中內存泄露的發生場景,通俗地說,就是程序員可能創建了一個對象,以后一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是Java中可能出現內存泄露的情況,例如,緩存系統,我們加載了一個對象放在緩存中(例如放在一個全局map對象中),然后一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。
Servlet有良好的生存期的定義,包括加載和實例化、初始化、處理請求以及服務結束。這個生存期由Javax.servlet.Servlet接口的init(),service()和destroy方法表達。
Servlet被服務器實例化后,容器運行其init方法,請求到達時運行其service方法,service方法自動派遣運行與請求對應的doXXX方法(doGet,doPost)等,當服務器決定將實例銷毀的時候調用其destroy方法。
web容器加載servlet,生命周期開始。通過調用servlet的init()方法進行servlet的初始化。通過調用service()方法實現,根據請求的不同調用不同的do***()方法。結束服務,web容器調用servlet的destroy()方法。
(1).從地址欄顯示來說
forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然后把這些內容再發給瀏覽器.瀏覽器根本不知道服務器發送的內容從哪里來的,所以它的地址欄還是原來的地址.
redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址.所以地址欄顯示的是新的URL.所以redirect等于客戶端向服務器端發出兩次request,同時也接受兩次response。
(2).從數據共享來說
forward:轉發頁面和轉發到的頁面可以共享request里面的數據.
redirect:不能共享數據.
redirect不僅可以重定向到當前應用程序的其他資源,還可以重定向到同一個站點上的其他應用程序中的資源,甚至是使用絕對URL重定向到其他站點的資源.
forward方法只能在同一個Web應用程序內的資源之間轉發請求.forward 是服務器內部的一種操作.
redirect 是服務器通知客戶端,讓客戶端重新發起請求.
所以,你可以說 redirect 是一種間接的請求, 但是你不能說"一個請求是屬于forward還是redirect "
(3).從運用地方來說
forward:一般用于用戶登陸的時候,根據角色轉發到相應的模塊.
redirect:一般用于用戶注銷登陸時返回主頁面和跳轉到其它的網站等.
(4).從效率來說
forward:高.
redirect:低.
(1),request.getParameter()取得是通過容器的實現來取得通過類似post,get等方式傳入的數據。
request.setAttribute()和getAttribute()只是在web容器內部流轉,僅僅是請求處理階段。
(2),getAttribute是返回對象,getParameter返回字符串
(3),getAttribute()一向是和setAttribute()一起使用的,只有先用setAttribute()設置之后,才能夠通過getAttribute()來獲得值,它們傳遞的是Object類型的數據。而且必須在同一個request對象中使用才有效。,而getParameter()是接收表單的get或者post提交過來的參數
(1)、<%@include file="xxx.jsp"%>為jsp中的編譯指令,其文件的包含是發生在jsp向servlet轉換的時期,而<jsp:include page="xxx.jsp">是jsp中的動作指令,其文件的包含是發生在編譯時期,也就是將Java文件編譯為class文件的時期
(2)、使用靜態包含只會產生一個class文件,而使用動態包含會產生多個class文件
(3)、使用靜態包含,包含頁面和被包含頁面的request對象為同一對象,因為靜態包含只是將被包含的頁面的內容復制到包含的頁面中去;而動態包含包含頁面和被包含頁面不是同一個頁面,被包含的頁面的request對象可以取到的參數范圍要相對大些,不僅可以取到傳遞到包含頁面的參數,同樣也能取得在包含頁面向下傳遞的參數。
MVC是Model-View-Controller的簡寫。Model代表的是應用的業務邏輯(通過JavaBean,EJB組件實現),View是應用的表示面(由JSP頁面產生),Controller是提供應用的處理過程控制(一般是一個Servlet),通過這種設計模型把應用邏輯,處理過程和顯示邏輯分成不同的組件實現。這些組件可以進行交互和重用。
JSP共有以下9個內置的對象:
(1),request 用戶端請求,此請求會包含來自GET/POST請求的參數
(2),response 網頁傳回用戶端的回應
(3),pageContext 網頁的屬性是在這里管理
(4),session 與請求有關的會話期
(5),application servlet 正在執行的內容
(6),out 用來傳送回應的輸出
(7),config servlet的構架部件
(8),page JSP網頁本身
(9),exception 針對錯誤網頁,未捕捉的例外
(1),Get是向服務器發索取數據的一種請求,而Post是向服務器提交數據的一種請求
(2),Get是獲取信息,而不是修改信息,類似數據庫查詢功能一樣,數據不會被修改
(3),Get請求的參數會跟在url后進行傳遞,請求的數據會附在URL之后,以?分割URL和傳輸數據,參數之間以&相連,%XX中的XX為該符號以16進制表示的ASCII,如果數據是英文字母/數字,原樣發送,如果是空格,轉換為+,如果是中文/其他字符,則直接把字符串用BASE64加密。
(4),Get傳輸的數據有大小限制,因為GET是通過URL提交數據,那么GET可提交的數據量就跟URL的長度有直接關系了,不同的瀏覽器對URL的長度的限制是不同的。
(5),GET請求的數據會被瀏覽器緩存起來,用戶名和密碼將明文出現在URL上,其他人可以查到歷史瀏覽記錄,數據不太安全。
在服務器端,用Request.QueryString來獲取Get方式提交來的數據Post請求則作為http消息的實際內容發送給web服務器,數據放置在HTML Header內提交,Post沒有限制提交的數據。Post比Get安全,當數據是中文或者不敏感的數據,則用get,因為使用get,參數會顯示在地址,對于敏感數據和不是中文字符的數據,則用post。
(6),POST表示可能修改變服務器上的資源的請求,在服務器端,用Post方式提交的數據只能用Request.Form來獲取。
(僅供參考,如果有更好的回答,歡迎探討)
Cookie是會話技術,將用戶的信息保存到瀏覽器的對象.
區別:
(1)cookie數據存放在客戶的瀏覽器上,session數據放在服務器上
(2)cookie不是很安全,別人可以分析存放在本地的COOKIE并進行COOKIE欺騙,如果主要考慮到安全應當使用session
(3)session會在一定時間內保存在服務器上。當訪問增多,會比較占用你服務器的性能,如果主要考慮到減輕服務器性能方面,應當使用COOKIE
(4)單個cookie在客戶端的限制是3K,就是說一個站點在客戶端存放的COOKIE不能3K。
結論:
將登陸信息等重要信息存放為SESSION;其他信息如果需要保留,可以放在COOKIE中。
JSP是Servlet技術的擴展,本質上就是Servlet的簡易方式。JSP編譯后是“類servlet”。
Servlet和JSP最主要的不同點在于:Servlet的應用邏輯是在Java文件中,并且完全從表示層中的HTML里分離開來。而JSP的情況是Java和HTML可以組合成一個擴展名為.jsp的文件。
JSP側重于視圖,Servlet主要用于控制邏輯。在struts框架中,JSP位于MVC設計模式的視圖層,而Servlet位于控制層.
當容器啟動時,會讀取在webapps目錄下所有的web應用中的web.xml文件,然后對xml文件進行解析,并讀取servlet注冊信息。然后,將每個應用中注冊的servlet類都進行加載,并通過反射的方式實例化。(有時候也是在第一次請求時實例化)在servlet注冊時加上<load-on-startup>1</load-on-startup>如果為正數,則在一開始就實例化,如果不寫或為負數,則第一次請求實例化。
(1),加載驅動
(2),通過DriverManager對象獲取連接對象Connection
(3),通過連接對象獲取會話
(4),通過會話進行數據的增刪改查,封裝對象
(5),關閉資源
(1),效率:預編譯會話比普通會話對象,數據庫系統不會對相同的sql語句不會再次編譯
(2),安全性:可以有效的避免sql注入攻擊!sql注入攻擊就是從客戶端輸入一些非法的特殊字符,而使服務器端在構造sql語句的時候仍然能夠正確構造,從而收集程序和服務器的信息和數據。比如:“select * from t_user where userName = ‘” + userName + “ ’ and password =’” + password + “’”如果用戶名和密碼輸入的是’1’ or ‘1’=’1’ ; 則生產的sql語句是:“select * from t_user where userName = ‘1’ or ‘1’ =’1’ and password =’1’ or ‘1’=’1’ 這個語句中的where 部分沒有起到對數據篩選的作用。
(1) 事務是作為單個邏輯工作單元執行的一系列操作。
(2),一個邏輯工作單元必須有四個屬性,稱為原子性、一致性、隔離性和持久性 (ACID) 屬性,只有這樣才能成為一個事務
事務處理步驟:
(3),conn.setAutoComit(false);設置提交方式為手工提交
(4),conn.commit()提交事務
(5),出現異常,回滾 conn.rollback();
(1),數據庫連接是一件費時的操作,連接池可以使多個操作共享一個連接。
(2),數據庫連接池的基本思想就是為數據庫連接建立一個“緩沖池”。預先在緩沖池中放入一定數量的連接,當需要建立數據庫連接時,只需從“緩沖池”中取出一個,使用完畢之后再放回去。我們可以通過設定連接池最大連接數來防止系統無盡的與數據庫連接。更為重要的是我們可以通過連接池的管理機制監視數據庫的連接的數量、使用情況,為系統開發,測試及性能調整提供依據。
(3),使用連接池是為了提高對數據庫連接資源的管理
當我們使用事務時,有可能會出現這樣的情況,有一行數據剛更新,與此同時另一個查詢讀到了這個剛更新的值。這樣就導致了臟讀,因為更新的數據還沒有進行持久化,更新這行數據的業務可能會進行回滾,這樣這個數據就是無效的。數據庫的TRANSACTIONREADCOMMITTED,TRANSACTIONREPEATABLEREAD,和TRANSACTION_SERIALIZABLE隔離級別可以防止臟讀。
幻讀是指一個事務多次執行一條查詢返回的卻是不同的值。假設一個事務正根據某個條件進行數據查詢,然后另一個事務插入了一行滿足這個查詢條件的數據。之后這個事務再次執行了這條查詢,返回的結果集中會包含剛插入的那條新數據。這行新數據被稱為幻行,而這種現象就叫做幻讀。
只有TRANSACTION_SERIALIZABLE隔離級別才能防止產生幻讀。
JDBC的DriverManager是一個工廠類,我們通過它來創建數據庫連接。當JDBC的Driver類被加載進來時,它會自己注冊到DriverManager類里面然后我們會把數據庫配置信息傳成DriverManager.getConnection()方法,DriverManager會使用注冊到它里面的驅動來獲取數據庫連接,并返回給調用的程序。
(1),Statement的execute(String query)方法用來執行任意的SQL查詢,如果查詢的結果是一個ResultSet,這個方法就返回true。如果結果不是ResultSet,比如insert或者update查詢,它就會返回false。我們可以通過它的getResultSet方法來獲取ResultSet,或者通過getUpdateCount()方法來獲取更新的記錄條數。
(2),Statement的executeQuery(String query)接口用來執行select查詢,并且返回ResultSet。即使查詢不到記錄返回的ResultSet也不會為null。我們通常使用executeQuery來執行查詢語句,這樣的話如果傳進來的是insert或者update語句的話,它會拋出錯誤信息為 “executeQuery method can not be used for update”的java.util.SQLException。
(3),Statement的executeUpdate(String query)方法用來執行insert或者update/delete(DML)語句,或者 什么也不返回,對于DDL語句,返回值是int類型,如果是DML語句的話,它就是更新的條數,如果是DDL的話,就返回0。只有當你不確定是什么語句的時候才應該使用execute()方法,否則應該使用executeQuery或者executeUpdate方法。
Oracle:
MySQL:
sql server:
在查詢數據庫后會返回一個ResultSet,它就像是查詢結果集的一張數據表。ResultSet對象維護了一個游標,指向當前的數據行。開始的時候這個游標指向的是第一行。如果調用了ResultSet的next()方法游標會下移一行,如果沒有更多的數據了,next()方法會返回false。可以在for循環中用它來遍歷數據集。默認的ResultSet是不能更新的,游標也只能往下移。也就是說你只能從第一行到最后一行遍歷一遍。不過也可以創建可以回滾或者可更新的ResultSet
當生成ResultSet的Statement對象要關閉或者重新執行或是獲取下一個ResultSet的時候,ResultSet對象也會自動關閉。可以通過ResultSet的getter方法,傳入列名或者從1開始的序號來獲取列數據。
以上就是我總結的這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值。
0
回答0
回答0
回答0
回答0
回答0
回答0
回答1
回答0
回答0
回答