Java基础——3
1、內(nèi)部類可以引用它的包含類的成員嗎?有沒有什么限制?
完全可以。如果不是靜態(tài)內(nèi)部類,那沒有什么限制!
如果你把靜態(tài)嵌套類當(dāng)作內(nèi)部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變量,而只能訪問外部類中的靜態(tài)成員,例如,下面的代碼:
class Outer
{
static int x;
static class Inner
{
?????????? void test()
?????????? {
??????????????????? syso(x);
?????????? }
}
}
?
答題時,也要能察言觀色,揣摩提問者的心思,顯然人家希望你說的是靜態(tài)內(nèi)部類不能訪問外部類的成員,但你一上來就頂牛,這不好,要先順著人家,讓人家滿意,然后再說特殊情況,讓人家吃驚。
?
2、Anonymous Inner Class (匿名內(nèi)部類) 是否可以extends(繼承)其它類,是否可以implements(實現(xiàn))interface(接口)?
可以繼承其他類或?qū)崿F(xiàn)其他接口。不僅是可以,而是必須!
3、super.getClass()方法調(diào)用
下面程序的輸出結(jié)果是多少?
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());
??? }
}
?
很奇怪,結(jié)果是Test
這屬于腦筋急轉(zhuǎn)彎的題目,在一個qq群有個網(wǎng)友正好問過這個問題,我覺得挺有趣,就研究了一下,沒想到今天還被你面到了,哈哈。
在test方法中,直接調(diào)用getClass().getName()方法,返回的是Test類名
由于getClass()在Object類中定義成了final,子類不能覆蓋該方法,所以,在
test方法中調(diào)用getClass().getName()方法,其實就是在調(diào)用從父類繼承的getClass()方法,等效于調(diào)用super.getClass().getName()方法,所以,super.getClass().getName()方法返回的也應(yīng)該是Test。
如果想得到父類的名稱,應(yīng)該用如下代碼:
getClass().getSuperClass().getName();
?
4. jdk中哪些類是不能繼承的?
不能繼承的是類是那些用final關(guān)鍵字修飾的類。一般比較基本的類型或防止擴展類無意間破壞原來方法的實現(xiàn)的類型都應(yīng)該是final的,在jdk中System,String,StringBuffer等都是基本類型。
5、String是最基本的數(shù)據(jù)類型嗎?
基本數(shù)據(jù)類型包括byte、int、char、long、float、double、boolean和short。
java.lang.String類是final類型的,因此不可以繼承這個類、不能修改這個類。為了提高效率節(jié)省空間,我們應(yīng)該用StringBuffer類
?
6、String?s?=?"Hello";s?=?s?+?"?world!";這兩行代碼執(zhí)行后,原始的String對象中的內(nèi)容到底變了沒有?
沒有。因為String被設(shè)計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s原先指向一個String對象,內(nèi)容是 "Hello",然后我們對s進行了+操作,那么s所指向的那個對象是否發(fā)生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個 String對象,內(nèi)容為"Hello?world!",原來那個對象還存在于內(nèi)存之中,只是s這個引用變量不再指向它了。
通過上面的說明,我們很容易導(dǎo)出另一個結(jié)論,如果經(jīng)常對字符串進行各種各樣的修改,或者說,不可預(yù)見的修改,那么使用String來代表字符串的話會引起很大的內(nèi)存開銷。因為 String對象建立之后不能再改變,所以對于每一個不同的字符串,都需要一個String對象來表示。這時,應(yīng)該考慮使用StringBuffer類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。并且,這兩種類的對象轉(zhuǎn)換十分容易。
同時,我們還可以知道,如果要使用內(nèi)容相同的字符串,不必每次都new一個String。例如我們要在構(gòu)造器中對一個名叫s的String引用變量進行初始化,把它設(shè)置為初始值,應(yīng)當(dāng)這樣做:
public?class?Demo?{
private?String?s;
...
public?Demo?{
s?=?"Initial?Value";
}
...
}
而非
s?=?new?String("Initial?Value");
后者每次都會調(diào)用構(gòu)造器,生成新對象,性能低下且內(nèi)存開銷大,并且沒有意義,因為String對象不可改變,所以對于內(nèi)容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調(diào)用上面的構(gòu)造器創(chuàng)建多個對象,他們的String類型屬性s都指向同一個對象。
上面的結(jié)論還基于這樣一個事實:對于字符串常量,如果內(nèi)容相同,Java認(rèn)為它們代表同一個String對象。而用關(guān)鍵字new調(diào)用構(gòu)造器,總是會創(chuàng)建一個新的對象,無論內(nèi)容是否相同。
至于為什么要把String類設(shè)計成不可變類,是它的用途決定的。其實不只String,很多Java標(biāo)準(zhǔn)類庫中的類都是不可變的。在開發(fā)一個系統(tǒng)的時候,我們有時候也需要設(shè)計不可變類,來傳遞一組相關(guān)的值,這也是面向?qū)ο笏枷氲捏w現(xiàn)。不可變類有一些優(yōu)點,比如因為它的對象是只讀的,所以多線程并發(fā)訪問也不會有任何問題。當(dāng)然也有一些缺點,比如每個不同的狀態(tài)都要一個對象來代表,可能會造成性能上的問題。所以Java標(biāo)準(zhǔn)類庫還提供了一個可變版本,即 StringBuffer。
7、是否可以繼承String類?
String類是final類故不可以繼承。
?
8、String s = new String("xyz");創(chuàng)建了幾個String Object? 二者之間有什么區(qū)別?
兩個或一個,”xyz”對應(yīng)一個對象,這個對象放在字符串常量緩沖區(qū),常量”xyz”不管出現(xiàn)多少遍,都是緩沖區(qū)中的那一個。New String每寫一遍,就創(chuàng)建一個新的對象,它一句那個常量”xyz”對象的內(nèi)容來創(chuàng)建出一個新String對象。如果以前就用過’xyz’,這句代表就不會創(chuàng)建”xyz”自己了,直接從緩沖區(qū)拿。
9、String 和StringBuffer的區(qū)別
JAVA平臺提供了兩個類:String和StringBuffer,它們可以儲存和操作字符串,即包含多個字符的字符數(shù)據(jù)。String類表示內(nèi)容不可改變的字符串。而StringBuffer類表示內(nèi)容可以被修改的字符串。當(dāng)你知道字符數(shù)據(jù)要改變的時候你就可以使用StringBuffer。典型地,你可以使用StringBuffers來動態(tài)構(gòu)造字符數(shù)據(jù)。另外,String實現(xiàn)了equals方法,new String(“abc”).equals(new String(“abc”)的結(jié)果為true,而StringBuffer沒有實現(xiàn)equals方法,所以,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的結(jié)果為false。
?
接著要舉一個具體的例子來說明,我們要把1到100的所有數(shù)字拼起來,組成一個串。
StringBuffer sbf = new StringBuffer();?
for(int i=0;i<100;i++)
{
?????? sbf.append(i);
}
上面的代碼效率很高,因為只創(chuàng)建了一個StringBuffer對象,而下面的代碼效率很低,因為創(chuàng)建了101個對象。
String str = new String();?
for(int i=0;i<100;i++)
{
?????? str = str + i;
}
在講兩者區(qū)別時,應(yīng)把循環(huán)的次數(shù)搞成10000,然后用endTime-beginTime來比較兩者執(zhí)行的時間差異,最后還要講講StringBuilder與StringBuffer的區(qū)別。
?
String覆蓋了equals方法和hashCode方法,而StringBuffer沒有覆蓋equals方法和hashCode方法,所以,將StringBuffer對象存儲進Java集合類中時會出現(xiàn)問題。
?
10.StringBuffer與StringBuilder的區(qū)別
? StringBuffer和StringBuilder類都表示內(nèi)容可以被修改的字符串,StringBuilder是線程不安全的,運行效率高,如果一個字符串變量是在方法里面定義,這種情況只可能有一個線程訪問它,不存在不安全的因素了,則用StringBuilder。如果要在類里面定義成員變量,并且這個類的實例對象會在多線程環(huán)境下使用,那么最好用StringBuffer。
?
11、如何把一段逗號分割的字符串轉(zhuǎn)換成一個數(shù)組?
如果不查jdk api,我很難寫出來!我可以說說我的思路:
String [] result = new String[tokener .countTokens()];
Int i=0;
while(tokener.hasNext(){result[i++]=toker.nextToken();}
?
12、數(shù)組有沒有l(wèi)ength()這個方法? String有沒有l(wèi)ength()這個方法?
數(shù)組沒有l(wèi)ength()這個方法,有l(wèi)ength的屬性。String有有l(wèi)ength()這個方法。
13、下面這條語句一共創(chuàng)建了多少個對象:String s="a"+"b"+"c"+"d";
答:對于如下代碼:
String s1 = "a";
String s2 = s1 + "b";
String s3 = "a" + "b";
System.out.println(s2 == "ab");
System.out.println(s3 == "ab");
第一條語句打印的結(jié)果為false,第二條語句打印的結(jié)果為true,這說明javac編譯可以對字符串常量直接相加的表達(dá)式進行優(yōu)化,不必要等到運行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結(jié)果。
題目中的第一行代碼被編譯器在編譯時優(yōu)化后,相當(dāng)于直接定義了一個”abcd”的字符串,所以,上面的代碼應(yīng)該只創(chuàng)建了一個String對象。寫如下兩行代碼,
?????????? String s = "a" + "b" + "c" + "d";
?????????? System.out.println(s == "abcd");
最終打印的結(jié)果應(yīng)該為true。
?
?
14、try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執(zhí)行,什么時候被執(zhí)行,在return前還是后?
也許你的答案是在return之前,但往更細(xì)地說,我的答案是在return中間執(zhí)行,請看下面程序代碼的運行結(jié)果:
public? class Test {
?
??? /**
??? ?* @param args add by zxx ,Dec 9, 2008
??? ?*/
??? public static void main(String[] args) {
?????? // TODO Auto-generated method stub
?????? System.out.println(new Test().test());;
??? }
?
??? static int test()
??? {
?????? int x = 1;
?????? try
?????? {
?????????? return x;
?????? }
?????? finally
?????? {
?????????? ++x;
?????? }
??? }
???
}
?
---------執(zhí)行結(jié)果 ---------
1
?
運行結(jié)果是1,為什么呢?主函數(shù)調(diào)用子函數(shù)并得到結(jié)果的過程,好比主函數(shù)準(zhǔn)備一個空罐子,當(dāng)子函數(shù)要返回結(jié)果時,先把結(jié)果放在罐子里,然后再將程序邏輯返回到主函數(shù)。所謂返回,就是子函數(shù)說,我不運行了,你主函數(shù)繼續(xù)運行吧,這沒什么結(jié)果可言,結(jié)果是在說這話之前放進罐子里的。
15、下面的程序代碼輸出的結(jié)果是多少?
public class? smallT
{
?????? public static void? main(String args[])
?????? {
????????????? smallT t? = new? smallT();
????????????? int? b? =? t.get();
????????????? System.out.println(b);
?????? }
??????
?????? public int? get()
?????? {
????????????? try
????????????? {
???????????????????? return 1 ;
????????????? }
????????????? finally
????????????? {
???????????????????? return 2 ;
????????????? }
?????? }
}
?
返回的結(jié)果是2。
我可以通過下面一個例子程序來幫助我解釋這個答案,從下面例子的運行結(jié)果中可以發(fā)現(xiàn),try中的return語句調(diào)用的函數(shù)先于finally中調(diào)用的函數(shù)執(zhí)行,也就是說return語句先執(zhí)行,finally語句后執(zhí)行,所以,返回的結(jié)果是2。Return并不是讓函數(shù)馬上返回,而是return語句執(zhí)行后,將把返回結(jié)果放置進函數(shù)棧中,此時函數(shù)并不是馬上返回,它要執(zhí)行finally語句后才真正開始返回。
在講解答案時可以用下面的程序來幫助分析:
public? class Test {
?
??? /**
??? ?* @param args add by zxx ,Dec 9, 2008
??? ?*/
??? public static void main(String[] args) {
?????? // TODO Auto-generated method stub
?????? System.out.println(new Test().test());;
??? }
?
??? int test()
??? {
?????? try
?????? {
?????????? return func1();
?????? }
?????? finally
?????? {
?????????? return func2();
?????? }
??? }
???
??? int func1()
??? {
?????? System.out.println("func1");
?????? return 1;
??? }
??? int func2()
??? {
?????? System.out.println("func2");
?????? return 2;
??? }??
}
-----------執(zhí)行結(jié)果-----------------
?
func1
func2
2
?
結(jié)論:finally中的代碼比return 和break語句后執(zhí)行
轉(zhuǎn)載于:https://www.cnblogs.com/Jeanferly/archive/2012/08/07/2626296.html
總結(jié)
- 上一篇: Objective-C语法之KVC使用
- 下一篇: APP性能之终端兼容