java筆試面試題---基礎部分3

25、 abstract 的 method 是 否可 同時 是 static,是 否可 同時 是 native, 是否 可同 時是

synchronized?

abstract 的 method 不可以是 static 的,因爲抽象的方法是要被子類實現的,而 static 與子類扯不上關係!

native 方法表示該方法要用另外一種依賴平臺的編程語言實現的,不存在着被子類實現的問題,所以,它也不能是抽象的,不能與 abstract 混用。例如,FileOutputSteam 類要硬件打交道,底層的實現用的是操作系統相關的 api 實現,例如,在 windows 用 c 語言實現的,所以,查看 jdk 的源代碼,可以發現 FileOutputStream 的 open 方法的定義如下:

private native void open(String name) throwsFileNotFoundException;

如果我們要用 java調用別人寫的 c 語言函數,我們是無法直接調用的,我們需要按照 java的要求寫一個 c語言的函數,又我們的這個 c 語言函數去調用別人的 c 語言函數。由於我們的 c 語言函數是按 java 的要求來寫的,我們這個 c 語言函數就可以與 java 對接上,java 那邊的對接方式就是定義出與我們這個 c函數相對應的方法,java 中對應的方法不需要寫具體的代碼,但需要在前面聲明 native。

關於 synchronized 與 abstract 合用的問題,我覺得也不行,因爲在我幾年的學習和開發中,從來沒見到過這種情況,並且我覺得 synchronized 應該是作用在一個具體的方法上纔有意義。而且,方法上的 synchronized 同步所使用的同步鎖對象是 this,而抽象方法上無法確定 this 是什麼。

26、什麼是內部類?Static NestedClass 和 InnerClass的不同。

內部類就是在一個類的內部定義的類,內部類中不能定義靜態成員(靜態成員不是對象的特性,只是爲了找一個容身之處,所以需要放到一個類中而已,這麼一點小事,你還要把它放到類內部的一個類中,過分了啊!提供內部類,不是爲讓你幹這種事情,無聊,不讓你幹。我想可能是既然靜態成員類似 c 語言的全局變量,而內部類通常是用於創建內部對象用的,所以,把“全局變量”放在內部類中就是毫無意義的事情,既然是毫無意義的事情,就應該被禁止),內部類可以直接訪問外部類中的成員變量,內部類可以定義在外部類的方法外面,也可以定義在外部類的方法體中,如下所示:

public class Outer

{

int out_x

= 0;

public void method()

{

Inner1 inner1 = new Inner1();

public class Inner2

//在方法體內部定義的內部類

{

public method()

{

out_x = 3;

}

}

Inner2 inner2 = new Inner2();

}

public class Inner1

//在方法體外面定義的內部類

{

}

}

在方法體外面定義的內部類的訪問類型可以是 public,protecte,默認的,private 等 4 種類型,這就好像類中定義的成員變量有 4 種訪問類型一樣,它們決定這個內部類的定義對其他類是否可見;對於這種情況,我們也可以在外面創建內部類的實例對象,創建內部類的實例對象時,一定要先創建外部類的實例對象,然後用這個外部類的實例對象去創建內部類的實例對象,代碼如下:

Outer outer = new Outer();

Outer.Inner1 inner1 = outer.new Innner1();

在方法內部定義的內部類前面不能有訪問類型修飾符,就好像方法中定義的局部變量一樣,但這種內部類的前面可以使用 final 或 abstract 修飾符。這種內部類對其他類是不可見的其他類無法引用這種內部類,但是這種內部類創建的實例對象可以傳遞給其他類訪問。這種內部類必須是先定義,後使用,即內部類的定義代碼必須出現在使用該類之前,這與方法中的局部變量必須先定義後使用的道理也是一樣的。這種內部類可以訪問方法體中的局部變量,但是,該局部變量前必須加 final 修飾符。

對於這些細節,只要在 eclipse 寫代碼試試,根據開發工具提示的各類錯誤信息就可以馬上瞭解到。

在方法體內部還可以採用如下語法來創建一種匿名內部類,即定義某一接口或類的子類的同時,還創建了該子類的實例對象,無需爲該子類定義名稱:

public class Outer

{

public void start()

{

new Thread(

new Runable(){

public void run(){};

}

).start();

}

}

最後,在方法外部定義的內部類前面可以加上 static關鍵字,從而成爲Static Nested Class,它不再具有內部類的特性,所有,從狹義上講,它不是內部類。Static Nested Class 與普通類在運行時的行爲和功能上沒有什麼區別,只是在編程引用時的語法上有一些差別,它可以定義成 public、protected、默認的、private 等多種類型,而普通類只能定義成 public 和默認的這兩種類型。在外面引用 Static Nested Class 類的名稱爲“外部類名.內部類名”。在外面不需要創建外部類的實例對象,就可以直接創建 Static Nested Class,例如,假設 Inner 是定義在Outer 類中的 Static Nested Class,那麼可以使用如下語句創建 Inner 類:

Outer.Inner inner = new Outer.Inner();

由於 static Nested Class 不依賴於外部類的實例對象,所以,static Nested Class 能訪問外部類的非 static 成員變量。當在外部類中訪問 Static Nested Class 時,可以直接使用 Static

Nested Class 的名字,而不需要加上外部類的名字了,在 Static Nested Class 中也可以直接引用外部類的 static 的成員變量,不需要加上外部類的名字。

在靜態方法中定義的內部類也是 Static Nested Class,這時候不能在類前面加 static 關鍵字,靜態方法中的 Static Nested Class 與普通方法中的內部類的應用方式很相似,它除了可以直接訪問外部類中的 static 的成員變量,還可以訪問靜態方法中的局部變量,但是,該局部變量前必須加final修飾符。

備註:首先根據你的印象說出你對內部類的總體方面的特點:例如,在兩個地方可以定義,可以訪問外部類的成員變量,不能定義靜態成員,這是大的特點。然後再說一些細節方面的知識,例如,幾種定義方式的語法區別,靜態內部類,以及匿名內部類。

27、內部類可以引用它的包含類的成員嗎?有沒有什麼限制?

完全可以。如果不是靜態內部類,那沒有什麼限制!

如果你把靜態嵌套類當作內部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變量,而只能訪問外部類中的靜態成員,例如,下面的代碼:

class Outer

{

static int x;

static class Inner

{

void test()

{

syso(x);

}

}

}

答題時,也要能察言觀色,揣摩提問者的心思,顯然人家希望你說的是靜態內部類不能訪問外部類的成員,但你一上來就頂牛,這不好,要先順着人家,讓人家滿意,然後再說特殊情況,讓人家吃驚。

28、Anonymous Inner Class ((匿名內部類)) 是否可以 extends(繼承))其它類,是否可以

implements(實現)interface(接口?)?

可以繼承其他類或實現其他接口。不僅是可以,而是必須!

29、super.getClass()方法調用下面程序的輸出結果是多少?

import java.util.Date;

public

class Test extends Date{

public static void main(String[] args) {

new Test().test();

}

public void test(){

System.out.println(super.getClass().getName());

}

}

很奇怪,結果是 Test

在test方法中,直接調用 getClass().getName()方法,返回的是 Test 類名由於 getClass()在Object類中定義成了 final,子類不能覆蓋該方法,所以,在test 方法中調用getClass().getName()方法,其實就是在調用從父類 繼承 的getClass()方法,等效於調用super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也應該是 Test。

如果想得到父類的名稱,應該用如下代碼:

getClass().getSuperClass().getName();

30、String是最基本的數據類型嗎?

基本數據類型包括 byte、int、char、long、float、double、boolean 和 short。

java.lang.String 類是 final 類型的,因此不可以繼承這個類、不能修改這個類。爲了提高效率節省空間,我們應該用 StringBuffer 類

31、Stringss =="Hello";s== ss ++"" world!";這兩行代碼執行後,原始的 String對象中的內容到底變了沒有?

沒有。因爲 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。

32、是否可以繼承 String類?

String 類是 final 類故不可以繼承。

33、Stringss ==new String("xyz");創建了幾個 StringObject? 二者之間有什麼區別?

第一個對象是字符串常量"xyz"
第二個對象是new String("xyz")的時候產生的,在heap中分配內存給這個對象,只不過這個對象的內容是指向字符串常量"xyz"
另外還有一個引用s,指向第二個對象。這是一個變量,在棧中分配內存。

34、String 和 StringBuffer 的區別

JAVA 平臺提供了兩個類:String 和 StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數據。這個 String 類提供了數值不可改變的字符串。而這個 StringBuffer 類提供的字符串進行修改。當你知道字符數據要改變的時候你就可以使用 StringBuffer。典型地,你可以使用StringBuffers來動態構造字符數據。另外,String 實現了equals方法,new String(“abc”).equals(new String(“abc”)的結果爲true,而StringBuffer沒有實現equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結果爲 false。

接着要舉一個具體的例子來說明,我們要把 1 到 100 的所有數字拼起來,組成一個串。

StringBuffer sbf = new StringBuffer();

for(int i=0;i<100;i++)

{

sbf.append(i);

}

上面的代碼效率很高,因爲只創建了一個 StringBuffer 對象,而下面的代碼效率很低,因爲創建了101個對象。

String str= new String();

for(int i=0;i<100;i++)

{

str= str+ i;

}

在講兩者區別時,應把循環的次數搞成 10000,然後用 endTime-beginTime 來比較兩者執行的時間差異,最後還要講講StringBuilder與StringBuffer的區別。

String 覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋 equals方法和hashCode

方法,所以,將StringBuffer對象存儲進Java集合類中時會出現問題。

35、如何把一段逗號分割的字符串轉換成一個數組?(不太會)

思路:

1.用正則表達式,代碼大概爲:String [] result = orgStr.split(“,”);

2.用 StingTokenizer ,代碼爲:StringTokenizer

tokener = StringTokenizer(orgStr,”,”);

String [] result = new String[tokener .countTokens()];

Int i=0;

while(tokener.hasNext(){result[i++]=toker.nextToken();}

36、數組有沒有 length()這個方法??String有沒有 length()這個方法?

數組沒有 length()這個方法,有 length 的屬性。String 有有 length()這個方法。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章