Android程序員面試分類模擬2_第1頁(yè)
Android程序員面試分類模擬2_第2頁(yè)
Android程序員面試分類模擬2_第3頁(yè)
Android程序員面試分類模擬2_第4頁(yè)
Android程序員面試分類模擬2_第5頁(yè)
已閱讀5頁(yè),還剩21頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Android程序員面試分類模擬2論述題1.

Java語言有哪些優(yōu)點(diǎn)?正確答案:SUN公司對(duì)Java語言的描述如下:“Javaisasimple,object-oriented,dist(江南博哥)ributed,interpreted,robust,secure,architectureneutral,portable,high-performance,multithreaded,anddynamiclanguage”。具體而言,Java語言具有以下幾個(gè)方面的優(yōu)點(diǎn):

1)Java為純面向?qū)ο蟮恼Z言(《Java編程思想》提到Java語言是一種“Everythingisobject”的語言),它能夠直接反映現(xiàn)實(shí)生活中的對(duì)象,例如火車、動(dòng)物等,因此通過它,開發(fā)人員更容易編寫程序。

2)平臺(tái)無關(guān)性。Java語言可以一次編譯,到處運(yùn)行。無論是在Windows平臺(tái)還是在Linux、macOS等其他平臺(tái)上對(duì)Java程序進(jìn)行編譯,編譯后的程序在其他平臺(tái)上都可以運(yùn)行。由于Java是解釋型語言,編譯器會(huì)把Java代碼變成“中間代碼”,然后在JVM(JavaVirtualMachine,Java虛擬機(jī))上被解釋執(zhí)行。由于中間代碼與平臺(tái)無關(guān),所以,Java語言可以很好地跨平臺(tái)執(zhí)行,具有很好的可移植性。

3)Java提供了很多內(nèi)置的類庫(kù),通過這些類庫(kù),簡(jiǎn)化了開發(fā)人員的編程工作,同時(shí)縮短了項(xiàng)目的開發(fā)時(shí)間。例如:提供了對(duì)多線程支持,提供了對(duì)網(wǎng)絡(luò)通信的支持,最重要的一點(diǎn)是提供了垃圾回收器,把開發(fā)人員從對(duì)內(nèi)存的管理中解脫出來。

4)提供了對(duì)Web應(yīng)用開發(fā)的支持,例如Applet、Servlet和JSP可以用來開發(fā)Web應(yīng)用程序。Socket、RMI可以用來開發(fā)分布式應(yīng)用程序的類庫(kù)。

5)具有較好的安全性和健壯性。Java語言經(jīng)常被用在網(wǎng)絡(luò)環(huán)境中,為了增強(qiáng)程序的安全性,Java語言提供了一個(gè)防止惡意代碼攻擊的安全機(jī)制(數(shù)組邊界檢測(cè)和bytecode校驗(yàn)等)。Java的強(qiáng)類型機(jī)制、垃圾回收器、異常處理和安全檢查機(jī)制使得使用Java語言編寫的程序有很好的健壯性。

6)去除了C++語言中難以理解、容易混淆的特性,例如頭文件、指針、結(jié)構(gòu)、單元、運(yùn)算符重載、虛擬基礎(chǔ)類、多重繼承等,使得程序更加嚴(yán)謹(jǐn)、簡(jiǎn)潔。

2.

instanceof有什么作用?正確答案:instanceof是Java語言中的一個(gè)二元運(yùn)算符,它的作用是判斷一個(gè)引用類型的變量所指向的對(duì)象是否為一個(gè)類(或接口、抽象類、父類)的實(shí)例,即它左邊的對(duì)象是否是它右邊的類的實(shí)例,返回boolean類型的數(shù)據(jù)。

常見的用法為:result=objectinstanceofclass,如果object是class的一個(gè)實(shí)例,則instanceof運(yùn)算符返回true。如果object不是指定類的一個(gè)實(shí)例,或者object是null,則返回false。

以如下程序?yàn)槔?/p>

publicclassTest

{

publicstaticvoidmain(Stringargs[])

{

Strings="Hello";

int[]a={1,2};

if(sinstanceofString)

System.out.println("true");

if(sinstanceofObject)

System.out.println("true");

if(ainstanceofint[])

System.out.println("true");

}

}

程序運(yùn)行結(jié)果為:

true

true

true

3.

一個(gè)Java文件中是否可以定義多個(gè)類?正確答案:一個(gè)Java文件可以定義多個(gè)類,但是最多只能有一個(gè)類被public修飾,并且這個(gè)類的類名與文件名必須相同,若這個(gè)文件中沒有public的類,則文件名隨便是一個(gè)類的名字即可。需要注意的是,當(dāng)用javac指令編譯這個(gè)java文件的時(shí)候,它會(huì)給每一個(gè)類生成一個(gè)對(duì)應(yīng)的.class文件。如下例定義Derived.java為:

classBase

{

publicvoidprint()

{

System.out.println("Base");

}

}

publicclassDerivedextendsBase

{

publicstaticvoidmain(String[]a)

{

Basec=newDerived();

c.print();

}

}

使用javacDerived.java指令編譯上述代碼,會(huì)生成兩個(gè)字節(jié)碼文件:Base.class與Derived.class,然后使用javaDerived指令執(zhí)行,會(huì)輸出:Base。

4.

變量命名有哪些規(guī)則?正確答案:在Java語言中,變量名、函數(shù)名、數(shù)組名統(tǒng)稱為標(biāo)識(shí)符,Java語言規(guī)定標(biāo)識(shí)符只能由字母(a~z,A~Z)、數(shù)字(0~9)、下劃線(_)和$組成,并且標(biāo)識(shí)符的第一個(gè)字符必須是字母、下劃線或$。此外,標(biāo)識(shí)符也不能包含空白字符(換行符、空格和制表符)。

以下標(biāo)識(shí)符都是非法的:

1)char:char是Java語言的一個(gè)數(shù)據(jù)類型,是保留字,不能作為標(biāo)識(shí)符,其他的如int、float等類似。

2)numberofbook:標(biāo)識(shí)符中不能有空格。

3)3com:不能以數(shù)字開頭。

4)a*B:*不能作為標(biāo)識(shí)符的字符。

值得注意的是,在Java語言中,變量名是區(qū)分大小寫的,例如Count與count被認(rèn)為是兩個(gè)不同的標(biāo)識(shí)符。

5.

“==”、equals和hashCode的區(qū)別是什么?正確答案:“==”運(yùn)算符用來比較兩個(gè)變量的值是否相等,也就是用于比較變量所對(duì)應(yīng)的內(nèi)存中所存儲(chǔ)的數(shù)值是否相同,要比較兩個(gè)基本類型的數(shù)據(jù)或兩個(gè)引用變量是否相等,只能用“==”運(yùn)算符。

具體而言,如果兩個(gè)變量是基本數(shù)據(jù)類型,可以直接用“==”來比較其對(duì)應(yīng)的值是否相等。如果一個(gè)變量指向的數(shù)據(jù)是對(duì)象(引用類型),那么,此時(shí)涉及了兩塊內(nèi)存,對(duì)象本身占用一塊內(nèi)存(堆內(nèi)存),對(duì)象的引用也占用一塊內(nèi)存。例如,對(duì)于賦值語句Strings=newString(),變量s占用一塊存儲(chǔ)空間(一般在棧中),而newString()則存儲(chǔ)在另外一塊存儲(chǔ)空間里(一般在堆中),此時(shí),變量s所對(duì)應(yīng)的內(nèi)存中存儲(chǔ)的數(shù)值就是對(duì)象占用的那塊內(nèi)存的首地址。對(duì)于指向?qū)ο箢愋偷淖兞?,如果要比較兩個(gè)變量是否指向同一個(gè)對(duì)象,即要看這兩個(gè)變量所對(duì)應(yīng)的內(nèi)存中的數(shù)值是否相等(這兩個(gè)對(duì)象是否指向同一塊存儲(chǔ)空間),這時(shí)候就可以用“==”運(yùn)算符進(jìn)行比較。但是,如果要比較這兩個(gè)對(duì)象的內(nèi)容是否相等,那么用“==”運(yùn)算符就無法實(shí)現(xiàn)了。

2)equals是Object類提供的方法之一,每一個(gè)Java類都繼承自O(shè)bject類,所以每一個(gè)對(duì)象都具有equals這個(gè)方法。Object類中定義的equals(Object)方法是直接使用“==”比較的兩個(gè)對(duì)象,所以在沒有覆蓋equals(Object)方法的情況下,equals(Object)與“==”一樣,比較的是引用。

相比“==”運(yùn)算符,equals(Object)方法的特殊之處就在于它可以被覆蓋,所以可以通過覆蓋這個(gè)方法讓它不是比較引用而是比較對(duì)象的屬性。例如String類的equals方法是用于比較兩個(gè)獨(dú)立對(duì)象的內(nèi)容是否相同,即堆中的內(nèi)容是否相同。例如,對(duì)于下面的代碼:

Strings1=newString("Hello");

Strings2=newString("Hello");

兩條new語句在堆中創(chuàng)建了兩個(gè)對(duì)象,然后用s1、s2這兩個(gè)變量分別指向這兩個(gè)對(duì)象,這是兩個(gè)不同的對(duì)象,它們的首地址是不同的,即s1和s2中存儲(chǔ)的數(shù)值是不相同的,所以,表達(dá)式a==b將返回false,而這兩個(gè)對(duì)象中的內(nèi)容是相同的,所以,表達(dá)式a.equals(b)將返回true。

如果一個(gè)類沒有實(shí)現(xiàn)equals方法,那么它將繼承Object類的equals方法,Object類的equals方法的實(shí)現(xiàn)代碼如下:

booleanequals(Objecto){

returnthis==o;

}

通過以上例子可以說明,如果一個(gè)類沒有自己定義equals方法,它默認(rèn)的equals方法(從Object類繼承的)就是使用“==”運(yùn)算符,也是在比較兩個(gè)變量指向的對(duì)象是否為同一對(duì)象,此時(shí)使用equals方法和使用“==”會(huì)得到同樣的結(jié)果,如果比較的是兩個(gè)獨(dú)立的對(duì)象則總返回false。如果編寫的類希望能夠比較該類創(chuàng)建的兩個(gè)實(shí)例對(duì)象的內(nèi)容是否相同,那么必須覆蓋equals方法,由開發(fā)人員自己寫代碼來決定在什么情況即可認(rèn)為兩個(gè)對(duì)象的內(nèi)容是相同的。

3)hashCode()方法是從Object類中繼承過來的,它也用來鑒定兩個(gè)對(duì)象是否相等。Object類中的hashCode()方法返回對(duì)象在內(nèi)存中地址轉(zhuǎn)換成的一個(gè)int值,所以如果沒有重寫hashCode()方法,任何對(duì)象的hashCode()方法都是不相等的。

雖然equals方法也是用來判斷兩個(gè)對(duì)象是否相等的,但是二者是有區(qū)別的。一般來講,equals方法是給用戶調(diào)用的,如果需要判斷兩個(gè)對(duì)象是否相等,可以重寫equals方法,然后在代碼中調(diào)用,就可以判斷它們是否相等了。對(duì)于hashCode()方法,用戶一般不會(huì)去調(diào)用它,例如在HashMap中,由于key是不可以重復(fù)的,它在判斷key是否重復(fù)的時(shí)候就判斷了hashCode()這個(gè)方法,而且也用到了equals方法。此外“不可以重復(fù)”指的是equals和hashCode()只要有一個(gè)不等就可以了。所以,hashCode()相當(dāng)于是一個(gè)對(duì)象的編碼,就好像文件中的md5,它與equals方法的不同之處就在于它返回的是int型,比較起來不直觀。

一般在覆蓋equals方法的同時(shí)也要覆蓋hashCode()方法,否則,就會(huì)違反Object.hashCode的通用約定,從而導(dǎo)致該類無法與所有基于散列值(hash)的集合類(HashMap、HashSet和Hashtable)結(jié)合在一起正常運(yùn)行。

hashCode()的返回值和equals方法的關(guān)系如下:如果x.equals(y)返回true,即兩個(gè)對(duì)象根據(jù)equals方法比較是相等的,那么調(diào)用這兩個(gè)對(duì)象中任意一個(gè)對(duì)象的hashCode()方法都必須產(chǎn)生同樣的整數(shù)結(jié)果。如果x.equals(y)返回false,即兩個(gè)對(duì)象根據(jù)equals()方法比較是不相等的,那么x和y的hashCode()方法的返回值有可能相等,也有可能不等。反過來,hashCode()方法的返回值不等,一定能推出equals方法的返回值也不等,而hashCode()方法的返回值相等,則equals方法的返回值可能相等,也可能不等。

6.

“<<”運(yùn)算符與“>>”運(yùn)算符有何異同?正確答案:“<<”運(yùn)算符表示左移,左移n位表示原來的值乘2的n次方。經(jīng)常用來代替乘法操作,例如:一個(gè)數(shù)m乘以16可以表示為將這個(gè)數(shù)左移4位(m<<4),由于CPU直接支持位運(yùn)算,因此位運(yùn)算比乘法運(yùn)算的效率高。

與右移運(yùn)算不同的是,左移運(yùn)算沒有有符號(hào)與無符號(hào)左移,在左移的時(shí)候,移除高位的同時(shí)再低位補(bǔ)0。以4<<3(4為int型)為例,其運(yùn)算步驟如下所示:

1)把4轉(zhuǎn)換為二進(jìn)制數(shù)字00000000000000000000000000000100。

2)把該數(shù)字的高三位移走,同時(shí)其他位向左移動(dòng)3位。

3)在最低位補(bǔ)3個(gè)零。最終結(jié)果為00000000000000000000000000100000,對(duì)應(yīng)的十進(jìn)制數(shù)為32。

與右移運(yùn)算符相同的是,當(dāng)進(jìn)行左移運(yùn)算時(shí),如果移動(dòng)的位數(shù)超過了該類型的最大位數(shù),那么編譯器會(huì)對(duì)移動(dòng)的位數(shù)取模。例如對(duì)int型移動(dòng)33位,實(shí)際上只移動(dòng)了33%32=1位。

7.

Java程序初始化的順序是怎樣的?正確答案:在Java語言中,當(dāng)實(shí)例化對(duì)象時(shí),對(duì)象所在類的所有成員變量首先要進(jìn)行初始化,只有當(dāng)所有類成員完成初始化后,才會(huì)調(diào)用對(duì)象所在類的構(gòu)造函數(shù)創(chuàng)建對(duì)象。

Java程序的初始化一般遵循以下3個(gè)原則(優(yōu)先級(jí)依次遞減):①靜態(tài)對(duì)象(變量)優(yōu)先于非靜態(tài)對(duì)象初始化,其中,靜態(tài)對(duì)象(變量)只初始化一次,而非靜態(tài)對(duì)象(變量)可能會(huì)初始化多次。②父類優(yōu)先于子類進(jìn)行初始化。③按照成員變量定義順序進(jìn)行初始化。即使變量定義散布于方法定義之中,它們依然在任何方法(包括構(gòu)造方法)被調(diào)用之前先進(jìn)行初始化。

Java程序的初始化工作可以在許多不同的代碼塊中來完成(例如:靜態(tài)代碼塊、構(gòu)造函數(shù)等),它們執(zhí)行的順序?yàn)椋焊割愳o態(tài)變量→父類靜態(tài)代碼塊→子類靜態(tài)變量→子類靜態(tài)代碼→父類非靜態(tài)變量→父類非靜態(tài)代碼塊→父類構(gòu)造函數(shù)→子類非靜態(tài)變量→子類非靜態(tài)代碼塊→子類構(gòu)造函數(shù)。下面給出一個(gè)不同模塊初始化時(shí)執(zhí)行順序的一個(gè)例子。

classBase{

static

{

System.out.println("Basestaticblock");

}

{

System.out.println("Baseblock");

}

publicBase()

{

System.out.println("Baseconstructor");

}

)

publicclassDerivedextendsBase

{

static

{

System.out.println("Derivedstaticblock");

}

{

System.out.println("Derivedblock");

}

publicDerived()

{

System.out.println("Derivedconstructor");

}

publicstaticvoidmain(Stringargs[])

{

newDerived();

}

}

程序運(yùn)行結(jié)果為:

Basestaticblock

Derivedstaticblock

Baseblock

Baseconstructor

Derivedblock

Derivedconstructor

這里需要注意的是,(靜態(tài))非靜態(tài)成員域在定義時(shí)初始化和(靜態(tài))非靜態(tài)塊中初始化的優(yōu)先級(jí)是平級(jí)的,也就是說按照從上到下初始化,最后一次初始化為最終的值(不包括非靜態(tài)的成員域在構(gòu)造器中初始化)。所以在(靜態(tài))非靜態(tài)塊中初始化的域甚至能在該域聲明的上方,因?yàn)榉峙浯鎯?chǔ)空間在初始化之前就完成了。

如下例所示:

publicclasstestStatic

{

static{a=2;}

staticinta=1;

staticintb=3;

static{b=4;}

publicstaticvoidmain(String[]args)

{

System.out.println(a);

System.out.println(b);

}

}

程序運(yùn)行結(jié)果為:

1

4

8.

JDK中哪些類是不能被繼承的?正確答案:不能繼承的類是那些用final關(guān)鍵字修飾的類。一般比較基本的類型為防止擴(kuò)展類無意間破壞原來方法的實(shí)現(xiàn)的類型都應(yīng)該是final的,在JDK中,String、StringBuffer等都是基本類型。所以,String和StringBuffer等是不能繼承的。

9.

運(yùn)算符優(yōu)先級(jí)是什么?正確答案:Java語言中有很多運(yùn)算符,由于運(yùn)算符優(yōu)先級(jí)的問題經(jīng)常會(huì)導(dǎo)致程序出現(xiàn)意想不到的結(jié)果,下表詳細(xì)介紹了運(yùn)算符的優(yōu)先級(jí)。

運(yùn)算符優(yōu)先級(jí)優(yōu)先級(jí)運(yùn)算符結(jié)合性1.()[]從左向右2+(正)-(負(fù))++--~!3*/%4+(加)-(減)5<<>>(無符號(hào)右移)>>>(有符號(hào)右移)6<<=

>>=instanceof7==!=8&9|10^11&&12||13?:14=+=-=*=/=%=&=|=^=~=<<=>>=>>>=在實(shí)際使用的時(shí)候,如果不確定運(yùn)算符的優(yōu)先級(jí),最好通過括號(hào)運(yùn)算符來控制運(yùn)算順序。

10.

數(shù)組的初始化方式有哪幾種?正確答案:在Java語言中,一維數(shù)組的聲明方式為:

typearrayName[]或type[]arrayName

其中type既可以是基本的數(shù)據(jù)類型,也可以是類,arrayName表示數(shù)組的名字,[]用來表示這個(gè)變量的類型為一維數(shù)組。與C/C++語言不同的是,在Java語言中,數(shù)組被創(chuàng)建后會(huì)根據(jù)數(shù)組存儲(chǔ)的數(shù)據(jù)類型初始化成對(duì)應(yīng)的初始值(例如,int類型會(huì)初始化為0,對(duì)象會(huì)初始化為null)。另外一個(gè)不同之處是Java數(shù)組在定義的時(shí)候,并不會(huì)給數(shù)組元素分配空間,因此[]中不需要指定數(shù)組的長(zhǎng)度,對(duì)于使用上面方式定義的數(shù)組在使用的時(shí)候還必須為之分配空間,分配方法為:

arrayName=newtype[arraySize];//arraySize表示數(shù)組的長(zhǎng)度

在完成數(shù)組的聲明后,需要對(duì)其進(jìn)行初始化,下面介紹兩種初始化方法:

1)int[]a=newint[5];//動(dòng)態(tài)創(chuàng)建5個(gè)整型,默認(rèn)初始化為0

2)int[]a={1,2,3,4,5};//聲明一個(gè)數(shù)組類型變量并初始化。

當(dāng)然,在使用的時(shí)候也可以把數(shù)組的聲明和初始化分開來寫,例如:

1)int[]a;//聲明一個(gè)數(shù)組類型的對(duì)象a

a=newint[5];//給數(shù)組a申請(qǐng)可以存儲(chǔ)5個(gè)int類型大小的空間,默認(rèn)值為0

2)int[]a;//聲明一個(gè)數(shù)組類型的對(duì)象a

a=newint[]{1,2,3,4,5};//給數(shù)組申請(qǐng)存儲(chǔ)空間,并初始化為默認(rèn)值

以上主要介紹了一維數(shù)組的聲明與初始化的方式,下面介紹二維數(shù)組的聲明與初始化的方式,二維數(shù)組有3種聲明的方法:

1)typearrayName[][];

2)type[][]arrayName;

3)type[]arrayName[];

其中[]必須為空。

二維數(shù)組也可以用初始化列表的方式來進(jìn)行初始化,它的一般形式為:

typearrayName[][]={{c11,c12,c13...},{c21,c22,c23...},{c31,c32,c33...}...};

也可以通過new關(guān)鍵字來給數(shù)組申請(qǐng)存儲(chǔ)空間:

typearrayname[][]=newtype[行數(shù)][列數(shù)]

與C/C++語言不同的是,在Java語言中,二維數(shù)組的第二維的長(zhǎng)度可以不同。假如要定義一個(gè)二維數(shù)組有兩行,第一行有兩列,第二行有三列,定義方法如下:

1)int[][]arr={{12},{345}};

2)int[][]a=newint[2][];

a[0]=newint[]{1,2};

a[1]=newint[]{3,4,5);

對(duì)二維數(shù)組的訪問也是通過下標(biāo)來完成的,一般形式為arryName[行號(hào)][列號(hào)],下例介紹二維數(shù)組的遍歷方法。

publicclassTest

{

publicstaticvoidmain(String[]args)

{

inta[][]=newint[2][];

a[0]=newint[]{1,2};

a[1]=newint[]{3,4,5};

for(inti=0;i<a.length;i++)

{

for(intj=0;j<a[i].length;j++)

System.out.print(a[i][j]+"");

}

}

}

程序運(yùn)行結(jié)果為:

12345

11.

Java如何實(shí)現(xiàn)類似于C語言中函數(shù)指針的功能?正確答案:在C語言中,有一個(gè)非常重要的概念:函數(shù)指針,其最重要的功能是實(shí)現(xiàn)回調(diào)函數(shù)。什么是回調(diào)函數(shù)呢?所謂回調(diào)函數(shù),就是指函數(shù)先在某處注冊(cè),而它將在稍后某個(gè)需要的時(shí)候被調(diào)用。在Windows系統(tǒng)中,開發(fā)人員想讓系統(tǒng)DLL(DynamicLinkLibrary,動(dòng)態(tài)鏈接庫(kù))調(diào)用自己編寫的一個(gè)方法,于是利用DLL當(dāng)中回調(diào)函數(shù)的接口來編寫程序,通過傳遞一個(gè)函數(shù)的指針來被調(diào)用,這個(gè)過程就稱為回調(diào)?;卣{(diào)函數(shù)一般用于截獲消息、獲取系統(tǒng)信息或處理異步事件。舉一個(gè)簡(jiǎn)單例子,程序員A寫了一段程序a,其中預(yù)留有回調(diào)函數(shù)接口,并封裝好了該程序。程序員B要讓a調(diào)用自己的程序b中的一個(gè)方法,于是,他通過a中的接口回調(diào)屬于自己的程序b中的方法。

函數(shù)指針一般作為函數(shù)的參數(shù)來使用,開發(fā)人員在使用的時(shí)候可以根據(jù)自己的需求傳遞自定義的函數(shù)來實(shí)現(xiàn)指定的功能。例如:在實(shí)現(xiàn)排序算法的時(shí)候,可以通過傳遞一個(gè)函數(shù)指針來決定兩個(gè)數(shù)的先后順序,從而最終決定該算法是按升序還是降序排列。

由于在Java語言中沒有指針的概念,那么如何才能實(shí)現(xiàn)類似于函數(shù)指針的功能呢?可以利用接口與類來實(shí)現(xiàn)同樣的效果。具體而言,首先定義一個(gè)接口,然后在接口中聲明要調(diào)用的方法,接著實(shí)現(xiàn)這個(gè)接口,最后把這個(gè)實(shí)現(xiàn)類的一個(gè)對(duì)象作為參數(shù)傳遞給調(diào)用程序,調(diào)用程序通過這個(gè)參數(shù)來調(diào)用指定的方法,從而實(shí)現(xiàn)回調(diào)函數(shù)的功能。如下例所示:

//接口中定義了一個(gè)用來比較大小的方法

interfaceIntCompare

{

publicintcmp(inta,intb);

}

classCmp1implementsIntCompare

{

publicintcmp(inta,intb){

if(a>b)

return1;

elseif(a<b)

return-1;

else

return0;

}

}

classCmp2implementsIntCompare

{

publicintcmp(inta,intb)

{

if(a>b)

return-1;

elseif(a<b)

return1;

else

return0;

}

}

publicclassTest

{

publicstaticvoidinsertSort(int[]a,IntComparecmp)

{

if(a!=null)

{

for(inti=1;i<a.length;i++)

{

inttemp=a[i],j=i;

if(cmp.cmp(a[j-1],temp)==1)

{

while(j>=1&&cmp.cmp(a[j-1],temp)==1)

{

a[j]=a[j-1];

j--;

}

}

a[j]=temp;

}

}

}

publicstaticvoidmain(String[]args)

{

int[]array1={7,3,19,40,4,7,1};

insertSort(array1,newCmp1());

System.out.print("升序排列:");

for(inti=0;i<array1.length;i++)

System.out.print(array1[i]+"");

System.out.println();

int[]array2={7,3,19,40,4,7,1};

insertSort(array2,newCmp2());

System.out.print("降序排列:");

for(inti=0;i<array2.length;i++)

System.out.print(array2[i]+"");

}

}

程序運(yùn)行結(jié)果為:

升序排列:134771940

降序排列:401977431

在上例中,定義了一個(gè)用來比較大小的接口IntCompare,這個(gè)接口實(shí)際上充當(dāng)了C語言中函數(shù)指針的功能,在使用的時(shí)候,開發(fā)人員可以根據(jù)實(shí)際需求傳入自定義的類。在上例中分別有兩個(gè)類Cmp1和Cmp2都實(shí)現(xiàn)了這個(gè)接口,分別用來在實(shí)現(xiàn)升序排序和降序排序的時(shí)候使用。其實(shí)這也是策略設(shè)計(jì)模式所用到的思想。

12.

如何實(shí)現(xiàn)無符號(hào)數(shù)右移操作?正確答案:Java提供了兩種右移運(yùn)算符:“>>”和“>>>”。其中,“>>”被稱為有符號(hào)右移運(yùn)算符,“>>>”被稱為無符號(hào)右移運(yùn)算符,它們的功能是將參與運(yùn)算的對(duì)象對(duì)應(yīng)的二進(jìn)制數(shù)右移指定的位數(shù)。不同點(diǎn)在于“>>”在執(zhí)行右移操作的時(shí)候,如果參與運(yùn)算的數(shù)字為正數(shù)時(shí),則在高位補(bǔ)0,若為負(fù)數(shù)則在高位補(bǔ)1。而“>>>”則不同,無論參與運(yùn)算的值為正或?yàn)樨?fù),都會(huì)在高位補(bǔ)0。

此外,需要特別注意的是,對(duì)于char、byte、short等類型的數(shù)進(jìn)行移位操作前,都會(huì)自動(dòng)將數(shù)值轉(zhuǎn)化為int型,然后才進(jìn)行移位操作,由于int型變量只占4個(gè)字節(jié)(32位),因此當(dāng)右移的位數(shù)超過32時(shí),移位運(yùn)算沒有任何意義。所以,在Java語言中,為了保證移動(dòng)位數(shù)的有效性,使得右移的位數(shù)不超過32,采用了取余的操作,即a>>n等價(jià)于a>>(n%32)。如下例所示:

publicclassTest

{

publicstaticvoidmain(String[]a)

{

inti=-4;

System.out.println("----int>>:"+i);

System.out.println("移位前二進(jìn)制:"+Integer.toBinaryString(i));

i>>=1;

System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(i));

System.out.println("----int>>:"+i);

i=-4;

System.out.println("----int>>>:"+i);

System.out.println("移位前二進(jìn)制:"+Integer.toBinaryString(i));

i>>>=1;

System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(i));

System.out.println("----int>>>:"+i);

shortj=-4;

System.out.println("----short>>>:"+j);

System.out.println("移位前二進(jìn)制:"+Integer.toBinaryString(j));

j>>>=1;

System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(j));

System.out.println("----short>>>:"+j);

i=5;

System.out.println("----int>>:"+i);

System.out.println("移位前二進(jìn)制:"+Integer.toBinaryString(i));

i>>=32;

System.out.println("移位后二進(jìn)制:"+Integer.toBinaryString(i));

System.out.println("----int>>:"+i);

}

}

程序運(yùn)行結(jié)果為:

----int>>:-4

移位前二進(jìn)制:11111111111111111111111111111100

移位后二進(jìn)制:11111111111111111111111111111110

----int>>:-2

----int>>>:-4

移位前二進(jìn)制:11111111111111111111111111111100

移位后二進(jìn)制:1111111111111111111111111111110

----int>>>:2147483646

----short>>>:-4

移位前二進(jìn)制:11111111111111111111111111111100

移位后二進(jìn)制:11111111111111111111111111111110

----short>>>:-2

----int>>:5

移位前二進(jìn)制:101

移位后二進(jìn)制:101

----int>>:5

需要特別說明的是,對(duì)于short類型來說,由于short只占兩字節(jié),在移位操作的時(shí)候會(huì)先轉(zhuǎn)換為int類型,雖然在進(jìn)行無符號(hào)右移的時(shí)候會(huì)在高位補(bǔ)1,當(dāng)把運(yùn)算結(jié)果再賦值給short類型的時(shí)候,只會(huì)取其中低位的兩個(gè)字節(jié),因此,高位無論補(bǔ)0還是補(bǔ)1對(duì)運(yùn)算結(jié)果無影響。在上例中,-4的二進(jìn)制表示為1111111111111100(負(fù)數(shù)以補(bǔ)碼格式存儲(chǔ)),在轉(zhuǎn)換為二進(jìn)制的時(shí)候會(huì)以4字節(jié)的方式輸出,高位會(huì)補(bǔ)1,因此輸出為11111111111111111111111111111100,在執(zhí)行無符號(hào)數(shù)右移后其二進(jìn)制變?yōu)?1111111111111111111111111111110,當(dāng)把運(yùn)算結(jié)果再?gòu)?fù)制給i的時(shí)候只會(huì)取低位的兩個(gè)字節(jié),因此,運(yùn)算結(jié)果的二進(jìn)制表示為1111111111111110,對(duì)應(yīng)的十進(jìn)制值為-2,當(dāng)把-2以二進(jìn)制形式輸出的時(shí)候,同理會(huì)以4字節(jié)的方式輸出,高位會(huì)補(bǔ)1,因此輸出為11111111111111111111111111111110。

13.

多態(tài)的實(shí)現(xiàn)機(jī)制是什么?正確答案:多態(tài)是面向?qū)ο蟪绦蛟O(shè)計(jì)中代碼重用的一個(gè)重要機(jī)制,它表示當(dāng)同一個(gè)操作作用在不同的對(duì)象的時(shí)候,會(huì)有不同的語義,從而會(huì)產(chǎn)生不同的結(jié)果。例如:同樣是“+”操作,3+4用來實(shí)現(xiàn)整數(shù)相加,而“3”+“4”卻實(shí)現(xiàn)了字符串的連接。在Java語言中,多態(tài)主要有以下兩種表現(xiàn)方式。

1)重載(Overload)

重載是指同一個(gè)類中有多個(gè)同名的方法,但這些方法有著不同的參數(shù),因此可以在編譯的時(shí)候就可以確定到底調(diào)用哪個(gè)方法,它是一種編譯時(shí)多態(tài)。重載可以被看作一個(gè)類中的方法多態(tài)性。

2)重寫(Override)

子類可以重寫父類的方法,因此同樣的方法會(huì)在父類與子類中有著不同的表現(xiàn)形式。在Java語言中,基類的引用變量不僅可以指向基類的實(shí)例對(duì)象,也可以指向其子類的實(shí)例對(duì)象。同樣,接口的引用變量也可以指向其實(shí)現(xiàn)類的實(shí)例對(duì)象。而程序調(diào)用的方法在運(yùn)行期才動(dòng)態(tài)綁定(綁定指的是將一個(gè)方法調(diào)用和一個(gè)方法主體連接到一起),就是引用變量所指向的具體實(shí)例對(duì)象的方法,也就是內(nèi)存里正在運(yùn)行的那個(gè)對(duì)象的方法,而不是引用變量的類型中定義的方法。通過這種動(dòng)態(tài)綁定的方法實(shí)現(xiàn)了多態(tài)。由于只有在運(yùn)行時(shí)才能確定調(diào)用哪個(gè)方法,因此通過方法重寫實(shí)現(xiàn)的多態(tài)也可以被稱為運(yùn)行時(shí)多態(tài)。如下例所示:

classBase

{

publicBase()

{

g();

}

publicvoidf()

{

System.out.println("Basef()");

}

publicvoidg()

{

System.out.println("Baseg()");

}

}

classDerivedextendsBase

{

publicvoidf()

{

System.out.println("Derivedf()");

}

publicvoidg()

{

System.out.println("Derivedg()");

}

}

publicclassTest

{

publicstaticvoidmain(String[]args)

{

Baseb=newDerived();

b.f();

b.g();

}

}

程序的輸出結(jié)果為:

Derivedg()

Derivedf()

Derivedg()

上例中,由于子類Derived的f()方法和g()方法與父類Base的方法同名,因此Derived的方法會(huì)覆蓋Base的方法。在執(zhí)行Baseb=newDerived()語句的時(shí)候,會(huì)調(diào)用Base類的構(gòu)造函數(shù),而在Base的構(gòu)造函數(shù)中,執(zhí)行了g()方法,由于Java語言的多態(tài)特性,此時(shí)會(huì)調(diào)用子類Derived的g()方法,而非父類Base的g()方法,因此會(huì)輸出Derivedg()。由于實(shí)際創(chuàng)建的是Derived類的對(duì)象,后面的方法調(diào)用都會(huì)調(diào)用子類Derived的方法。

此外,只有類中的方法才有多態(tài)的概念,類中成員變量沒有多態(tài)的概念。如下例所示:

classBase

{

publicinti=1;

}

classDerivedextendsBase

{

publicinti=2;

}

publicclassTest

{

publicstaticvoidmain(String[]args)

{

Baseb=newDerived();

System.out.println(b.i);

}

}

程序輸出結(jié)果為:

1

由此可見,成員變量是無法實(shí)現(xiàn)多態(tài)的,成員變量的值取父類還是子類并不取決于創(chuàng)建對(duì)象的類型,而是取決于定義的變量的類型。這是在編譯期間確定的。在上例中,由于b所屬的類型為Base,b.i指的是Base類中定義的i,所以程序輸出結(jié)果為1。

14.

什么是構(gòu)造方法?正確答案:構(gòu)造方法是一種特殊的方法,用來在對(duì)象實(shí)例化時(shí)初始化對(duì)象的成員變量。在Java語言中,構(gòu)造方法具有以下特點(diǎn)。

1)構(gòu)造方法必須與類的名字相同,并且不能有返回值(返回值也不能為void)。

2)每個(gè)類可以有多個(gè)構(gòu)造方法。當(dāng)開發(fā)人員沒有提供構(gòu)造方法的時(shí)候,編譯器在把源代碼編譯成字節(jié)碼的過程中會(huì)提供一個(gè)沒有參數(shù)默認(rèn)的構(gòu)造方法,但該構(gòu)造方法不會(huì)執(zhí)行任何代碼。如果開發(fā)人員提供了構(gòu)造方法,那么編譯器就不會(huì)再創(chuàng)建默認(rèn)的構(gòu)方法數(shù)了。

3)構(gòu)造方法可以有0個(gè)、1個(gè)或1個(gè)以上的參數(shù)。

4)構(gòu)造方法總是伴隨著new操作一起調(diào)用,不能由程序的編寫者直接調(diào)用,必須要由系統(tǒng)調(diào)用。構(gòu)造方法在對(duì)象實(shí)例化的時(shí)候會(huì)被自動(dòng)調(diào)用,且只運(yùn)行一次,而普通的方法是在程序執(zhí)行到它的時(shí)候被調(diào)用的,可以被該對(duì)象調(diào)用多次。

5)構(gòu)造方法的主要作用是完成對(duì)象的初始化工作。

6)構(gòu)造方法不能被繼承,因此就不能被重寫(Override),但是構(gòu)造方法能夠被重載,可以使用不同的參數(shù)個(gè)數(shù)或參數(shù)類型來定義多個(gè)構(gòu)造方法。

7)子類可以通過super關(guān)鍵字來顯式地調(diào)用父類的構(gòu)造方法,當(dāng)父類沒有提供無參數(shù)的構(gòu)造方法時(shí),子類的構(gòu)造方法中必須顯示地調(diào)用父類的構(gòu)造方法,如果父類中提供了無參數(shù)的構(gòu)造方法,此時(shí)子類的構(gòu)造方法就可以不顯式地調(diào)用父類的構(gòu)造方法,在這種情況下編譯器會(huì)默認(rèn)調(diào)用父類的無參數(shù)的構(gòu)造方法。當(dāng)有父類時(shí),在實(shí)例化對(duì)象時(shí)會(huì)首先執(zhí)行父類的構(gòu)造方法,然后才執(zhí)行子類的構(gòu)造方法。

8)當(dāng)父類和子類都沒有定義構(gòu)造方法的時(shí)候,編譯器會(huì)為父類生成一個(gè)默認(rèn)的無參數(shù)的構(gòu)造方法,給子類也生成一個(gè)默認(rèn)的無參數(shù)的構(gòu)造方法。此外,默認(rèn)構(gòu)造器的修飾符只跟當(dāng)前類的修飾符有關(guān)(例如:如果一個(gè)類被定義為public,那么它的構(gòu)造方法也是public)。

15.

static與final結(jié)合使用表示什么意思?正確答案:static常與final關(guān)鍵字結(jié)合使用,用來修飾成員變量與成員方法,有點(diǎn)類似于“全局常量”。對(duì)于變量,如果使用staticfinal修飾,則表示一旦賦值,就不可修改,并且通過類名可以訪問。對(duì)于方法,如果使用staticfinal修飾,則表示方法不可覆蓋,并且可以通過類名直接訪問。

16.

Java語言中是否存在goto關(guān)鍵字?正確答案:雖然goto作為Java的保留字,但目前沒有在Java中使用。在C/C++中,goto常被用作跳出多重循環(huán),在Java語言中,可以使用break和continue來達(dá)到同樣的效果。那么既然goto沒有在Java語言中使用,為什么還要作為保留字呢?其中一個(gè)可能的原因就是這個(gè)關(guān)鍵字有可能會(huì)在將來被使用。如果現(xiàn)在不把goto作為保留字,開發(fā)人員就有可能用goto作為變量名來使用。一旦有一天Java支持goto關(guān)鍵字了,這會(huì)導(dǎo)致以前的程序無法正常運(yùn)行。因此把goto作為保留字是非常有必要的。

這里需要注意的是,在Java語言中,雖然沒有g(shù)oto語句,但是卻能使用標(biāo)識(shí)符加冒號(hào)(:)的形式定義標(biāo)簽,如“mylabel:”,其目的主要是為了在多重循環(huán)中方便使用break和continue而設(shè)計(jì)的。

17.

volatile有什么作用?正確答案:volatile的使用是為了線程安全,但volatile不保證線程安全。線程安全有3個(gè)要素:可見性、有序性、原子性。線程安全是指在多線程情況下,對(duì)共享內(nèi)存的使用,不會(huì)因?yàn)椴煌€程的訪問和修改而發(fā)生不期望的情況。

volatile有3個(gè)作用:

1)volatile用于解決多核CPU高速緩存導(dǎo)致的變量不同步。

本質(zhì)上這是個(gè)硬件問題,其根源在于:CPU的高速緩存的讀取速度遠(yuǎn)遠(yuǎn)快于主存(物理內(nèi)存)。所以,CPU在讀取一個(gè)變量的時(shí)候,會(huì)把數(shù)據(jù)先讀取到緩存,這樣下次再訪問同一個(gè)數(shù)據(jù)的時(shí)候就可以直接從緩存讀取了,顯著提高了讀取的性能。而多核CPU有多個(gè)這樣的緩存。這就帶來了問題,當(dāng)某個(gè)CPU(例如CPU1)修改了這個(gè)變量(例如把a(bǔ)的值從1修改為2),但是其他的CPU(例如CPU2)在修改前已經(jīng)把a(bǔ)=1讀取到自己的緩存了,當(dāng)CPU2再次讀取數(shù)據(jù)的時(shí)候,它仍然會(huì)去自己的緩存區(qū)中去讀取,此時(shí)讀取到的值仍然是1,但是實(shí)際上這個(gè)值已經(jīng)變成2了。這里,就涉及線程安全的要素:可見性。

可見性是指當(dāng)多個(gè)線程在訪問同一個(gè)變量時(shí),如果其中一個(gè)線程修改了變量的值,那么其他線程應(yīng)該能立即看到修改后的值。

volatile的實(shí)現(xiàn)原理是內(nèi)存屏障(MemoryBarrier),其原理為:當(dāng)CPU寫數(shù)據(jù)時(shí),如果發(fā)現(xiàn)一個(gè)變量在其他CPU中存有副本,那么會(huì)發(fā)出信號(hào)量通知其他CPU將該副本對(duì)應(yīng)的緩存行置為無效狀態(tài),當(dāng)其他CPU讀取到變量副本的時(shí)候,會(huì)發(fā)現(xiàn)該緩存行是無效的,然后,它會(huì)從主存重新讀取。

2)volatile還可以解決指令重排序的問題。

在一般情況下,程序是按照順序執(zhí)行的,例如下面的代碼:

1、inti=0;

2、i++;

3、booleanf=false;

4、f=true;

如果i++發(fā)生在inti=0之前,那么會(huì)不可避免的出錯(cuò),CPU在執(zhí)行代碼對(duì)應(yīng)指令的時(shí)候,會(huì)認(rèn)為1、2兩行是具備依賴性的,因此,CPU一定會(huì)安排行1早于行2執(zhí)行。

那么,inti=0一定會(huì)早于booleanf=false嗎?

并不一定,CPU在運(yùn)行期間會(huì)對(duì)指令進(jìn)行優(yōu)化,沒有依賴關(guān)系的指令,它們的順序可能會(huì)被重排。在單線程執(zhí)行下,發(fā)生重排是沒有問題的,CPU保證了順序不一定一致,但結(jié)果一定一致。

但在多線程環(huán)境下,重排序則會(huì)引起很大的問題,這又涉及線程安全的要素:有序性。

有序性是指程序執(zhí)行的順序應(yīng)當(dāng)按照代碼的先后順序執(zhí)行。

為了更好地理解有序性,下面通過一個(gè)例子來分析:

//成員變量i

inti=0;

//線程一的執(zhí)行代碼

Thread.sleep(10);

i++;

f=true;

//線程二的執(zhí)行代碼

while(!f)

{

System.out.println(i);

}

理想的結(jié)果應(yīng)該是線程二不停地打印0,最后打印一個(gè)1,終止。

在線程一里,f和i沒有依賴性,如果發(fā)生了指令重排,那么f=true發(fā)生在i++之前,就有可能導(dǎo)致線程二在終止循環(huán)前輸出的全部是0。

需要注意的是,這種情況并不常見,再次運(yùn)行并不一定能重現(xiàn),正因?yàn)槿绱?,很可能?huì)導(dǎo)致一些莫名的問題,需要特別注意。如果修改上方代碼中i的定義為使用volatile關(guān)鍵字來修飾,那么就可以保證最后的輸出結(jié)果符合預(yù)期。這是因?yàn)楸籿olatile修飾的變量,CPU不會(huì)對(duì)它做重排序優(yōu)化,所以也就保證了有序性。

3)volatile不保證操作的原子性。

原子性:一個(gè)或多個(gè)操作,要么全部連續(xù)執(zhí)行且不會(huì)被任何因素中斷,要么就都不執(zhí)行。這個(gè)概念和數(shù)據(jù)庫(kù)概念里的事務(wù)(Transaction)很類似,沒錯(cuò),事務(wù)就是一種原子性操作。

原子性、可見性和有序性,是線程安全的三要素。

需要特別注意的是,volatile保證線程安全的可見性和有序性,但是不保證操作的原子性,下面的代碼將會(huì)證明這一點(diǎn):

staticvolatileintintVal=0;

publicstaticvoidmain(String[]args)

{

//創(chuàng)建10個(gè)線程,執(zhí)行簡(jiǎn)單的自加操作

for(inti=0;i<10;i++)

{

newThread(()->

{

for(intj=0;j<1000;j++)

intVal++;

}).stan();

}

//保證之前啟動(dòng)的全部線程執(zhí)行完畢

while(Thread.activeCount()>1)

Thread.yield();

System.out.println(intVal);

}

在之前的內(nèi)容有提及,volatile能保證修改后的數(shù)據(jù)對(duì)所有線程可見,那么,這一段對(duì)intVal自增的代碼,最終執(zhí)行完畢的時(shí)候,intVal應(yīng)該為10000。

但事實(shí)上,結(jié)果是不確定的,大部分情況下會(huì)小于10000。這是因?yàn)?,無論是volatile還是自增操作,都不具備原子性。

假設(shè)intVal初始值為100,自增操作的指令執(zhí)行順序如下所示:

1)獲取intVal值,此時(shí)主存內(nèi)intVal值為100;

2)intVal執(zhí)行+1,得到101,此時(shí)主存內(nèi)intVal值仍然為100;

3)將101寫回給intVal,此時(shí)主存內(nèi)intVal值從100變化為101。

具體執(zhí)行流程如下圖所示。

自增操作的實(shí)現(xiàn)原理

這個(gè)過程很容易理解,如果這段指令發(fā)生在多線程環(huán)境下呢?以下面這段會(huì)發(fā)生錯(cuò)誤的指令順序?yàn)槔?/p>

1)線程一獲得了intVal值為100;

2)線程一執(zhí)行+1,得到101,此時(shí)值沒有寫回給主存;

3)線程二在主存內(nèi)獲得了intVal值為100;

4)線程二執(zhí)行+1,得到101;

5)線程一寫回101;

6)線程二寫回101。

于是,最終主存內(nèi)的intVal值,還是101。具體執(zhí)行流程如下圖所示。

多線程執(zhí)行自增操作的結(jié)果

為什么volatile的可見性保證在這里沒有生效?

根據(jù)volatile保證可見性的原理(內(nèi)存屏障),當(dāng)一個(gè)線程執(zhí)行寫的時(shí)候,才會(huì)改變“數(shù)據(jù)修改”的標(biāo)量,在上述過程中,線程A在執(zhí)行加法操作發(fā)生后,寫回操作發(fā)生前,CPU開始處理線程B的時(shí)間片,執(zhí)行了另外一次讀取intVal,此時(shí)intVal值為100,且由于寫回操作尚未發(fā)生,這一次讀取是成功的。

因此,出現(xiàn)了最后計(jì)算結(jié)果不符合預(yù)期的情況。

synchoronized關(guān)鍵字確實(shí)可以解決多線程的原子操作問題,可以修改上面的代碼為:

for(inti=0;i<10;i++)

{

newThread(()->{

synchronized(lock){

for(intj=0;j<1000;j++)

intVal++;

}

}).start();

}

但是,這種方式明顯效率不高(后面會(huì)介紹如何通過CAS來保證原子性),10個(gè)線程都在爭(zhēng)搶同一個(gè)代碼塊的使用權(quán)。

由此可見,volatile只能提供線程安全的兩個(gè)必要條件:可見性和有序性。

18.

JavaCollections框架是什么?正確答案:容器在Java語言開發(fā)中有著非常重要的作用,Java提供了多種類型的容器來滿足開發(fā)的需要,容器不僅在面試,在筆試中也是非常重要的一個(gè)知識(shí)點(diǎn),在實(shí)際開發(fā)的過程中也是經(jīng)常會(huì)用到。因此,對(duì)容器的掌握是非常有必要也是非常重要的。Java中的容器可以被分為以下兩類。

(1)Collection

用來存儲(chǔ)獨(dú)立的元素,其中包括List、Set和Queue。其中List是按照插入的順序保存元素,Set中不能有重復(fù)的元素,而Queue按照排隊(duì)規(guī)則來處理容器中的元素。它們之間的關(guān)系如圖1所示。

圖1

Collection類圖

(2)Map

用來存儲(chǔ)鍵值對(duì),這個(gè)容器允許通過鍵來查找值。Map也有多種實(shí)現(xiàn)類,如圖2所示。

圖2

Map類圖

JavaCollections框架中包含了大量集合接口以及這些接口的實(shí)現(xiàn)類和操作它們的算法(例如排序、查找、反轉(zhuǎn)、替換、復(fù)制、取最小元素、取最大元素等),具體而言,主要提供了List(列表)、Queue(隊(duì)列)、Set(集合)、Stack(棧)和

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論