Java基礎面試

1. 面向對象的三大特性

1) 封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。

2) 繼承,是指可以讓某個類型的對象獲得另一個類型的對象的屬性和方法。

3) 多態,是指一個類實例的相同方法在不同情形有不同表現形式。

2. 重載重寫

1) 重載是在同一個類中的兩個或兩個以上的方法,擁有相同的方法名,但是參數卻不相同,方法體也不相同,最常見的重載的例子就是類的構造函數。

兩同一不同原則:

兩同:同一個類,方法名相同;
不同:參數列表不同;

注意:方法的其它部分,比如方法的返回值類型、方法修飾符等都與方法重載沒有任何關係。

2) 重寫是子類的方法覆蓋父類的方法,要求方法名和參數都相同。

兩同兩小一大原則:

兩同:方法名相同、形參列表相同;
兩小:子類方法返回值類型小於父類方法返回值類型或相等;子類方法聲明拋出的異常類型應比父類方法聲明拋出的異常類型更小或相等。
一大:子類方法的訪問權限要大於等於父類方法的訪問權限。

注意: private修飾的相同方法不是被重寫了,而是另一個重新定義的方法,因爲private只對當前類可見。

3.常用Object類的方法

equals()方法

== 運算符

對於基本類型變量,如果兩者數值相同,則返回true。
對於引用類型變量,只有兩者指向同一個對象,才返回true。

Object默認提供的功能只是比較兩個對象的地址是否相同。通常需要重載equals()方法。

例如:在String類中就重載了equals()方法,用來判斷String對象包含的字符序列是否相同。

//比較嚴謹的重載equals()方法的實例如下
public boolean equals(Object obj) 
{
    //如果兩個對象爲同一個對象
    if (this == obj) {
        return true;
    }
    //getClass()獲得的是對象的運行時類型
    if (obj != null && obj.getClass() == Person.class) 
    {
        Person personObj = (Person)obj;
        //並且當前對象的idStr 與 obj對象的idStr 相等的時候纔可以判斷兩個對象是相等的
        if (this.getIdStr().equals(personObj.getIdStr()) 
        {
            return true;
        }
    }
    return false;
}

toString()方法

通常在打印對象信息時會使用到toString()方法,比如:

System.out.println(p);
//等價於
//輸出:Person@15db9742
//打印格式爲:類名+@+hashCode
System.out.println(p.toString);

通常需要重寫toString()方法,該方法總是會返回該對象的所有令人感興趣的信息所組成的字符串,可以返回如下格式的字符串:

類名[field1=值1, field2=值2,...]

hashCode()方法

hashCode()方法主要在集合中才會用到。

將對象放入集合中的步驟:

1) 首先判斷要放入對象的hashcode值與集合中的任意一個元素的hashcode值是否相等,如果不相等直接將該對象放入集合中。

2) 如果hashcode值相等,然後再通過equals方法判斷要放入對象與集合中的任意一個對象是否相等,如果equals判斷不相等,直接將該元素放入到集合中,否則不放入。

參考:hashCode與equals的區別與聯繫

finalize()方法

在垃圾回收機制回收某個對象佔用的內存之前,需要程序調用一定的方法來清理資源。而java提供了默認的機制來清理該對象的資源,該機制就是finalize()方法。

注意: 垃圾回收機制什麼時候調用對象的finalize()方法是完全透明的,只有當程序認爲需要更多的額外內存空間時,它才能夠進行垃圾回收的工作。也就是說finalize()方法是在垃圾回收之前執行的。

比如: 當一個對象雖然失去了引用,但是隻佔用了少量的內存資源,而且系統沒有很嚴重的內存需求,此時,垃圾回收機制沒有試圖去回收對象所佔用的資源,這樣對象的finalize()方法是不會被調用的。

finalize()方法4個特點:
1) 永遠不要主動調用某個對象的finalize()方法,該方法應交給垃圾回收機制調用。

2) finalize()方法何時被調用,是否被調用具有不確定性,不要把finalize()方法當成一定會被執行的方法。

3) 當JVM執行可恢復對象的finalize()方法時,可能使該對象或系統中其他對象重新變成可達狀態。

4) 當JVM執行finalize()方法時出現異常時,垃圾回收機制不會報告異常,程序繼續執行。

getClass()方法

返回當前對象所屬類對應的CLASS對象(具體方法查看API);

clone()方法

用來幫助其他對象來實現“自我克隆”,也就是得到一個當前對象的副本,而且兩者完全隔離。Object類提供的clone()方法使用了protected修飾符,該方法只能夠被子類重寫或調用。

注意: Object類中提供的Clone機制只可以對對象裏面的各實例變量進行“簡單複製”,如果實例變量的類型爲引用類型,Object的Clone機制也只能夠簡單地複製這個引用變量。

參考:Java瘋狂講義 P247頁

4. 類訪問權限

修飾詞 本類 同一個包的類 繼承類 其他類
private × × ×
無(默認) × ×
protected ×
public

5. String、stringbuffer、stringbuilder 聯繫、區別、源碼

String:字符串常量

StringBuffer:字符串變量(線程安全)

StringBuilder:字符串變量(線程非安全)

三者在執行速度方面的比較:StringBuilder > StringBuffer > String

使用場景:

1) 如果要操作少量的數據用 = String

2) 單線程操作字符串緩衝區下操作大量數據 = StringBuilder

3) 多線程操作字符串緩衝區下操作大量數據 = StringBuffer

爲什麼線程安全比非線程安全性能低?

1) 線程的安全是以犧牲性能爲代價的,所謂線程安全就是多了個加鎖,解鎖的操作,比如100億個操作中都要加鎖和解鎖,線程是安全了,但性能就下降了。

2) 有些軟件是以性能爲主的,爲了提高性能,就少了加鎖,解鎖的操作,雖然容易出現併發性問題,但性能卻提高了。

6. final修飾符

final修飾的變量不可改變。

final修飾成員變量

說明:final修飾的成員變量必須由程序員顯示地指定初始值。

類變量:必須在靜態初始化塊中指定初始值或聲明該類變量時指定初始值,而且只能在兩個地方的其中之一指定。

實例變量:必須在非靜態初始化塊、聲明該變量或構造器中指定初始值,而且只能在三個地方的其中之一指定。

final修飾局部變量

final修飾局部變量在定義時沒有指定默認值,可以在後面代碼中對該final變量賦初始值,但是隻能一次,不可重複賦值。

final修飾的形參不能在方法體內賦值,因爲形參在調用該方法時,是由系統根據傳入的參數來完成初始化的。

final修飾基本類型變量和引用類型變量

final修飾基本類型變量時,不可以對基本類型變量重新賦值,因此基本類型變量不能被改變。

final修飾引用類型變量時,只保證該引用類型變量所引用的地址不會改變,即一直引用同一個對象,但這個對象完全可以發生改變。

final修飾的方法

final修飾的方法不能被重寫,並不是不能被重載。(例如Object類中的getClass()方法就是一個final方法)

final修飾類

final修飾的類不可以有子類

immutable不可變類:當你獲得這個類的一個實例引用時,你不可以改變這個實例的內容。不可變類的實例一但創建,其內在成員變量的值就不能被修改。

7. 抽象類和接口的聯繫區別

共同點:

1) 接口和抽象類都不能被實例化,它們都在繼承樹的頂端,用來被其他類實現和繼承。

2) 接口和抽象類都可以包含抽象方法,實現接口或繼承抽象類的普通子類都必須實現這些抽象方法。

設計目的:

接口主要體現一種規範,它類似於整個系統的“總綱”,它制定了系統各模塊應該遵循的標準,因此一個系統中的接口不應該經常改變。

抽象類主要體現了一種模板式設計。可以認爲是系統實現過程當中的中間產品。它已經實現了系統的部分功能(哪些已經提供實現的方法)

區別:

1)接口中只能包含抽象方法、靜態方法和默認方法,不能爲普通方法提供方法的實現;而抽象類則完全可以包含普通方法。

2)接口中只能定義靜態常量,不能定義普通成員變量;抽象類裏則可以定義普通成員變量,也可以定義靜態常量。

3)接口裏不包含構造器;抽象類裏可以包含構造器;但是抽象類中的構造器不是用來創建對象,而是讓其子類調用這些構造器來完成屬於抽象類的初始化操作。

4)接口中不可以包含初始化塊;但是抽象類中可以包含初始化塊。

5)一個類最多只能有一個直接父類,包括抽象類;但一個類可以直接實現多個接口,通過實現多個接口可以彌補java單繼承的不足。

什麼時候用接口什麼時候用抽象類?

抽象類都是從一些相似的對象中抽象出來的一個相對無法具體描述的一個類,它的子類之間是有相似性的;

接口更側重於對相同的動作進行抽象封裝。當你關注一個事物的本質的時候,用抽象類;當你關注一個操作的時候,用接口。

8. 對象的初始化過程

1)初始化父類中的靜態成員變量和靜態代碼塊;

2)初始化子類中的靜態成員變量和靜態代碼塊;

3)初始化父類的普通成員變量和代碼塊,再執行父類的構造方法;

4)初始化子類的普通成員變量和代碼塊,再執行子類的構造方法;

9. static修飾符

static修飾變量

1)對於靜態變量在內存中只有一個拷貝(節省內存),JVM只爲靜態分配一次內存。

2)對於實例變量,每創建一個實例,就會爲實例變量分配一次內存,實例變量可以在內存中有多個拷貝,互不影響(靈活)。

static方法

靜態方法中不能訪問非靜態成員方法和非靜態成員變量,但是在非靜態成員方法中是可以訪問靜態成員方法和變量的

static代碼塊

static代碼塊是在類中獨立於類成員的static語句塊,可以有多個,位置可以隨便放,它不在任何的方法體內,JVM加載類時會執行這些靜態的代碼塊,如果static代碼塊有多個,JVM將按照它們在類中出現的先後順序依次執行它們,每個代碼塊只會被執行一次。

關鍵的作用:用來形成靜態代碼塊以優化程序性能。因爲它只會在類加載的時候執行一次,所以能優化程序性能。

10. instanceof運算符

編譯時類型必須是如下3種情況

1)要麼與後面的類相同;
2)要麼是後面類型的父類;
3)要麼是後面類型的子類;

如果前面操作數的編譯時類型與後面的類型沒有任何關係,程序將沒發通過編譯。

運行階段

被轉型變量所引用對象的實際類型必須是目標類型的實例,或者是目標類型的子類,實現類的實例,否則在運行時將引發ClassCastException異常。

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