1. 簡(jiǎn)單說(shuō)下什么是跨平臺(tái)
術(shù)語(yǔ):操作系統(tǒng)指令集懂从、屏蔽系統(tǒng)之間的差異
由于各種操作系統(tǒng)所支持的指令集不是完全一致街州,所以在操作系統(tǒng)之上加個(gè)虛擬機(jī)可以來(lái)提供統(tǒng)一接口懈费,屏蔽系統(tǒng)之間的差異羹饰。
2. Java有幾種基本數(shù)據(jù)類(lèi)型
有八種基本數(shù)據(jù)類(lèi)型孝冒。
數(shù)據(jù)類(lèi)型字節(jié)默認(rèn)值
byte10
short20
int40
long80
float40.0f
double80.0d
char2'\u0000'
boolean4false
各自占用幾字節(jié)也記一下尊惰。
3. 面向?qū)ο筇卣?/p>
面向?qū)ο蟮木幊陶Z(yǔ)言有封裝讲竿、繼承 、抽象择浊、多態(tài)等4個(gè)主要的特征戴卜。
封裝: 把描述一個(gè)對(duì)象的屬性和行為的代碼封裝在一個(gè)模塊中,也就是一個(gè)類(lèi)中琢岩,屬性用變量定義投剥,行為用方法進(jìn)行定義,方法可以直接訪問(wèn)同一個(gè)對(duì)象中的屬性担孔。
抽象: 把現(xiàn)實(shí)生活中的對(duì)象抽象為類(lèi)江锨。分為過(guò)程抽象和數(shù)據(jù)抽象
數(shù)據(jù)抽象 -->鳥(niǎo)有翅膀,羽毛等(類(lèi)的屬性)
過(guò)程抽象 -->鳥(niǎo)會(huì)飛,會(huì)叫(類(lèi)的方法)
繼承:子類(lèi)繼承父類(lèi)的特征和行為。子類(lèi)可以有父類(lèi)的方法糕篇,屬性(非private)啄育。子類(lèi)也可以對(duì)父類(lèi)進(jìn)行擴(kuò)展,也可以重寫(xiě)父類(lèi)的方法拌消。缺點(diǎn)就是提高代碼之間的耦合性挑豌。
多態(tài): 多態(tài)是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定(比如:向上轉(zhuǎn)型,只有運(yùn)行才能確定其對(duì)象屬性)氓英。方法覆蓋和重載體現(xiàn)了多態(tài)性侯勉。
4. 為什么要有包裝類(lèi)型
術(shù)語(yǔ):讓基本類(lèi)型也具有對(duì)象的特征
基本類(lèi)型包裝器類(lèi)型
booleanBoolean
charCharacter
intInteger
byteByte
shortShort
longLong
floatFloat
doubleDouble
為了讓基本類(lèi)型也具有對(duì)象的特征,就出現(xiàn)了包裝類(lèi)型(如我們?cè)谑褂眉项?lèi)型Collection時(shí)就一定要使用包裝類(lèi)型而非基本類(lèi)型)因?yàn)槿萜鞫际茄bobject的铝阐,這是就需要這些基本類(lèi)型的包裝器類(lèi)了址貌。
自動(dòng)裝箱:new Integer(6);,底層調(diào)用:Integer.valueOf(6)
自動(dòng)拆箱:int i = new Integer(6);徘键,底層調(diào)用i.intValue();方法實(shí)現(xiàn)练对。
Integeri??=6;
Integerj?=6;
System.out.println(i==j);
答案在下面這段代碼中找:
publicstaticIntegervalueOf(inti){
if(i?>=?IntegerCache.low?&&?i?<=?IntegerCache.high)
returnIntegerCache.cache[i?+?(-IntegerCache.low)];
returnnewInteger(i);
}
二者的區(qū)別:
聲明方式不同:基本類(lèi)型不使用new關(guān)鍵字,而包裝類(lèi)型需要使用new關(guān)鍵字來(lái)在堆中分配存儲(chǔ)空間吹害;
存儲(chǔ)方式及位置不同:基本類(lèi)型是直接將變量值存儲(chǔ)在棧中螟凭,而包裝類(lèi)型是將對(duì)象放在堆中,然后通過(guò)引用來(lái)使用它呀;
初始值不同:基本類(lèi)型的初始值如int為0赂摆,boolean為false,而包裝類(lèi)型的初始值為null钟些;
使用方式不同:基本類(lèi)型直接賦值直接使用就好,而包裝類(lèi)型在集合如Collection绊谭、Map時(shí)會(huì)使用到政恍。
5. ==和equals區(qū)別
==較的是兩個(gè)引用在內(nèi)存中指向的是不是同一對(duì)象(即同一內(nèi)存空間),也就是說(shuō)在內(nèi)存空間中的存儲(chǔ)位置是否一致达传。如果兩個(gè)對(duì)象的引用相同時(shí)(指向同一對(duì)象時(shí))篙耗,“==”操作符返回true,否則返回flase宪赶。
equals用來(lái)比較某些特征是否一樣宗弯。我們平時(shí)用的String類(lèi)等的equals方法都是重寫(xiě)后的,實(shí)現(xiàn)比較兩個(gè)對(duì)象的內(nèi)容是否相等搂妻。
我們來(lái)看看String重寫(xiě)的equals方法:
它不止判斷了內(nèi)存地址蒙保,還增加了字符串是否相同的比較。
publicbooleanequals(Object?anObject){
//判斷內(nèi)存地址是否相同
if(this==?anObject)?{
returntrue;
}
//?判斷參數(shù)類(lèi)型是否是String類(lèi)型
if(anObject?instanceof?String)?{
//?強(qiáng)轉(zhuǎn)
String?anotherString?=?(String)anObject;
intn?=value.length;
//?判斷兩個(gè)字符串長(zhǎng)度是否相等
if(n?==?anotherString.value.length)?{
charv1[]?=value;
charv2[]?=?anotherString.value;
inti?=0;
//?一一比較?字符是否相同
while(n--?!=0)?{
if(v1[i]?!=?v2[i])
returnfalse;
i++;
}
returntrue;
}
}
returnfalse;
}
6. String欲主、StringBuffer和StringBuilder區(qū)別
java中String邓厕、StringBuffer、StringBuilder是編程中經(jīng)常使用的字符串類(lèi)扁瓢,他們之間的區(qū)別也是經(jīng)常在面試中會(huì)問(wèn)到的問(wèn)題∠昴眨現(xiàn)在總結(jié)一下,看看他們的不同與相同引几。
1. 數(shù)據(jù)可變和不可變
String底層使用一個(gè)不可變的字符數(shù)組private final char value[];所以它內(nèi)容不可變昧互。
StringBuffer和StringBuilder都繼承了AbstractStringBuilder底層使用的是可變字符數(shù)組:char[] value;
2. 線(xiàn)程安全
StringBuilder是線(xiàn)程不安全的,效率較高;而StringBuffer是線(xiàn)程安全的敞掘,效率較低叽掘。
通過(guò)他們的append()方法來(lái)看,StringBuffer是有同步鎖渐逃,而StringBuilder沒(méi)有:
@Override
publicsynchronizedStringBufferappend(Object?obj){
toStringCache?=null;
super.append(String.valueOf(obj));
returnthis;
}
@Override
publicStringBuilder?append(String?str)?{
super.append(str);
returnthis;
}
3. 相同點(diǎn)
StringBuilder與StringBuffer有公共父類(lèi)AbstractStringBuilder够掠。
最后,操作可變字符串速度:StringBuilder > StringBuffer > String茄菊,這個(gè)答案就顯得不足為奇了疯潭。
7. 講一下Java中的集合
Collection下:List系(有序、元素允許重復(fù))和Set系(無(wú)序面殖、元素不重復(fù))
set根據(jù)equals和hashcode判斷竖哩,一個(gè)對(duì)象要存儲(chǔ)在Set中,必須重寫(xiě)equals和hashCode方法
Map下:HashMap線(xiàn)程不同步脊僚;TreeMap線(xiàn)程同步
Collection系列和Map系列:Map是對(duì)Collection的補(bǔ)充相叁,兩個(gè)沒(méi)什么關(guān)系
8. ArrayList和LinkedList區(qū)別?
之前專(zhuān)門(mén)有寫(xiě)過(guò)ArrayList和LinkedList源碼的文章辽幌。
ArrayList是實(shí)現(xiàn)了基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu)增淹,LinkedList基于鏈表的數(shù)據(jù)結(jié)構(gòu)。
對(duì)于隨機(jī)訪問(wèn)get和set乌企,ArrayList覺(jué)得優(yōu)于LinkedList虑润,因?yàn)長(zhǎng)inkedList要移動(dòng)指針。
對(duì)于新增和刪除操作add和remove加酵,LinedList比較占優(yōu)勢(shì)拳喻,因?yàn)锳rrayList要移動(dòng)數(shù)據(jù)。
9. ConcurrentModificationException異常出現(xiàn)的原因
publicclassTest{
publicstaticvoidmain(String[]?args){
ArrayListlist=newArrayList();
list.add(2);
Iterator?iterator?=list.iterator();
while(iterator.hasNext()){
Integer?integer?=?iterator.next();
if(integer==2)
list.remove(integer);
}
}
}
執(zhí)行上段代碼是有問(wèn)題的猪腕,會(huì)拋出ConcurrentModificationException異常冗澈。
原因:調(diào)用list.remove()方法導(dǎo)致modCount和expectedModCount的值不一致。
finalvoidcheckForComodification(){
if(modCount?!=?expectedModCount)
thrownewConcurrentModificationException();
}
解決辦法:在迭代器中如果要?jiǎng)h除元素的話(huà)陋葡,需要調(diào)用Iterator類(lèi)的remove方法亚亲。
publicclassTest{
publicstaticvoidmain(String[]?args){
ArrayListlist=newArrayList();
list.add(2);
Iterator?iterator?=list.iterator();
while(iterator.hasNext()){
Integer?integer?=?iterator.next();
if(integer==2)
iterator.remove();//注意這個(gè)地方
}
}
}
10. HashMap和HashTable、ConcurrentHashMap區(qū)別腐缤?
相同點(diǎn):
HashMap和Hashtable都實(shí)現(xiàn)了Map接口
都可以存儲(chǔ)key-value數(shù)據(jù)
不同點(diǎn):
HashMap可以把null作為key或value朵栖,HashTable不可以
HashMap線(xiàn)程不安全,效率高柴梆。HashTable線(xiàn)程安全陨溅,效率低。
HashMap的迭代器(Iterator)是fail-fast迭代器绍在,而Hashtable的enumerator迭代器不是fail-fast的门扇。
什么是fail-fast?
就是最快的時(shí)間能把錯(cuò)誤拋出而不是讓程序執(zhí)行雹有。
10.2 如何保證線(xiàn)程安全又效率高?
Java 5提供了ConcurrentHashMap臼寄,它是HashTable的替代霸奕,比HashTable的擴(kuò)展性更好。
ConcurrentHashMap將整個(gè)Map分為N個(gè)segment(類(lèi)似HashTable)吉拳,可以提供相同的線(xiàn)程安全质帅,但是效率提升N倍,默認(rèn)N為16留攒。
10.3 我們能否讓HashMap同步煤惩?
HashMap可以通過(guò)下面的語(yǔ)句進(jìn)行同步:
Map m = Collections.synchronizeMap(hashMap);
11. 拷貝文件的工具類(lèi)使用字節(jié)流還是字符流
答案:字節(jié)流
11.1 什么是字節(jié)流,什么是字符流炼邀?
字節(jié)流:傳遞的是字節(jié)(二進(jìn)制)魄揉,
字符流:傳遞的是字符
11.2 答案
我們并不支持下載的文件有沒(méi)有包含字節(jié)流(圖片、影像拭宁、音源)洛退,所以考慮到通用性,我們會(huì)用字節(jié)流杰标。
12. 線(xiàn)程創(chuàng)建方式
這個(gè)之前自己做過(guò)總結(jié)兵怯,也算比較全面。
方法一:繼承Thread類(lèi)腔剂,作為線(xiàn)程對(duì)象存在(繼承Thread對(duì)象)
publicclassCreatThreadDemo1extendsThread{
/**
*?構(gòu)造方法:?繼承父類(lèi)方法的Thread(String?name)摇零;方法
*@paramname
*/
publicCreatThreadDemo1(String?name){
super(name);
}
@Override
publicvoidrun(){
while(!interrupted()){
System.out.println(getName()+"線(xiàn)程執(zhí)行了...");
try{
Thread.sleep(200);
}catch(InterruptedException?e)?{
e.printStackTrace();
}
}
}
publicstaticvoidmain(String[]?args){
CreatThreadDemo1?d1?=newCreatThreadDemo1("first");
CreatThreadDemo1?d2?=newCreatThreadDemo1("second");
d1.start();
d2.start();
d1.interrupt();//中斷第一個(gè)線(xiàn)程
}
}
常規(guī)方法,不多做介紹了桶蝎,interrupted方法,是來(lái)判斷該線(xiàn)程是否被中斷谅畅。(終止線(xiàn)程不允許用stop方法登渣,該方法不會(huì)施放占用的資源。所以我們?cè)谠O(shè)計(jì)程序的時(shí)候毡泻,要按照中斷線(xiàn)程的思維去設(shè)計(jì)胜茧,就像上面的代碼一樣)。
讓線(xiàn)程等待的方法
Thread.sleep(200); //線(xiàn)程休息2ms
Object.wait()仇味; //讓線(xiàn)程進(jìn)入等待呻顽,直到調(diào)用Object的notify或者notifyAll時(shí),線(xiàn)程停止休眠
方法二:實(shí)現(xiàn)runnable接口丹墨,作為線(xiàn)程任務(wù)存在
publicclassCreatThreadDemo2implementsRunnable{
@Override
publicvoidrun(){
while(true){
System.out.println("線(xiàn)程執(zhí)行了...");
}
}
publicstaticvoidmain(String[]?args){
//將線(xiàn)程任務(wù)傳給線(xiàn)程對(duì)象
Thread?thread?=newThread(newCreatThreadDemo2());
//啟動(dòng)線(xiàn)程
thread.start();
}
}
Runnable 只是來(lái)修飾線(xiàn)程所執(zhí)行的任務(wù)廊遍,它不是一個(gè)線(xiàn)程對(duì)象。想要啟動(dòng)Runnable對(duì)象贩挣,必須將它放到一個(gè)線(xiàn)程對(duì)象里喉前。
方法三:匿名內(nèi)部類(lèi)創(chuàng)建線(xiàn)程對(duì)象
publicclassCreatThreadDemo3extendsThread{
publicstaticvoidmain(String[]?args){
//創(chuàng)建無(wú)參線(xiàn)程對(duì)象
newThread(){
@Override
publicvoidrun(){
System.out.println("線(xiàn)程執(zhí)行了...");
}
}.start();
//創(chuàng)建帶線(xiàn)程任務(wù)的線(xiàn)程對(duì)象
newThread(newRunnable()?{
@Override
publicvoidrun(){
System.out.println("線(xiàn)程執(zhí)行了...");
}
}).start();
//創(chuàng)建帶線(xiàn)程任務(wù)并且重寫(xiě)run方法的線(xiàn)程對(duì)象
newThread(newRunnable()?{
@Override
publicvoidrun(){
System.out.println("runnable?run?線(xiàn)程執(zhí)行了...");
}
}){
@Override
publicvoidrun(){
System.out.println("override?run?線(xiàn)程執(zhí)行了...");
}
}.start();
}
}
創(chuàng)建帶線(xiàn)程任務(wù)并且重寫(xiě)run方法的線(xiàn)程對(duì)象中没酣,為什么只運(yùn)行了Thread的run方法。我們看看Thread類(lèi)的源碼卵迂,
裕便,我們可以看到Thread實(shí)現(xiàn)了Runnable接口,而Runnable接口里有一個(gè)run方法见咒。
所以偿衰,我們最終調(diào)用的重寫(xiě)的方法應(yīng)該是Thread類(lèi)的run方法。而不是Runnable接口的run方法改览。
方法四:創(chuàng)建帶返回值的線(xiàn)程
publicclassCreatThreadDemo4implementsCallable{
publicstaticvoidmain(String[]?args)throwsExecutionException,?InterruptedException{
CreatThreadDemo4?demo4?=newCreatThreadDemo4();
FutureTask?task?=newFutureTask(demo4);//FutureTask最終實(shí)現(xiàn)的是runnable接口
Thread?thread?=newThread(task);
thread.start();
System.out.println("我可以在這里做點(diǎn)別的業(yè)務(wù)邏輯...因?yàn)镕utureTask是提前完成任務(wù)");
//拿出線(xiàn)程執(zhí)行的返回值
Integer?result?=?task.get();
System.out.println("線(xiàn)程中運(yùn)算的結(jié)果為:"+result);
}
//重寫(xiě)Callable接口的call方法
@Override
publicObjectcall()throwsException{
intresult?=1;
System.out.println("業(yè)務(wù)邏輯計(jì)算中...");
Thread.sleep(3000);
returnresult;
}
}
Callable接口介紹:
publicinterfaceCallable{
/**
*?Computes?a?result,?or?throws?an?exception?if?unable?to?do?so.
*
*@returncomputed?result
*@throwsException?if?unable?to?compute?a?result
*/
Vcall()throwsException;
}
返回指定泛型的call方法下翎。然后調(diào)用FutureTask對(duì)象的get方法得道call方法的返回值。
方法五:定時(shí)器Timer
publicclassCreatThreadDemo5{
publicstaticvoidmain(String[]?args){
Timer?timer?=newTimer();
timer.schedule(newTimerTask()?{
@Override
publicvoidrun()
{
System.out.println("定時(shí)器線(xiàn)程執(zhí)行了...");
}
},0,1000);//延遲0恃疯,周期1s
}
}
方法六:線(xiàn)程池創(chuàng)建線(xiàn)程
publicclassCreatThreadDemo6{
publicstaticvoidmain(String[]?args){
//創(chuàng)建一個(gè)具有10個(gè)線(xiàn)程的線(xiàn)程池
ExecutorService?threadPool?=?Executors.newFixedThreadPool(10);
longthreadpoolUseTime?=?System.currentTimeMillis();
for(inti?=0;i<10;i++){
threadPool.execute(newRunnable()?{
@Override
publicvoidrun()
{
System.out.println(Thread.currentThread().getName()+"線(xiàn)程執(zhí)行了...");
}
});
}
longthreadpoolUseTime1?=?System.currentTimeMillis();
System.out.println("多線(xiàn)程用時(shí)"+(threadpoolUseTime1-threadpoolUseTime));
//銷(xiāo)毀線(xiàn)程池
threadPool.shutdown();
threadpoolUseTime?=?System.currentTimeMillis();
}
}
方法七:利用java8新特性 stream 實(shí)現(xiàn)并發(fā)
lambda表達(dá)式不懂的漏设,可以看看我的java8新特性文章:
java8-lambda:
http://www.reibang.com/p/3a08dc78a05f
java8-stream:
http://www.reibang.com/p/ea16d6712a00
publicclassCreatThreadDemo7{
publicstaticvoidmain(String[]?args){
List?values?=?Arrays.asList(10,20,30,40);
//parallel?平行的,并行的
intresult?=?values.parallelStream().mapToInt(p?->?p*2).sum();
System.out.println(result);
//怎么證明它是并發(fā)處理呢
values.parallelStream().forEach(p->?System.out.println(p));
}
}
輸出:
200
40
10
20
30
怎么證明它是并發(fā)處理呢,他們并不是按照順序輸出的 今妄。
文集介紹
該專(zhuān)題分為Java基礎(chǔ)郑口、計(jì)算機(jī)網(wǎng)絡(luò)、操作系統(tǒng)盾鳞、數(shù)據(jù)結(jié)構(gòu)犬性、算法精讀、數(shù)據(jù)庫(kù)面試題腾仅、框架面試題乒裆、服務(wù)高可用、分布式事務(wù)推励、分布式鎖鹤耍、消息隊(duì)列等部分,盡量將全網(wǎng)的面試題一網(wǎng)打盡验辞,方便大家手機(jī)閱讀和收藏稿黄。