2016-10-19 html
初級問題,可是仍是加入了筆記,由於得滿分不容易。 &和&&均可以用做邏輯與的運算(兩邊是boolean類型),全真則真,一假則假。 &&還具備短路的功能,即第一個表達式爲false,則再也不計算第二個表達式。例如, if(str != null&& !str.equals(「「)) 當str爲null時,後面的表達式不會執行,不會出現NullPointerException,若是將&&改成&,則會拋出NullPointerException異常。 &還能夠用做位運算符,當&操做符兩邊的表達式不是boolean類型時,&表示按位與操做,咱們一般使用0x0f來與一個整數進行&運算,來獲取該整數的最低4個bit位,例如,0x31 & 0x0f的結果爲0x01。備註:這道題先說二者的共同點,再說出&&和&的特殊之處,並列舉一些經典的例子來代表本身理解透徹深刻。
前半部分是老生常談的。你們都知道:final 用於聲明類的屬性,方法和類自己,分別表示屬性自己不可變,方法不可覆蓋,類不可繼承。且內部類要訪問局部變量,局部變量必須定義成final類型,由於常量的做用範圍變大,內部類才能夠訪問到。java
本題問的主要是後者,涉及到了Java內存模型和重排序的含義。更加詳細參考下面文章c++
簡單說就是構造器內對一個final域的寫,與隨後把這個被構造對象的引用賦值給一個引用變量,這兩個操做之間不能重排序,即若是final域在構造器內初始化,那麼必定是先初始化完畢,才能使用對象。不會逃逸。程序員
初次讀一個包含final域的對象的引用,與隨後初次讀這個final域,這兩個操做之間不能重排序,讀final域的重排序規則能夠確保:在讀一個對象的final域以前,必定會先讀包含這個final域的對象的引用。面試
在構造器內對一個final引用的對象的成員域的寫入,與隨後在構造函數外把這個被構造對象的引用賦值給一個引用變量,這兩個操做之間不能重排序。算法
不能執行,編譯有錯, final修飾的變量是常量,使用以前必須進行初始化,能夠顯示初始化,也能夠經過構造方法或者初始化塊進行初始化,若是不初始化編譯會報錯。
finalize是Object類的一個保護方法 protected void finalize() throws Throwable { } 當垃圾回收器肯定不存在對該對象的更多引用時,對象的垃圾回收器自動調用此方法,程序員能夠覆蓋此方法提供垃圾收集時的其餘資源回收,例如關閉文件等。而記得《Java編程思想》說:「若是須要進行清理,最好是編寫你本身的清理方法,但不要用finalize」,其實你寫了或者你用了「本身的清理方法」,只是沒感受到。好比I/O的close方法就是,如今的問題是爲何釋放資源的代碼不直接寫在finalize裏面。由於手動調用它,JVM不保證此方法總被及時調用或者根本不保證會被調用,這都不能保證,要你何用。並且它的調用對性能影響很大。具體來講就是: java的GC只負責內存的清理,全部其它資源的清理必須由程序員手工完成。要否則會引發資源泄露,有可能致使程序崩潰。 而finalize()是Object的protected方法,那麼子類理論上能夠覆蓋該方法,且GC會在回收對象以前調用對象的該方法。可是finalize()與C++中的析構函數不是對應的。C++中的析構函數調用的時機是肯定的(對象離開做用域或delete掉),但Java中的finalize的調用具備不肯定性,不建議用finalize方法完成「非內存資源」的清理工做。Java語言規範並不保證finalize方法會被及時地執行、並且根本不會保證它們會被執行,finalize方法可能會帶來性能問題。由於JVM一般在單獨的低優先級線程中完成finalize的執行。 在Java虛擬機的垃圾回收器看來,堆區中的每一個對象均可能處於如下三個狀態之一。 可觸及狀態:當一個對象(假定爲Sample對象)被建立後,只要程序中還有引用變量引用它,那麼它就始終處於可觸及狀態。 可復活狀態:當程序再也不有任何引用變量引用Sample對象時,它就進入可復活狀態。在這個狀態中,垃圾回收器會準備釋放它佔用的內存,在釋放以前,會調用它及其餘處於可復活狀態的對象的finalize()方法,這些finalize()方法有可能使Sample 對象從新轉到可觸及狀態。 不可觸及狀態:當Java虛擬機執行完全部可復活對象的finalize()方法後,假如這些方法都沒有使Sample對象轉到可觸及狀態,那麼Sample對象就進入不可觸及狀態。只有當對象處於不可觸及狀態時,垃圾回收器纔會真正回收它佔用的內存。 一個對象開始是可觸及態的,當對象到GC Root沒有任何引用鏈接相連。那麼就證實這個對象目前是不可用的,這時這個對象就被判死緩了(從可觸及到可復活),可是想要真正的對這個對象判死刑,這個對象還至少經歷兩次判決。第一次是判斷是否有必要對這個對象執行finalize()方法,若是當前對象沒有覆蓋finalize()方法,或finalize()方法已經被調用過了(最多調用一次),那麼當前對象就不會調用finalize()方法了,即對象成功的逃脫了一審判決。若是對象有必要執行finalize()方法,那麼這個對象會被放入一個叫作F-Queue的隊列中,這也就意味着在一審中這個對象已經被判死刑了,可是還沒執行。而在JVM中,會有一個叫作Finalizer的低優先級線程去觸發可復活對象的finalize()方法,finalize()方法是對象逃脫死刑的最後一次機會,若是在finalize()的過程當中成功的與GC Root相連,則對象成功的逃脫死刑(進入可觸及態)。不然對象就會被第二次標記(進入不可觸及態),被第二次標記的對象就會被送上刑場槍斃。又想起一個問題,即便在程序裏,不顯式指定對象指向null,JVM也會找機會解決它。 分析說明:finalize方法至多由GC執行一次, 儘管finalize()方法是保證在回收內存空間以前執行的,可是對具體的執行時間和執行順序是沒有任何保證的。多個實例之間的finalize()執行順序是不能提早預知的,甚至有可能它們是並行執行的。程序不該該預先假設實例執行finalize()的方法,也不該該使用finalize()方法來回收資源。
這個題很重要,糾正我一個誤區:Java只有值傳遞。java中沒有顯式的指針。沒有相似c和c++的那種地址,引用傳遞。對於java值傳遞,形參str指向了實參str指向的對象good字符串,可是change方法內部,形參str指向從新開闢一個空間存儲的test ok,change執行完畢,實參str的指向對象並無被修改。故不起做用。而ch是數組,值傳遞的是對象的引用,值發生了改變,打印good and gbc
重要:別混淆:Java傳參方式只有一種:按值傳遞
Java一直是隻有值傳遞。不幸的是,制定規則的人決定把Java裏的指針的東西叫作引用,所以初學者老是被搞暈。其實這些引用也是經過值傳遞的。即Java中傳遞任何東西都是傳值。若是傳入方法的是基本類型的東西,你就獲得此基本類型的一份拷貝。若是是傳遞引用,就獲得引用的拷貝。 通常來講,對於基本類型的傳遞,咱們很容易理解,而對於對象,總讓人感受是按引用傳遞。
1true 編程
取得類的全部方法的對象。 public Method[] getDeclaredMethods() //返回類或接口聲明的全部方法,包括public, protected, default (package) 訪問和private方法的Method對象,但不包括繼承的方法。固然也包括它所實現接口的方法。 public Method[] getMethods() // 返回某個類的全部public方法,包括其繼承類的公用方法,固然也包括它所實現接口的方法 Java反射 能夠理解爲在運行時期獲取對象類型信息的操做,傳統的編程方法要求程序員在編譯階段決定使用的類型,可是在反射的幫助下,編程人員能夠動態獲取這些信息,從而編寫更加具備可移植性的代碼。嚴格地說,反射並不是java語言的特性,由於任何一種語言均可以實現反射機制,可是若是編程語言自己支持反射,那麼反射的實現就會方便不少。 得到類型類;Java中一切都是對象,咱們通常所使用的對象都直接或間接繼承自Object類。Object類中包含一個方法名叫getClass(final修飾),利用這個方法就能夠得到一個實例的類型類。類型類指的是表明一個類型的類,由於一切皆是對象,類型也不例外,在Java使用類型類來表示一個類型。全部的類型類都是Class類的實例。例: A a = new A(); if(a.getClass()==A.class) System.out.println("equal"); else System.out.println("unequal"); 結果就是打印出 「equal」。對象a是A的一個實例,if中使用a.getClass()返回的結果正是A的類型類。在Java中表示一個特定類型的類型類能夠用「類型.class」的方式得到,由於a.getClass()得到是A的類型類,也就是A.class,所以上面的代碼執行的結果就是打印出 「equal」,特別注意的是,類型類是一一對應的,父類的類型類和子類的類型類是不一樣的,所以,假設A是B的子類,那麼以下的代碼將獲得 「unequal」的輸出: A a = new A(); if(a.getClass()==B.class) System.out.println("equal"); else System.out.println("unequal"); 所以,若是你知道一個實例,那麼你能夠經過實例的「getClass()」方法得到該對象的類型類,若是你知道一個類型,那麼你可使用「.class」的方法得到該類型的類型類。 小結: Class cl=A.class; // JVM將使用類A的類裝載器, 將類A裝入內存(前提是:類A尚未裝入內存),不對類A作類的初始化工做.返回類A的Class的對象(類型類,一切都是對象)。 Class cl=對象引用.getClass(); // 返回引用運行時真正所指的對象(由於:子對象的引用可能會賦給父對象的引用變量)所屬的類的Class的對象。 Class.forName(); // 返回的是一個類, .newInstance() 後才建立一個對象, Class.forName()的做用是要求JVM查找並加載指定的類 得到類型的信息 在得到類型類以後能夠調用其中的一些方法得到類型的信息,主要的方法有: getName():String:得到該類型的全稱名稱。 getSuperClass():Class:得到該類型的直接父類,若是該類型沒有直接父類,那麼返回null。 getInterfaces():Class[]:得到該類型實現的全部接口。 isArray():boolean:判斷該類型是不是數組。 isEnum():boolean:判斷該類型是不是枚舉類型。 isInterface():boolean:判斷該類型是不是接口。 isPrimitive():boolean:判斷該類型是不是基本類型,便是否是int,boolean,double等等。 isAssignableFrom(Class cls):boolean:判斷這個類型是不是類型cls的父(祖先)類或父(祖先)接口。 getComponentType():Class:若是該類型是一個數組,那麼返回該數組的組件類型。
Object的getClass做用是返回運行時的類的名字,可是SuperTest和Date的getClass都沒有被重寫,他們都是調用Object的getClass,而Object的getClass做用是返回運行時的類的名字。那麼此時這個運行時的類就是當前類,因此返回的是test.SuperTest,與Date類無關,要返回Date類的名字須要寫super.getClass().getSuperclass()。還有別忘了包名!
java的訪問權限有public、protected、private和default的,default不能修飾變量。native是方法修飾符。定義navtive方法時,並不提供實現體,由於其實現體是用非Java語言在外面實現的。native能夠和任何修飾符連用,abstract除外。由於native暗示這個方法有實現體,而abstract卻顯式指明瞭這個方法沒有實現體。
從c++/c的角度來看,數組的複製就是對某塊內存的複製,直接和內存打交道的是最快的,for循環的話,for是最慢的。雖然很靈活。 看System.arraycopy()源碼: public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length); 能夠看到是native方法:native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前文件,而是在用其餘語言(如C和C++)實現的文件中。 能夠將native方法比做Java程序同C程序的接口。效率最高。 C項寫法就錯了,copyOf不是System的方法,而是Arrays的靜態方法,下面是源碼,能夠看到本質上是調用的本地方法arraycopy,那麼其效率必然是比不上 arraycopy的。 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } clone的話,屬於Object類的保護本地方法,返回的是Object,須要強制轉換。 通常用clone效率是比較差的。 protected native Object clone() throws CloneNotSupportedException;
main()方法必定是靜態的。若是main()容許是非靜態的,那麼在調用main方法時,JVM就得實例化它的類。在實例化時,得調用類的構造函數。必然要找該類的入口,而入口是非靜態的方法,矛盾了。main()方法必須聲明爲靜態的,這樣JVM才能夠調用main()方法而無需實例化它的類。若是從main()方法去掉「static」這個聲明,雖然編譯依然能夠成功,但在運行時會致使程序失敗。 對於後個問題,固然能夠重載main()方法。一個Java類能夠有任意數量的main()方法。爲了運行java類,類的main()方法應該有例如「public static void main(String[] args)」的聲明。若是對此聲明作任何修改,編譯也是能夠成功的。可是,運行不了Java程序。會獲得運行時錯誤,由於找不到main方法。
不能,main方法必須public。不能定義main()方法爲private和protected,也不能不用訪問修飾符。這是爲了能讓JVM訪問main()方法。若是你不定義main()方法爲public,雖然編譯也會成功,但你會獲得運行時錯誤,由於找不到main方法。
不能,由於main方法是靜態方法,而在Java中靜態方法在編譯時會結合在一塊兒,因此你在Java中不能覆蓋靜態方法。
main方法能夠在Java中同步,synchronized修飾符容許用於main方法的聲明中,這樣就能夠在Java中同步main方法了。
java.lang包在使用的時候無需顯示導入,編譯時由編譯器自動導入。提供java編成語言的程序設計的基礎類.Object類是類層次結構的根,Java中全部的類從根本上都繼承自這個類。Object類是Java中惟一沒有父類的類。其餘全部的類,包括標準容器類,好比數組,都繼承Object類中的方法 補充;Object類源代碼分析 package java.lang; public class Object { /* 一個私有靜態的native方法,具體是用C(C++)在DLL Dynamic Link Library 中實現的,而後經過JNI調用。*/ private static native void registerNatives(); /* 對象初始化時自動調用此方法*/ static { registerNatives(); } /* 返回此 Object 的運行時類。*/ public final native Class<?> getClass(); /* hashCode 的常規協定是: 1.在 Java 應用程序執行期間,在對同一對象屢次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。從某一應用程序的一次執行到同一應用程序的另外一次執行,該整數無需保持一致。 2.若是根據 equals() 方法,兩個對象是相等的,那麼對這兩個對象中的每一個對象調用 hashCode 方法都必須生成相同的整數結果。3.若是根據 equals() 方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不要求必定生成不一樣的整數結果。可是,程序員應該意識到,爲不相等的對象生成不一樣整數結果能夠提升哈希表的性能。*/ public native int hashCode(); //Object類的equals()方法判斷調用equals()方法的引用於傳進來的引用是否一致,即兩個引用是否指向同一個對象。Object類中的equals()方法等價於==。 //只有當繼承Object的類覆寫(override)equals()方法以後,繼承類實現equals(),才能夠說equals()方法與==的不一樣。 //equals()方法須要具備以下特色: //自反性(reflexive):任何非空引用x.equals(x)返回爲true。 //對稱性(symmetric)任何非空引用x和y,x.equals(y)返回true當且僅當y.equals(x)返回true。 //傳遞性(transitive):任何非空引用x和y,若是x.equals(y)返回true,而且y.equals(z)返回true,那麼x.equals(z)返回true。 //一致性(consistent):兩個非空引用x和y,x.equals(y)的屢次調用應該保持一致的結果,(前提條件是在屢次比較之間沒有修改x和y用於比較的相關信息)。 //約定:對於任何非空引用x,x.equals(null)應該返回爲false。而且覆寫equals()方法時,應該同時覆寫hashCode()方法,反之亦然。 public boolean equals(Object obj) { return (this == obj); } /*本地clone方法,用於對象的複製。(想到了一個面試題:Java生成對象有幾種方式?)任何類在實例上調用clone(),他將實現cloneable接口重寫clone方法建立副本。有這個方法的類必須實現java.lang.Cloneable接口,不然會拋出CloneNotSupportedException異常。Cloneable接口中不包含任何方法,因此實現它時只要在類聲明中加上implements語句便可。 第二個比較特殊的地方在於這個方法是protected修飾的,覆寫clone()方法的時候須要寫成public,才能讓類外部的代碼調用。 protected native Object clone() throws CloneNotSupportedException; /*返回該對象的字符串表示。打印引用會自動調用對象的toString()方法,打印出引用所指的對象的toString()方法的返回值,由於每一個類都直接或間接地繼承自Object,所以每一個類都有toString()方法。 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } public final native void notify(); public final native void notifyAll(); /*在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法前,致使當前線程等待。換句話說,此方法的行爲就好像它僅執行 wait(0) 調用同樣。當前線程必須擁有此對象監視器。該線程發佈對此監視器的全部權並等待,直到其餘線程經過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。而後該線程將等到從新得到對監視器的全部權後才能繼續執行。*/ public final void wait() throws InterruptedException { wait(0); } /*在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量前,致使當前線程等待。*/ public final native void wait(long timeout) throws InterruptedException; /* 在其餘線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其餘某個線程中斷當前線程,或者已超過某個實際時間量前,致使當前線程等待。*/ public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException( "nanosecond timeout value out of range"); } if (nanos >= 500000 || (nanos != 0 && timeout == 0)) { timeout++; } wait(timeout); } /*當垃圾回收器肯定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。 protected void finalize() throws Throwable { } }
枚舉類全部的枚舉值都是類靜態常量,在初始化時會對全部的枚舉值對象進行第一次初始化。枚舉類在後臺實現時,其實是轉化爲一個繼承了java.lang.Enum類的實體類,原先的枚舉類型變成對應的實體類型,上例中AccountType變成了個class AccountType,而且會生成一個新的構造函數,若原來有構造函數,則在此基礎上添加兩個參數,生成新的構造函數,新構造器會包含已有的構造器的代碼,並且在這個類中,還會添加若干(本例子是3個字段)靜態final字段來表明具體的枚舉類型。最後並且還會添加一段static代碼段初始化他們。在初始化過程當中new AccountType構造函數被調用了三次,因此Enum中定義的構造函數中的打印代碼被執行了3遍。或者簡單的說private類內可見,類外不可見,枚舉類有三個實例,故調用三次構造方法,打印三次It is a account type,而後main方法裏打印一次FIXED。
java 中的instanceof 運算符是用來在運行時指出對象是不是特定類的一個實例。instanceof經過返回一個布爾值來指出這個對象是不是這個特定類或者是它的子類的一個實例。 用法: result = object instanceof class 參數: Result:布爾類型。 Object:必選項。任意對象表達式。 Class:必選項。任意已定義的對象類。 說明:若是 object 是 class 的一個實例,則 instanceof 運算符返回 true。若是 object 不是指定類的一個實例,或者 object 是 null,則返回 false。 至於具體實現原理,簡單說說:JVM有一條名爲 instanceof 的指令,而Java源碼編譯到Class文件時會把Java語言中的 instanceof 運算符映射到JVM的 instanceof 指令上。
參考:Java instanceof 關鍵字是如何實現的? 數組
super(), this() 都得放在構造函數第一行,確定不能放在一塊兒。編程語言
super表明父類對應的對象,因此用super訪問在子類中沒法直接使用的父類成員和方法,若是在子類中對從父類繼承來的成員變量進行從新定義,即出現了子類變量對父類變量的隱藏,不是說的private成員。ide
public class Outter{ public class Inner{ } } 內部類就不須要與文件名相同
形式參數就是函數定義時設定的參數。例如函數頭 int min(int x,int y,int z) 中 x,y,z 就是形參。 實際參數是調用函數時所使用的實際的參數。 形參能夠是對象,是對象的時候傳遞引用.形式參數只能用final修飾符,其它任何修飾符都會引發編譯器錯誤 。可是用這個修飾符也有必定的限制,就是在方法中不能對參數作任何修改。 不過通常狀況下,一個方法的形參不用final修飾。只有在特殊狀況下,那就是:方法內部類。 一個方法內的內部類若是使用了這個方法的參數或者局部變量的話,這個參數或局部變量應該是final。 形式參數可被視爲local variable。形參和局部變量同樣都不能離開方法。都只有在方法內纔會發生做用,也只有在方法中使用,不會在方法外可見。
a選項 -d便可設置系統屬性 c選項 一次編譯多個java文件用javac *.java. 便可編譯當前目錄下的全部java文件 d選項 -s指定存放生成的源文件的位置