能夠有多個類,但只能有一個public的類,而且public的類名必須與文件名相一致。java
java中的保留字,如今沒有在java中使用。web
&和&&均可以用做邏輯與的運算符,表示邏輯與(and),當運算符兩邊的表達式的結果都爲true時,整個運算結果才爲true,不然,只要有一方爲false,則結果爲false。面試
&&還具備短路的功能,即若是第一個表達式爲false,則再也不計算第二個表達式,例如,對於if(str!= null&& !str.equals(s))表達式,當str爲null時,後面的表達式不會執行,因此不會出現NullPointerException若是將&&改成&,則會拋出NullPointerException異常。If(x==33 &++y>0) y會增加,If(x==33 && ++y>0)不會增加算法
&還能夠用做位運算符,當&操做符兩邊的表達式不是boolean類型時,&表示按位與操做,咱們一般使用0x0f來與一個整數進行&運算,來獲取該整數的最低4個bit位,例如,0x31 & 0x0f的結果爲0x01。編程
在Java中,要想跳出多重循環,能夠在外面的循環語句前定義一個標號,而後在裏層循環體的代碼中使用帶有標號的break語句,便可跳出外層循環。windows
例如:api
for(int i=0;i<10;i++){
for(intj=0;j<10;j++){
System.out.println(「i=」 + i + 「,j=」 + j);
if(j == 5) break ok;
}
}
複製代碼
另外,我我的一般並不使用標號這種方式,而是讓外層的循環條件表達式的結果能夠受到裏層循環體代碼的控制,例如,要在二維數組中查找到某個數字。數組
int arr[][] ={{1,2,3},{4,5,6,7},{9}};boolean found = false;for(int i=0;i<arr.length&&!found;i++) {for(intj=0;j<arr[i].length;j++){System.out.println(「i=」 + i + 「,j=」 + j);if(arr[i][j] ==5) {found =true;break;}}}複製代碼
在switch(e)中,e只能是一個整數表達式或者枚舉常量(更大字體),整數表達式能夠是int基本類型或Integer包裝類型,因爲byte,short,char均可以隱含轉換爲int,因此,這些類型以及這些類型的包裝類型也是能夠的。顯然,long和String類型都不符合switch的語法規定,而且不能被隱式轉換成int類型,因此,它們不能做用於swtich語句中。安全
對於short s1= 1; s1 = s1 + 1;因爲s1+1運算時會自動提高表達式的類型,因此結果是int型,再賦值給short類型s1時,編譯器將報告須要強制轉換類型的錯誤。bash
對於short s1= 1; s1 += 1;因爲 +=是java語言規定的運算符,java編譯器會對它進行特殊處理,所以能夠正確編譯。
char型變量是用來存儲Unicode編碼的字符的,unicode編碼字符集中包含了漢字,因此,char型變量中固然能夠存儲漢字啦。不過,若是某個特殊的漢字沒有被包含在unicode編碼字符集中,那麼,這個char型變量中就不能存儲這個特殊漢字。補充說明:unicode編碼佔用兩個字節,因此,char類型的變量也是佔用兩個字節。
2<< 3,(左移三位)由於將一個數左移n位,就至關於乘以了2的n次方,那麼,一個數乘以8只要將其左移3位便可,而位運算cpu直接支持的,效率最高,因此,2乘以8等於幾的最效率的方法是2<< 3。
使用final關鍵字修飾一個變量時,是指引用變量不能變,引用變量所指向的對象中的內容仍是能夠改變的。例如,對於以下語句:
final StringBuffer a=new StringBuffer("immutable");
複製代碼
a=new StringBuffer("");
複製代碼
a.append(" broken!");
複製代碼
有人在定義方法的參數時,可能想採用以下形式來阻止方法內部修改傳進來的參數對象:
public void method(final StringBuffer param){}複製代碼
實際上,這是辦不到的,在該方法內部仍然能夠增長以下代碼來修改參數對象:
param.append("a");
複製代碼
在語法定義上的區別:靜態變量前要加static關鍵字,而實例變量前則不加。
在程序運行時的區別:實例變量屬於某個對象的屬性,必須建立了實例對象,其中的實例變量纔會被分配空間,才能使用這個實例變量。靜態變量不屬於某個實例對象,而是屬於類,因此也稱爲類變量,只要程序加載了類的字節碼,不用建立任何實例對象,靜態變量就會被分配空間,靜態變量就能夠被使用了。總之,實例變量必須建立對象後才能夠經過這個對象來使用,靜態變量則能夠直接使用類名來引用。
例如,對於下面的程序,不管建立多少個實例對象,永遠都只分配了一個staticVar變量,而且每建立一個實例對象,這個staticVar就會加1;可是,每建立一個實例對象,就會分配一個instanceVar,便可能分配多個instanceVar,而且每一個instanceVar的值都只自加了1次。
public class VariantTest{publicstatic int staticVar = 0;publicint instanceVar = 0;publicVariantTest(){staticVar++;instanceVar++;System.out.println(staticVar +instanceVar);}}複製代碼
不能夠。由於非static方法是要與對象關聯在一塊兒的,必須建立一個對象後,才能夠在該對象上進行方法調用,而static方法調用時不須要建立對象,能夠直接調用。也就是說,當一個static方法被調用時,可能尚未建立任何實例對象,若是從一個static方法中發出對非static方法的調用,那個非static方法是關聯到哪一個對象上的呢?這個邏輯沒法成立,因此,一個static方法內部發出對非static方法的調用。
int是java提供的8種原始數據類型之一。Java爲每一個原始類型提供了封裝類,Integer是java爲int提供的封裝類。int的默認值爲0,而Integer的默認值爲null,即Integer能夠區分出未賦值和值爲0的區別,int則沒法表達出未賦值的狀況。
例如:要想表達出沒有參加考試和考試成績爲0的區別,則只能使用Integer。在JSP開發中,Integer的默認爲null,因此用el表達式在文本框中顯示時,值爲空白字符串,而int默認的默認值爲0,因此用el表達式在文本框中顯示時,結果爲0,因此,int不適合做爲web層的表單數據的類型。
在Hibernate中,若是將OID定義爲Integer類型,那麼Hibernate就能夠根據其值是否爲null而判斷一個對象是不是臨時的,若是將OID定義爲了int類型,還須要在hbm映射文件中設置其unsaved-value屬性爲0。
另外,Integer提供了多個與整數相關的操做方法,例如,將一個字符串轉換成整數,Integer中還定義了表示整數的最大值和最小值的常量。
Math類中提供了三個與取整有關的方法:ceil、floor、round,這些方法的做用與它們的英文名稱的含義相對應。
例如,ceil的英文意義是天花板,該方法就表示向上取整,Math.ceil(11.3)的結果爲12,Math.ceil(-11.3)的結果是-11;floor的英文意義是地板,該方法就表示向下取整,Math.ceil(11.6)的結果爲11,Math.ceil(-11.6)的結果是-12;最難掌握的是round方法,它表示「四捨五入」,算法爲Math.floor(x+0.5),即將原來的數字加上0.5後再向下取整,因此,Math.round(11.5)的結果爲12,Math.round(-11.5)的結果爲-11。
這裏有一些筆誤,floor的英文意義是地板,該方法就表示向下取整,Math.floor(11.6)的結果爲11,Math.floor(-11.6)的結果是-12;
Overload是重載的意思,Override是覆蓋的意思,也就是重寫。
重載Overload表示同一個類中能夠有多個名稱相同的方法,但這些方法的參數列表各不相同(即參數個數或類型不一樣)。
重寫Override表示子類中的方法能夠與父類中的某個方法的名稱和參數徹底相同,經過子類建立的實例對象調用這個方法時,將調用子類中的定義方法,這至關於把父類中定義的那個徹底相同的方法給覆蓋了,這也是面向對象編程的多態性的一種表現。子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,由於子類能夠解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。若是父類的方法是private類型,那麼,子類則不存在覆蓋的限制,至關於子類中增長了一個全新的方法。
至於Overloaded的方法是否能夠改變返回值的類型這個問題,要看你倒底想問什麼呢?這個題目很模糊。若是幾個Overloaded的方法的參數列表不同,它們的返回者類型固然也能夠不同。但我估計你想問的問題是:若是兩個方法的參數列表徹底同樣,是否可讓它們的返回值不一樣來實現重載Overload。這是不行的,咱們能夠用反證法來講明這個問題,由於咱們有時候調用一個方法時也能夠不定義返回結果變量,即不要關心其返回結果,例如,咱們調用map.remove(key)方法時,雖然remove方法有返回值,可是咱們一般都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數列表徹底相同的方法,僅僅是返回類型不一樣,java就沒法肯定編程者倒底是想調用哪一個方法了,由於它沒法經過返回結果類型來判斷。
override能夠翻譯爲覆蓋,從字面就能夠知道,它是覆蓋了一個方法而且對其重寫,以求達到不一樣的做用。對咱們來講最熟悉的覆蓋就是對接口方法的實現,在接口中通常只是對方法進行了聲明,而咱們在實現時,就須要實現接口聲明的全部方法。除了這個典型的用法之外,咱們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意如下的幾點:
一、覆蓋的方法的標誌必需要和被覆蓋的方法的標誌徹底匹配,才能達到覆蓋的效果;
二、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
三、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;
四、被覆蓋的方法不能爲private,不然在其子類中只是新定義了一個方法,並無對其進行覆蓋。
Overload對咱們來講可能比較熟悉,能夠翻譯爲重載,它是指咱們能夠定義一些名稱相同的方法,經過定義不一樣的輸入參數來區分這些方法,而後再調用時,VM就會根據不一樣的參數樣式,來選擇合適的方法執行。在使用重載要注意如下的幾點:
一、在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序(固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int,float),可是不能爲fun(int,int));
二、不能經過訪問權限、返回類型、拋出的異常進行重載;
三、方法的異常類型和數目不會對重載形成影響;
四、對於繼承來講,若是某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,若是定義的話,也只是定義了一個新方法,而不會達到重載的效果。
接口能夠繼承接口。抽象類能夠實現(implements)接口,抽象類能夠繼承具體類。抽象類中能夠有靜態的main方法。
備註:只要明白了接口和抽象類的本質和做用,這些問題都很好回答,你想一想,若是你是java語言的設計者,你是否會提供這樣的支持,若是不提供的話,有什麼理由嗎?若是你沒有道理不提供,那答案就是確定的了。
只要記住抽象類與普通類的惟一區別就是不能建立實例對象和容許有abstract方法。
靠的是父類或接口定義的引用變量能夠指向子類或具體實現類的實例對象,而程序調用的方法在運行期才動態綁定,就是引用變量所指向的具體實例對象的方法,也就是內存里正在運行的那個對象的方法,而不是引用變量的類型中定義的方法。
1.抽象類能夠有構造方法,接口中不能有構造方法。
2.抽象類中能夠有普通成員變量,接口中沒有普通成員變量
3.抽象類中能夠包含非抽象的普通方法,接口中的全部方法必須都是抽象的,不能有非抽象的普通方法。
4. 抽象類中的抽象方法的訪問類型能夠是public,protected和(默認類型,雖然
eclipse下不報錯,但應該也不行),但接口中的抽象方法只能是public類型的,而且默認即爲public abstract類型。
5. 抽象類中能夠包含靜態方法,接口中不能包含靜態方法
6. 抽象類和接口中均可以包含靜態成員變量,抽象類中的靜態成員變量的訪問類型能夠任意,但接口中定義的變量只能是publicstatic final類型,而且默認即爲publicstatic final類型。
7. 一個類能夠實現多個接口,但只能繼承一個抽象類。
abstract的method不能夠是static的,由於抽象的方法是要被子類實現的,而static與子類扯不上關係!
native方法表示該方法要用另一種依賴平臺的編程語言實現的,不存在着被子類實現的問題,因此,它也不能是抽象的,不能與abstract混用。例如,FileOutputSteam類要硬件打交道,底層的實現用的是操做系統相關的api實現;例如,在windows用c語言實現的,因此,查看jdk的源代碼,能夠發現FileOutputStream的open方法的定義以下:
private native void open(Stringname) throwsFileNotFoundException;
複製代碼
若是咱們要用java調用別人寫的c語言函數,咱們是沒法直接調用的,咱們須要按照java的要求寫一個c語言的函數,又咱們的這個c語言函數去調用別人的c語言函數。因爲咱們的c語言函數是按java的要求來寫的,咱們這個c語言函數就能夠與java對接上,java那邊的對接方式就是定義出與咱們這個c函數相對應的方法,java中對應的方法不須要寫具體的代碼,但須要在前面聲明native。
關於synchronized與abstract合用的問題,我以爲也不行,由於在我幾年的學習和開發中,歷來沒見到過這種狀況,而且我以爲synchronized應該是做用在一個具體的方法上纔有意義。並且,方法上的synchronized同步所使用的同步鎖對象是this,而抽象方法上沒法肯定this是什麼。
徹底能夠。若是不是靜態內部類,那沒有什麼限制!
若是你把靜態嵌套類看成內部類的一種特例,那在這種狀況下不能夠訪問外部類的普通成員變量,而只能訪問外部類中的靜態成員,例如,下面的代碼:
class Outer{static int x;static class Inner{voidtest(){syso(x);}}}複製代碼
沒有。由於String被設計成不可變(immutable)類,因此它的全部對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內容是 "Hello",而後咱們對s進行了+操做,那麼s所指向的那個對象是否發生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另外一個 String對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是s這個引用變量再也不指向它了。
經過上面的說明,咱們很容易導出另外一個結論,若是常常對字符串進行各類各樣的修改,或者說,不可預見的修改,那麼使用String來表明字符串的話會引發很大的內存開銷。由於String對象創建以後不能再改變,因此對於每個不一樣的字符串,都須要一個String對象來表示。這時,應該考慮使用StringBuffer類,它容許修改,而不是每一個不一樣的字符串都要生成一個新的對象。而且,這兩種類的對象轉換十分容易。
同時,咱們還能夠知道,若是要使用內容相同的字符串,沒必要每次都new一個String。例如咱們要在構造器中對一個名叫s的String引用變量進行初始化,把它設置爲初始值,應當這樣作:
public class Demo {
private String s;
...
public Demo {
s = "Initial Value";
}
...
}
複製代碼
而非
s = new String("Initial Value");
複製代碼
後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,而且沒有意義,由於String對象不可改變,因此對於內容相同的字符串,只要一個String對象來表示就能夠了。也就說,屢次調用上面的構造器建立多個對象,他們的 String類型屬性s都指向同一個對象。
上面的結論還基於這樣一個事實:對於字符串常量,若是內容相同,Java認爲它們表明同一個String對象。而用關鍵字new調用構造器,老是會建立一個新的對象,不管內容是否相同。
至於爲何要把String類設計成不可變類,是它的用途決定的。其實不僅String,不少Java標準類庫中的類都是不可變的。在開發一個系統的時候,咱們有時候也須要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。不可變類有一些優勢,好比由於它的對象是隻讀的,因此多線程併發訪問也不會有任何問題。固然也有一些缺點,好比每一個不一樣的狀態都要一個對象來表明,可能會形成性能上的問題。因此Java標準類庫還提供了一個可變版本,即StringBuffer。
這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,至關於一種動態的數組,咱們之後能夠按位置索引號取出某個元素,而且其中的數據是容許重複的,這是與HashSet之類的集合的最大不一樣處,HashSet之類的集合不能夠按索引號去檢索其中的元素,也不容許有重複的元素。
ArrayList與Vector的區別主要包括兩個方面:.
(1)同步性:
Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不一樣步的。若是隻有一個線程會訪問到集合,那最好是使用ArrayList,由於它不考慮線程安全,效率會高些;若是有多個線程會訪問到集合,那最好是使用Vector,由於不須要咱們本身再去考慮和編寫線程安全的代碼。
(2)數據增加:
ArrayList與Vector都有一個初始的容量大小,當存儲進它們裏面的元素的個數超過了容量時,就須要增長ArrayList與Vector的存儲空間,每次要增長存儲空間時,不是隻增長一個存儲單元,而是增長多個存儲單元,每次增長的存儲單元的個數在內存空間利用與程序效率之間要取得必定的平衡。Vector默認增加爲原來兩倍,而ArrayList的增加策略在文檔中沒有明確規定(從源代碼看到的是增加爲原來的1.5倍)。ArrayList與Vector均可以設置初始的空間大小,Vector還能夠設置增加的空間大小,而ArrayList沒有提供設置增加空間的方法。
總結:即Vector增加原來的一倍,ArrayList增長原來的0.5倍。
HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap容許空(null)鍵值(key),因爲非線程安全,在只有一個線程訪問的狀況下,效率要高於Hashtable。
HashMap容許將null做爲一個entry的key或者value,而Hashtable不容許。
HashMap把Hashtable的contains方法去掉了,改爲containsvalue和containsKey。由於contains方法容易讓人引發誤解。
Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。
最大的不一樣是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不須要本身爲它的方法實現同步,而HashMap就必須爲之提供同步。
就HashMap與HashTable主要從三方面來講。
一.歷史緣由:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現
二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的
三.值:只有HashMap可讓你將空值做爲一個表的條目的key或value
一個是存儲單列數據的集合,另外一個是存儲鍵和值這樣的雙列數據的集合,List中存儲的數據是有順序,而且容許重複;Map中存儲的數據是沒有順序的,其鍵是不能重複的,它的值是能夠有重複的。
List,Set是,Map不是
(這樣的題比較考水平,兩個方面的水平:一是要真正明白這些內容,二是要有較強的總結和表述能力。)
首先,List與Set具備類似性,它們都是單列元素的集合,因此,它們有一個共同的父接口,叫Collection。Set裏面不容許有重複的元素,即不能有兩個相等(注意,不是僅僅是相同)的對象,即假設Set集合中有了一個A對象,如今我要向Set集合再存入一個B對象,但B對象與A對象equals相等,則B對象存儲不進去,因此,Set集合的add方法有一個boolean的返回值,當集合中沒有某個元素,此時add方法可成功加入該元素時,則返回true,當集合含有與某個元素equals相等的元素時,此時add方法沒法加入該元素,返回結果爲false。Set取元素時,不能細說要取第幾個,只能以Iterator接口取得全部的元素,再逐一遍歷各個元素。
List表示有前後順序的集合,注意,不是那種按年齡、按大小、按價格之類的排序。當咱們屢次調用add(Obje)方法時,每次加入的對象就像火車站買票有排隊順序同樣,按先來後到的順序排序。有時候,也能夠插隊,即調用add(intindex,Obj e)方法,就能夠指定當前對象在集合中的存放位置。一個對象能夠被反覆存儲進List中,每調用一次add方法,這個對象就被插入進集合中一次,其實,並非把這個對象自己存儲進了集合中,而是在集合中用一個索引變量指向這個對象,當這個對象被add屢次時,即至關於集合中有多個索引指向了這個對象,如圖x所示。List除了能夠用Iterator接口取得全部的元素,再逐一遍歷各個元素以外,還能夠調用get(index i)來明確說明取第幾個。
Map與List和Set不一樣,它是雙列的集合,其中有put方法,定義以下:put(obj key,obj value),每次存儲時,要存儲一對key/value,不能存儲重複的key,這個重複的規則也是按equals比較相等。取則能夠根據key得到相應的value,即get(Object key)返回值爲key所對應的value。另外,也能夠得到全部的key的結合,還能夠得到全部的value的結合,還能夠得到key和value組合成的Map.Entry對象的集合。
List以特定次序來持有元素,可有重複元素。Set沒法擁有重複元素,內部排序。Map保存key-value值,value可多值。
ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增長和插入元素,它們都容許直接按序號索引元素,可是插入元素要涉及數組元素移動等內存操做,因此索引數據快而插入數據慢,Vector因爲使用了synchronized方法(線程安全),一般性能上較ArrayList差。而LinkedList使用雙向鏈表實現存儲,按序號索引數據須要進行前向或後向遍歷,索引就變慢了,可是插入數據時只須要記錄本項的先後項便可,因此插入速度較快。
LinkedList也是線程不安全的,LinkedList提供了一些方法,使得LinkedList能夠被看成堆棧和隊列來使用。
Vector newVector = new Vector();For (int i=0;i<vector.size();i++){Object obj = vector.get(i);if(!newVector.contains(obj);newVector.add(obj);}複製代碼
還有一種簡單的方式,利用了Set不容許重複元素:
Collection是集合類的上級接口,繼承他的接口主要有Set和List.
Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各類集合的搜索、排序、線程安全化等操做。
Set裏的元素是不能重複的,元素重複與否是使用equals()方法進行判斷的。
==和equal區別也是考爛了的題,這裏說一下:
==操做符專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操做符。
equals方法是用於比較兩個獨立對象的內容是否相同,就比如去比較兩我的的長相是否相同,它比較的兩個對象是獨立的。
好比:兩條new語句建立了兩個對象,而後用a/b這兩個變量分別指向了其中一個對象,這是兩個不一樣的對象,它們的首地址是不一樣的,即a和b中存儲的數值是不相同的,因此,表達式a==b將返回false,而這兩個對象中的內容是相同的,因此,表達式a.equals(b)將返回true。
最經常使用的集合類是 List 和 Map。 List的具體實現包括 ArrayList和 Vector,它們是可變大小的列表,比較適合構建、存儲和操做任何類型對象的元素列表。 List適用於按數值索引訪問元素的情形。
Map 提供了一個更通用的元素存儲方法。 Map集合類用於存儲元素對(稱做"鍵"和"值"),其中每一個鍵映射到一個值。
它們都有增刪改查的方法。
對於set,大概的方法是add,remove, contains等
對於map,大概的方法就是put,remove,contains等
List類會有get(int index)這樣的方法,由於它能夠按順序取元素,而set類中沒有get(int index)這樣的方法。List和set均可以迭代出全部元素,迭代時先要獲得一個iterator對象,因此,set和list類都有一個iterator方法,用於返回那個iterator對象。map能夠返回三個集合,一個是返回全部的key的集合,另一個返回的是全部value的集合,再一個返回的key和value組合成的EntrySet對象的集合,map也有get方法,參數是key,返回值是key對應的value,這個自由發揮,也不是考記方法的能力,這些編程過程當中會有提示,結合他們三者的不一樣說一下用法就行。
Java知音公衆號整理一些各大公司經常使用的面試筆試題,供你們在天天閒暇之餘學習其中幾道題目,日積月累,等到出去面試時,一切都水到渠成,面試時就天然會遊刃有餘了。