java核心技術面試
【前方高能,是這半年BAT,京東,遠景,華為,中興以及蘇研發中心被問到的Java公共問題的一個整理】
-----------------------------------------------------------------------------------------------------------------------------------------------
1、.java原始檔:
一個以”.java“為字尾的原始檔:只能有一個與檔名相同的類,可以包含其他類。
2、類方法:
類方法:類中用static修飾的方法(非static為例項方法) |
在類方法中呼叫本類的類方法時,可以直接呼叫。 |
在類方法中不能有this關鍵字,直接呼叫類方法即可。 |
類方法中可以通過建立例項物件呼叫類的例項方法。 |
3、super和this關鍵字
在子類構造器中使用super()顯示呼叫父類的構造方法,super()必須寫在子類構造方法的第一行,否則編譯不通過;
this:
屬性:this屬性表示找到本類的屬性,如果本類沒有找到則繼續查詢父類;
方法:this方法表示找到本類的方法,如果本類沒有找到則繼續查詢父類;
構造:必須放在構造方法的首行,不能與super關鍵字同時出現;
特殊:表示當前物件;
super:
屬性:super屬性直接在子類之中查詢父類中的指定屬性,不再查詢子類本身屬性;
方法:super方法直接在子類之中查詢父類中的指定方法,不再查詢子類本身方法;
構造:必須放在構造方法首行,不能與this關鍵字同時出現。
super和this關鍵字 |
1)呼叫super()必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地呼叫super(),如果父類沒有這種形式的建構函式,那麼在編譯的時候就會報錯。 2)super從子類中呼叫父類的構造方法,this()在同一類內呼叫其它方法。 3)super()和this()均需放在構造方法內第一行。 4)儘管可以用this呼叫一個構造器,但卻不能呼叫兩個。 5)this和super不能同時出現在一個建構函式裡面,因為this必然會呼叫其它的建構函式,其它的建構函式必然也會有super語句的存在,所以在同一個建構函式裡面有相同的語句,就失去了語句的意義,編譯器也不會通過。 6)this()和super()都指的是物件,所以,均不可以在static環境中使用。包括:static變數,static方法,static語句塊。 7)從本質上講,this是一個指向本物件的指標, 然而super是一個Java關鍵字。 |
4、抽象類
1、抽象類不能被例項化,例項化的工作應該交由它的子類來完成,它只需要有一個引用即可。
2、抽象方法必須由子類來進行重寫。
3、只要包含一個抽象方法的類,該類必須要定義成抽象類,不管是否還包含有其他方法。
4、抽象類中可以包含具體的方法,當然也可以不包含抽象方法。
5、子類中的抽象方法不能與父類的抽象方法同名。
6、abstract不能與final並列修飾同一個類。(abstract需要子類去實現,而final表示不能被繼承,矛盾。)
7、abstract 不能與private、static、final或native並列修飾同一個方法。
A、final修飾的類為終態類,不能被繼承,而抽象類是必須被繼承的才有其意義的,因此,final是不能用來修飾抽象類的。
B、 final修飾的方法為終態方法,不能被重寫。而繼承抽象類,必須重寫其方法。
C、抽象方法是僅宣告,並不做實現的方法。
5、訪問許可權:
(1)訪問許可權修飾詞:
1)public(公共的):表明該成員變數或方法對所有類或物件都是可見的,所有類或物件都可以直接訪問;
2)protected(受保護的):表明成員變數或方法對該類本身&與它在同一個包中的其它類&在其它包中的該類的子類都可見;
3)default(預設的,不加任何訪問修飾符):表明成員變數或方法只有自己&其位於同一個包內的類可見;
4)private(私有的):表明該成員變數或方法是私有的,只有當前類對其具有訪問許可權。
由大到小:public(介面訪問許可權)、protected(繼承訪問許可權)、包訪問許可權(沒有使用任何訪問許可權修飾詞)、private(私有無法訪問)
protected表示就類使用者而言,這是private的,但對於任何繼承於此類的匯出類或其他任何位於同一個包內的類來說,卻是可以訪問的。(protected也提供了包內訪問許可權)
private和protected一般不用來修飾外部類,而public、abstract或final可以用來修飾外部類(如果用private和protected修飾外部類,會使得該類變得訪問性受限)。
(2)訪問許可權注意點:
1、類的訪問許可權,只能是包訪問許可權(預設無訪問修飾符即可)或者public。若把一個類中的構造器指定為private,則不能訪問該類,若要建立該類的物件,則需要再該類的static成員內部建立,如單例模式。
2、如果沒能為類訪問許可權指定一個訪問修飾符,預設得到包訪問許可權,則該類的物件可以由包內任何其他類建立,但是包外不可以。
3、訪問許可權的控制,也稱為具體實現的隱藏。制定規則(如使用訪問許可權,設定成員所遵守的界限),是防止客戶端程式設計師對類隨心所欲而為。
(3)控制對成員的訪問許可權的兩個原因:
· 使使用者不要碰觸那些不該碰觸的部分,對類內部的操作是必要的,不屬於客戶端程式設計師所需介面的一部分;
· 讓類庫設計者可以更改類的內部工作方式,而不會對客戶端程式設計師產生重大影響;訪問許可權控制可以確保不會有任何客戶端程式設計師依賴於類的底層實現的任何部分。
(4)對某成員的訪問權的唯一途徑:
· 1.該成員為public;
· 2.通過不加訪問許可權修飾詞並將其他類放置在同一個包內的方式給成員賦予包訪問權。
· 3.繼承技術,訪問protected成員
· 4.提供訪問器和變異器(get/set方法),以讀取和改變數值。
6、值傳遞與引用傳遞
值傳遞:Java中原始資料型別都是值傳遞,傳遞的是值的副本,形參的改變不會影響實際引數的值;
引用傳遞: 傳遞的是引用型別資料,包括String,陣列,列表,map,類物件等型別,形參與實參指向的是同一記憶體地址,因此形參改變會影響實參的值。
7、封裝:
把資料和方法包裝進類中,以及實現的隱藏,共同稱作封裝。結果是一個同時帶有特徵和行為的資料型別。
8、組合、繼承:
(1)組合:
定義:只需在新的類中產生現有類的物件,由於新的類是由現有類的物件所組成, 稱為組合。組合技術知識將物件引用置於新類中即可。
缺點:將一個成員物件置於所要構造的類中(組合),在新類中暴露這個成員物件的所有方法(繼承),需要折中(代理),可以選擇只提供在成員物件中的方法的某個子集。
特點:
· 1.has-a關係用組合;
· 2.組合技術通常用於想在新類中使用現有類的功能而非它的介面這種情形。在新類中嵌入某個物件,讓其實現所需要的功能,但新類的使用者看到的只是為新類所定義的介面,而非所嵌入物件的介面。
(2)繼承:
定義:按照現有類的型別來建立新類 ,無需改變現有類的形式,採用現有類的形式並在其增加新程式碼,稱為繼承。通過關鍵字extends實現。
特點:
· 1.當建立一個類時,總在繼承。(除非明確指明繼承類,否則都是隱式第繼承根類Object)
· 2.為了繼承,一般將所有的資料成員都指定為private,將所有的方法指定為public。
· 3.可以將繼承視作是對類的複用;
· 4.is-a關係用繼承;
· 5.繼承允許物件視為自身的型別或其基型別加以處理;
· 6.如果向上轉型,不能呼叫那些新的方法(如Animal an = new Cat(),an是不能呼叫Cat中有的而Animal中沒有的方法,會返回一條編譯時出錯訊息),所以向上轉型會丟失具體的型別資訊;
注意:
1.構造方法不能被繼承;方法和屬性可以被繼承;
2.子類的構造方法隱式地呼叫父類的不帶引數的構造方法;
3.當父類沒有不帶引數的構造方法時,子類需要使用super來顯示呼叫父類的構造方法,super指的是對父類的引用
4.super關鍵字必須是構造方法中的第一行語句。特例如下
當兩個方法形成重寫關係時,可在子類方法中通過super.run()形式呼叫父類的run()方法,其中super.run()不必放在第一行語句,因此此時父類物件已經構造完畢,先呼叫父類的run()方法還是先呼叫子類的run()方法是根據程式的邏輯決定的。
總結:
代理使用時,可以擁有更多的控制力,可以選擇只提供在成員物件中的方法的某個子集;
組合和繼承都允許在新的類中放置子物件,組合是顯式地放置,繼承是隱式的做;
組合和繼承都能從現有型別中生成新類,組合一般是將現有型別作為新型別底層實現的一部分加以複用,而繼承複用的是介面。優先使用組合。
9、final關鍵字
1)使用範圍:資料、方法和類
2)final關鍵字:final可以修飾屬性、方法、類。
3)final修飾類:當一個類被final所修飾時,表示該類是一個終態類,即不能被繼承。
4)final修飾方法:當一個方法被final所修飾時,表示該方法是一個終態方法,即不能被重寫(Override)。
5)final修飾屬性:當一個屬性被final所修飾時,表示該屬性不能被改寫。
(1)final資料:
· 1.編譯時常量:是使用static和 final修飾的常量,全用大寫字母命名,且字與字之間用下劃線隔開。(不能因為資料是final的就認為在編譯時就知道值,在執行時也可以用某數值來初始化某一常量)
· 2.final修飾基本資料型別和物件引用:對於基本型別,final修飾的數值是恆定不變;而final修飾物件引用,則引用恆定不變(一旦引用被初始化指向一個物件,就不能改為指向另一個物件),但是物件本身的內容可以修改。
· 3.空白final:空白final是指被宣告為final但又未給定初值的域,無論什麼情況,編譯器都保證空白final在使用被初始化。必須在域的定義處或每個構造器中用表示式對final進行賦值。
· 4.final引數:final修飾引數後,在方法體中不允許對引數進行更改,只可以讀final引數。主要用於向匿名類傳遞資料。
(2)final方法:
· 1.使用final修飾方法原因:將方法鎖定以及效率問題。將方法鎖定:防止任何繼承類修改final方法的含義,確保該方法行為保持不變,且不會被覆蓋;效率:早期Java實現中同意編譯器將針對該方法的所有呼叫轉為內嵌呼叫。
· 2.類中所有的private方法都隱式地指定為final的。
(3)final類:
· 1.將某個類整體定義為final時,則不繼承該類,不能有子類。
10、初始化及類的載入
1.載入的含義:通常,載入發生在建立類的第一個物件時,但訪問static域或static方法時,也會發生載入。static的東西只會初始化一次。
2.載入過程:載入一個類的時候,首先去載入父類的靜態域,然後再載入自身的靜態域,之後去初始化父類的成員變數,後加載父類的構造方法,最後初始化自身的成員變數,後加載自身的構造方法。(先初始化成員變數,後加載建構函式的原因是,建構函式中可能要用到這些成員變數)
父類靜態塊——子類靜態塊——父類塊——父類構造器——子類塊——子類構造器
最終版本:父類靜態域——父類靜態塊——子類靜態域——子類靜態塊——父類成員變數及程式碼塊——父類構造器——子類成員變數及程式碼塊——子類構造器。
3.載入次數:載入的動作只會載入一次,該類的靜態域或第一個實體的建立都會引起載入。
4.變數的初始化:變數的初始化總是在當前類構造器主體執行之前進行的,且static的成員比普通的成員變數先初始化。
11、多型
1.多型只發生在普通方法中,對於域和static方法,不發生多型。子類物件轉化為父型別引用時,對於任何域的訪問都是由編譯器解析。靜態方法是與類相關聯,而不與單個物件相關聯;
2.在繼承時,若被覆寫的方法不是private,則父類呼叫方法時,會呼叫子類的方法,常用的多型性就是當父類引用指向子類物件時。
3.多型就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數到底指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。
4.多型是同一個行為具有多個不同表現形式或形態的能力。
5.多型就是同一個介面,使用不同的例項而執行不同操作,多型性是物件多種表現形式的體現。
12、構造器
1.為什麼強制每個匯出類部分都必須呼叫構造器的原因?(基類的構造器總是在匯出類的構造過程中被呼叫)
只有基類的構造器才具有恰當的知識和許可權對自己的元素進行初始化,因此必須令所有的構造器都得到呼叫。匯出類只能訪問自己的成員,不能訪問基類中的成員(通常是private型別)。
2.編寫構造器原則:用盡可能的簡單的方法使物件進入正常狀態;如果可以的話,避免呼叫其他方法,因為呼叫這些方法,有可能會導致初始化未進行,呼叫的是0值,在構造器內唯一能夠安全呼叫的方法是基類中的final方法(呼叫不能被覆蓋的方法)。
13、基本資料型別與包裝類
所有的包裝類(8個)都位於java.lang包下,分別是Byte,Short,Integer,Long,Float,Double,Character,Boolean
基本資料型別:byte:8位;short:16位;int:32位;long:64位;float:32位;double:64位;char:16位;boolean:8位。
14、==與equals方法的區別:
(1)基本資料型別與引用資料型別
1.基本資料型別的比較:只能用==;
2.引用資料型別的比較:==是比較棧記憶體中存放的物件在堆記憶體地址,equals是比較物件的內容是否相同;
(2)特殊:String作為一個物件
例子一:通過建構函式建立物件時。物件不同,內容相同,"=="返回false,equals返回true
String s1 = newString("java");
String s2 = new String("java");
System.out.println(s1==s2); //false
System.out.println(s1.equals(s2)); //true
例子二:同一物件,"=="和equals結果相同
String s1 = newString("java");
String s2 = s1; //兩個不同的引用變數指向同一個物件
System.out.println(s1==s2); //true
System.out.println(s1.equals(s2)); //true
如果值不相同,物件就不相同,所以"=="和equals結果一樣
String s1 = "java";
String s2 = "java"; //此時String常量池中有java物件,直接返回引用給s2;
System.out.println(s1==s2); //true
System.out.println(s1.equals(s2)); //true
字面量形式建立物件時:
如果String緩衝池內不存在與其指定值相同的String物件,那麼此時虛擬機器將為此建立新的String物件,並存放在String緩衝池內。
如果String緩衝池記憶體在與其指定值相同的String物件,那麼此時虛擬機器將不為此建立新的String物件,而直接返回已存在的String物件的引用。
(3)String的字面量形式和建構函式建立物件
1)String s = "aaa";採用字面值方式賦值
1.查詢StringPool中是否存再“aaa”這個物件,如果不存在,則在StringPool中建立一個“aaa”物件,然後將String Pool中的這個“aaa”物件的地址返回來,賦給引用變數s,這樣s會指向String Pool中的這個“aaa”字串物件;
2.如果存在,則不建立任何物件,直接將String Pool中的這個“aaa”物件地址返回來,賦給s引用。
2)String s = new String("aaa");
1.首先在StringPool中查詢有沒有"aaa"這個字串物件,如果有,則不在String Pool中再去建立"aaa"這個物件,直接在堆中建立一個"aaa"字串物件,然後將堆中的這個"aaa"物件的地址返回來,賦給s引用,導致s指向了堆中建立的這個"aaa"字串物件;
2.如果沒有,則首先在String Pool中建立一個"aaa"物件,然後再去堆中建立一個"aaa"物件,然後將堆中的這個"aaa"物件的地址返回來,賦給s引用,導致s指向了堆中所建立的這個"aaa"物件。
15、Object類的公有方法
clone()(protected的)、toString()、equals(Object obj)、hashCode()、getClass()、finialize()(protected的)、notify()/notifyAll()、wait()/wait(long timeout)、wait(long timeout,intnaos)
16、try catchfinally
· 1.finally裡面的程式碼一定會執行的;
· 2.當try和catch中有return時,先執行return中的運算結果但是先不返回,然後儲存下來計算結果,接著執行finally,最後再返回return的值。
· 3.finally中最好不要有return,否則,直接返回,而先前的return中計算後儲存的值得不到返回。
17、面向物件的三大基本特徵
封裝、繼承和多型
(1)封裝
隱藏一切可以隱藏的訊息,只向外界提供最簡單的程式設計介面;類就是對資料和方法的封裝;方法就是對具體實現細節的封裝;
(2)繼承
從已有的類繼承得到繼承資訊,建立新類的過程,並無需重新編寫與原來的類相同的方法或成員變數情況下就可以對這些功能進行擴充套件。
(3)多型
允許父型別的引用指向子型別的物件。
實現方式:方法過載(編譯器繫結,前繫結)和方法重寫(執行期繫結,後繫結)
18、靜態類和非靜態類
(1)靜態類
靜態類中的欄位與方法都必須是static的,靜態類不需要例項化就可以使用;
(2)非靜態類
非靜態類中可以有static的欄位與方法,也可以由非static的欄位與方法,訪問static的欄位與方法不需要例項化,但是訪問非static的欄位與方法時需要例項化。
19、for和foreach迴圈效率:
for可以不逐個遍歷,如每隔一個遍歷;也可以從前向後遍歷,從後向前遍歷;有條件判斷,使用已知次數的迴圈遍歷;
foreach只能逐個遍歷;只能從前向後遍歷;沒有執行條件限制,不能向迭代變數賦值;適合集合的遍歷;
如果遍歷集合或陣列時,如果需要訪問集合或陣列的下標,則最好使用舊式的方式來實現迴圈或遍歷,而不要使用增強的for迴圈,因為它丟失了下標資訊。
20、JNIjava native interface
設計作用:主要實現和其他語言的通訊,c和c++。標準的Java類庫中可能不支援程式所需的特性,或已經有了一個用其他語言編寫的庫或程式,但是現在希望用到Java程式中,則需要使用JNI。
使用場景:JDBC實現連線資料庫,Thread.sleep()方法。
21、pach和classpath的區別
path是windows的環境屬性,用於指定可執行命令的路徑;classpath是指在Java程式執行的時候,用於指定類的載入路徑。
22、final、finally、finalize的區別
final是Java的一個關鍵字,用於定義不能被繼承的類,不能被覆寫的方法,不能修改的常量。
finally是Java的一個關鍵字,是異常處理操作的統一出口。
finalize是Object類中所提供的一個方法,用於在物件回收之前進行收尾操作。
final
修飾符(關鍵字)如果一個類被宣告為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個類不能既被宣告為 abstract的,又被宣告為final的。將變數或方法宣告為final,可以保證它們在使用中不被改變。被宣告為final的變數必須在宣告時給定初值,而在以後的引用中只能讀取,不可修改。被宣告為final的方法不可以重寫(父子類繼承關係),但是可以過載(同一個類中)。
finally
異常處理時提供 finally 塊來執行任何清除操作。如果丟擲一個異常,那麼相匹配的 catch 子句就會執行,然後控制就會進入 finally 塊(如果有的話)。一般異常處理塊需要。
finalize
· 方法名,Java技術允許使用 finalize() 方法在垃圾收集器將物件從記憶體中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在確定這個物件沒有被引用時對這個物件呼叫的。它是在 Object 類中定義的,因此所有的類都繼承了它。子類覆蓋 finalize() 方法以整理系統資源或者執行其他清理工作。finalize() 方法是在垃圾收集器刪除物件之前對這個物件呼叫的。
· Java中所有類都從Object類中繼承finalize()方法。
· 當垃圾回收器(garbage colector)決定回收某物件時,就會執行該物件的finalize()方法。值得C++程式設計師注意的是,finalize()方法並不能等同與解構函式。Java中是沒有解構函式的。C++的解構函式是在物件消亡時執行的。由於C++沒有垃圾回收,物件空間手動回收,所以一旦物件用不到時,程式設計師就應當把它delete()掉。所以解構函式中經常做一些檔案儲存之類的收尾工作。但是在Java中很不幸,如果記憶體總是充足的,那麼垃圾回收可能永遠不會進行,也就是說filalize()可能永遠不被執行,顯然指望它做收尾工作是靠不住的。
· 那麼finalize()究竟是做什麼的呢?它最主要的用途是回收特殊渠道申請的記憶體。Java程式有垃圾回收器,所以一般情況下記憶體問題不用程式設計師操心。但有一種JNI(JavaNative Interface)呼叫non-Java程式(C或C++),finalize()的工作就是回收這部分的記憶體。
23、Java實現可移植性的原理
Java程式最終通過位元組碼檔案執行,執行的時候位元組碼需要JVM支援,但是在不同的作業系統中有不同的JVM,程式不用關心作業系統,只關心JVM,只要JVM不改變,程式可以在作業系統間任意移植。
24、Java的資料型別劃分
1)當若干個變數參與運算時,結果型別取決於這些變數中表示範圍最大的那個變數型別,如有整型int,有雙精度浮點型double,有短整型short,則最後的結果型別為double。
2)取模
資料型別 |
預設值 |
基本資料型別 |
|
數值型:整型:byte、short、int、long 浮點型:float、double |
0 |
字元型:char |
'\u0000' |
布林型:boolean |
false |
引用資料型別 |
|
陣列、類、介面 |
null |
25、&和&&、|和||的區別
· &(普通與)和|(普通或)是指所有條件都需要判斷;
· &&稱為邏輯與(短路與)是如果前面的條件不滿足false,則後面的不再進行判斷;||稱為邏輯或(短路或)如果前面的條件滿足true則後面的不再判斷;
· 在開發之中為了效能的提高,不需要所有條件進行判斷,所以使用短路與和短路或操作;
· &和|除了用於邏輯運算以外,還進行位運算的操作。
·
26、String物件的兩種例項化方式的區別
1.首先String物件的例項化有兩種:直接賦值和構造方法完成。
2.直接賦值:在常量池中建立該字串;
3.構造方法:先判斷在字串常量池中是否包含該字串,若包含該字串,則在堆中直接建立這個字串物件並返回該物件引用;若不包含,則先在堆上建立,然後在字串常量池中也建立,最後把返回堆上物件引用。
27、throw和throws區別
1.throw是語句丟擲一個異常。
語法:throw (異常物件);
throw e;
throws是方法可能丟擲異常的宣告。(用在宣告方法時,表示該方法可能要丟擲異常)
語法:[(修飾符)](返回值型別)(方法名)([引數列表])[throws(異常類)]{......}
public void doA(int a) throws Exception1,Exception3{......}
2.throw語句用在方法體內,表示丟擲異常,由方法體內的語句處理;throws語句用在方法聲明後面,表示再丟擲異常,由該方法的呼叫者來處理。
3.throw是具體向外拋異常的動作,已經發生異常,被捕獲到,要丟擲該異常,所以它是丟擲一個異常例項;throws主要是宣告這個方法會丟擲這種型別的異常,使它的呼叫者知道要捕獲這個異常,傾向於發生,但不一定發生。
28、列舉(Enums)
1.當使用“enum”定義列舉型別時,實質上是繼承java.lang.Enum型別;
2.每個列舉的成員其實就是定義的列舉型別的一個例項,他們都被預設為final,所以無法改變他們,也是static成員,所以可以通過型別名稱直接使用它們,且他們是公開的public的。
3.特性:final static public的。
4.在編譯時期就確定該列舉型別具有幾個例項,分別是什麼。在執行期間我們無法再使用該列舉型別建立新的例項,這些例項在編譯期間就已經完全確定下來。
29、遞迴
Recursion,就是方法呼叫自身,對於遞迴來說,一定有一個出口,讓遞迴結束,只有這樣才能保證不出現死迴圈。
30、可變引數
1.可變引數本質上就是一個數組,對於某個聲明瞭可變引數的方法來說,既可以傳遞離散的值,也可以傳遞陣列物件。
2.如果將方法中的引數定義為陣列,則只能傳遞陣列物件而不能傳遞離散的值。
3.可變引數必須要作為方法引數的最後一個引數,即一個方法不可能具有兩個或以上的可變引數。
31、靜態匯入
1.使用靜態匯入import static時,要一直匯入到類中的靜態成員變數或靜態方法。
如:
import static com.ljy.exercise.Person.age;
import staticcom.ljy.exercise.Person.printlnPersonName;
32、集合的元素
集合中存放的依然是物件的引用,而不是物件本身。
集合無法放置原生資料型別,所以需要使用原生資料型別的包裝類將其轉換為真正的型別。
33、一個類不能既是final的,又是abstract的
因為abstract的主要目的是定義一種約束:讓子類去實現這種約定,而final表示該類不能被繼承,這樣abstract希望該類可以被繼承與之矛盾。
34、靜態方法
1.static修飾方法,可以通過類名.靜態方法名的方式訪問,靜態方法只能繼承,不能重寫(Override)。
2.不能在靜態方法中使用this關鍵字;
3.靜態的只能訪問靜態的(因為靜態的程式碼塊在構造方法之前就已經開始初始化,而此時非靜態的還未開始初始化,如果靜態能訪問非靜態的就會出現發生錯誤),非靜態的可以訪問一切。
35、區域性變數和成員變數
區域性變數使用前必須宣告並賦初值;成員變數使用前必須要宣告,但可以不賦初值。
36、引用型別
reference type,引用型別用在物件上,一個物件可以被多個引用所指向,但同一時刻,每個引用只能指向唯一的物件,如果一個物件被多個引用所指向,那麼無論哪個引用對物件的屬性進行修改,都會反映到其他的引用中去。
37、方法和類的定義
(1)類的定義
修飾符 class 類的名字{
//類的內容(包含了屬性與方法)
}
(2)方法的定義
修飾符 返回型別 方法名稱([引數1,引數2,引數3...]){
//方法體
}
1)方法定義不能巢狀,一個方法中不能定義另一個方法,方法只能定義在類中。
2)形式引數:方法定義時的引數。
3)實際引數:方法呼叫時所賦予的具體值。
38、break和continue
1)break語句:經常用在迴圈語句中,用於跳出整個迴圈,執行迴圈後面的程式碼。(如果雙重迴圈,在內迴圈中使用break,跳出內迴圈)
2)continue語句:經常用在迴圈語句中,用於跳出本次迴圈,開始下一次迴圈的執行。
3)break與continue可以搭配標籤使用。
39、switch語句
40、變數的自增與自減運算
1)關於int b = a++,作用:先將a賦給b,然後再讓a自增1。
2)關於int b = ++a,作用:先將a的值自增1,然後再將自增後的a賦給b。
總結:哪個在前,就先做哪一步。
41、Arrays.sort底層實現
基本型別:採用調優的快速排序:當待排序元素小於7個的時候,採用插入排序。
物件型別:採用改進的歸併排序;
42、什麼是跨平臺性?原理是什麼?
1)跨平臺性:通過Java語言編寫的應用程式在不同的系統平臺上都可以執行。
2)原理:只要在需要執行Java應用程式的作業系統上,先安裝一個Java虛擬機器(JVM Java Virtual Machine)即可,由JVM來負責Java程式在該系統中的執行。因為有了JVM,所以同一個Java程式在三個不同的作業系統中都可以執行,這樣實現Java程式的跨平臺性,也稱為Java具有良好的可移植性。
43、JRE與JDK
1)JRE:Java Runtime Environment,Java執行環境,包括JVM和Java程式所需的核心類庫等。
2)JDK:Java Development Kit,Java開發工具包,JDK是提供給Java開發人員使用的,其中包含了Java的開發工具(編譯工具javac.exe和打包工具jar.exe等),也包括了JRE。所以安裝JDK,就不用單獨安裝JRE。
3)如果是命令列模式:編譯器javac進行編譯:javac 原始檔名.java——編譯通過後,對class位元組碼檔案執行:java 類名
4)執行與工作原理
5)path環境變數配置的作用:程式開發過程中,不能將原始碼寫入JDK的安裝目錄,因此需要將源程式儲存到任意位置的指定目錄(英文目錄),所以需要使javac指令在任意目錄下可以執行。通過配置path環境變數,將javac指令所在目錄及JDK安裝目錄下的bin目錄配置到path變數下,即可使javac指令在任意目錄下執行。
6)使classpath目錄中的.class檔案可以在任意目錄執行。
7)path和classpath的區別:path環境變數裡面記錄的是可執行性檔案,如.exe檔案,對可執行檔案先在當前路徑去找,如果沒找到就去path環境變數中配置的路徑去找。而classpath環境變數裡記錄的是java類的執行檔案所在的目錄。
44、反射
(1)反射機制
1)定義:JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼檔案對應的Class型別的物件.
2)獲取Class物件的三種方式
第一種方式:
Person p = new Person();
Class c = p.getClass();
第二種方式:任意類都具備一個class靜態屬性
Class c2 = Person.class;
第三種方式:將類名作為字串傳遞給Class類的靜態方法forName
Class c3 =Class.forName("Person");
(2)動態代理
1)在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler介面,通過使用這個類和介面就可以生成動態代理物件。JDK提供的代理只能針對介面做代理。我們有更強大的代理cglib
2)Proxy類中的方法建立動態代理類物件
public static Object newProxyInstance(ClassLoaderloader,Class<?>[] interfaces,InvocationHandler h)
最終會呼叫InvocationHandler的方法
Proxy類中建立動態代理物件的方法的三個引數;
· ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入;
· Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它,那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了;
· InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上。
3)InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)
每一個動態代理類都必須要實現InvocationHandler這個介面,並且每個代理類的例項都關聯到了一個handler,當我們通過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉發為由InvocationHandler這個介面的invoke 方法來進行呼叫。
InvocationHandler介面中invoke方法的三個引數:
· proxy:代表動態代理物件
· method:代表正在執行的方法
· args:代表呼叫目標方法時傳入的實參
4)Proxy.newProxyInstance
建立的代理物件是在jvm執行時動態生成的一個物件,它並不是我們的InvocationHandler型別,也不是我們定義的那組介面的型別,而是在執行是動態生成的一個物件,並且命名方式都是這樣的形式,以$開頭,proxy為中,最後一個數字表示物件的標號。System.out.println(u.getClass().getName());
45、異常
(1)異常介紹
1)編譯時異常
除了RuntimeException及其子類,Exception中所有的子類都是,這種異常必須要處理,要不編譯通不過
2)執行時異常
RuntimeException及其子類都是,這種異常不用處理,編譯會通過,不過這樣的程式會有安全隱患,遇到這種異常是需要改程式碼的
3)嚴重錯誤問題
用Error進行描述,這個問題發生後,一般不編寫針對程式碼進行處理,而是要對程式進行修正.通常都是由虛擬機器丟擲的問題
(2)Throwable中方法
getMessage()
獲取異常資訊,返回字串。
toString()
獲取異常類名和異常資訊,返回字串。
printStackTrace()
獲取異常類名和異常資訊,以及異常出現在程式中的位置。返回值void。
printStackTrace(PrintStream s)
通常用該方法將異常內容儲存在日誌檔案中,以便查閱。
(3)throws和throw的區別
1)throws
· 用在方法聲明後面,跟的是異常類名;
· 可以跟多個異常類名,用逗號隔開;
· 表示丟擲異常,由該方法的呼叫者來處理;
· throws表示出現異常的一種可能性,並不一定會發生這些異常。
2)throw
· 用在方法體內,跟的是異常物件名;
· 只能丟擲一個異常物件名;
· 表示丟擲異常,由方法體內的語句處理;
· throw則是丟擲了異常,執行throw則一定丟擲了某種異常 。
(4)try和throws區別
如果該功能內部可以將問題處理,用try,如果處理不了,則交由呼叫者處理,用throws進行丟擲異常。
區別:後序程式需要執行,則用try;後序程式不需要繼續執行,則用throws;
46、面向物件:
1)思想:是站在現實世界的角度去抽象和解決問題,把資料和行為都看作是物件的一部分,可以讓程式設計師以符合現實世界的思維方式來編寫和組織程式。
2)原則:
單一職責:一個類只做它該做的事(高內聚);
開放封閉:對擴充套件開放,對修改關閉;
里氏替換:任何時候都可用子型別替換父型別;
依賴倒置:面向介面程式設計(抽象型別可被任何一個子類所替代);
合成聚和複用:優先使用聚合或合成關係複用程式碼;
介面隔離:一個介面只應描述一種能力,介面應該是高內聚的(小而專一);
迪米特法則:最少知識原則,一個物件應對其他物件儘可能少的瞭解。
47、陣列和容器的區別
1)效率:陣列是一種效率最高的儲存和隨機訪問物件引用序列的方式,陣列就是一個簡單的線性序列,這使得元素訪問非常快速,可以通過整型索引值訪問元素;
2)大小:陣列物件的大小被固定,並且在其生命週期中不可改變;容器如ArrayList可以動態擴容,通過建立一個新例項,然後把舊例項中所有的引用移到新例項中,從而實現更多空間的自動分配;
3)資料型別:陣列可以持有基本型別,陣列持有某種具體型別,通過編譯器檢查,防止插入錯誤型別和抽取不當型別;容器通過泛型,指定並檢查它們所持有物件的型別,並且有了自動包裝機制,好像是能夠持有基本資料型別。
注意:陣列的比較是是通過equals()方法,用來比較整個陣列,同樣,此方法針對所有基類型別與Object都做了過載,陣列相等的條件是元素個數必須相等,並且對應位置的元素也相等,這可以通過對每一個元素使用equals()作比較判斷。
48、Arrays的方法
java.util類庫中的Arrays類,有一套用於陣列的static實用方法。有6個基本方法+1個asList()方法。
1)Arrays.asList():接收任意的序列或陣列作為其引數,並將其轉變為List容器;
2)equals():用於比較兩個陣列是否相等(deepEquals()用於多維陣列);
3)fill():是用同一個數值進行填充陣列的各個位置,針對物件而言,就是複製同一個引用進行填充;
4)sort():用於對陣列排序;(對於數值排序,小於8的使用插入排序,大於等於8個元素使用快速排序;對於物件排序,使用合併排序);
5)binarySearch():用於在已經排序的陣列中查詢元素;
6)toString():差生陣列的String表示;
7)hashCode():產生陣列的雜湊碼;
50、equals()方法的5個條件
1)自反性。對任意x,x.equals(x)一定返回true;
2)對稱性。對任意x和y,如果y.equals(x)返回true,則x.equals(y)也返回true;
3)傳遞性。對任意x、y、z,如果有x.equals(y)返回true,y.equals(z)返回true,則x.equals(z)一定返回true;
4)一致性。對任意x和y,如果物件中用於等價比較的資訊沒有改變,那麼無論呼叫x.equals(y)多少次,返回的結果應該保持一致,要麼一直是true,要麼一直是false;
5)對任何不是null的x,x.equals(null)一定返回false。
預設的Object.equals()只是比較物件的地址。
51、public staticvoid main(String[] args)方法的必要性
1)是Java程式的入口方法,JVM在執行程式時,會首先查詢main()方法;
2)public是許可權修飾符,表明任何類或物件都可以訪問這個方法;
3)static表明main()方法是一個靜態方法,即方法中的程式碼是儲存在靜態儲存區的,只要類載入後,就可以使用該方法而不需要通過例項化物件來訪問,可以直接通過類名。
4)main()不能用abstract修飾,但可以用final和synchronized修飾,且public與static的順序可以顛倒。
52、Java程式初始化的順序
(1)遵循3個原則:
1)靜態物件(變數)優先於非靜態物件(變數)初始化;
2)父類優先於子類進行初始化;
3)按照成員變數的定義順序進行初始化,
(2)初始化順序
父類靜態變數、父類靜態程式碼塊、子類靜態變數、子類靜態程式碼塊、父類非靜態變數、父類非靜態程式碼塊、父類建構函式、子類非靜態變數、子類非靜態程式碼塊、子類建構函式
53、Java變數型別
(1)變數型別
靜態變數、成員變數、區域性變數
(2)變數型別的範圍
1)靜態變數:被static修飾的成員變數稱為靜態變數,靜態變數不依賴於特定的例項,而是被所有例項所共享,只要一個類被載入,JVM就會給類的靜態變數分配儲存空間,可以通過類名和例項變數名訪問靜態變數。
2)成員變數:作用範圍與類的例項化物件的作用範圍相同,當類被例項化時,成員變數就會在記憶體中分配空間並初始化,直到這個被例項化物件的生命週期結束時,成員變數的宣告週期才結束。
3)區域性變數:作用域與可見性為它所在的花括號內。
54、ArrayList和LinkedList
1)實現介面:都實現了List介面;
2)底層:ArrayList底層是由陣列支援;LinkedList底層是由雙向連結串列實現;
3)記憶體:ArrayList比LinkedList申請少的記憶體,因為LinkedList中的每個物件包含資料的同時還包含指向連結串列中前一個與後一個元素的引用;
4)操作:ArrayList不適合插入或刪除,需要移動後面的元素,但適合快速訪問;而LinkedList適合插入和刪除,因為開銷是固定的;
55、快速報錯機制
1)出現原因:在迭代遍歷某個容器的過程中,另一個程序介入其中,並且插入、刪除或修改此容器內的某個物件,則會出現問題:也許迭代過程已經處理過容器中得到該元素了,也許還沒處理,也許在呼叫size()之後容器的尺寸收縮了。
2)快速報錯(fail-fast)機制:探查容器上除了你的程序所進行的操作以外的所有變化,一旦發現其他程序修改容器,立即丟擲ConcurrentModificationException異常,即不是使用複雜的演算法在事後來檢查問題。