2018年面試準備彙總

一、面向對象的特徵java

    面向對象的三個基本特徵:封裝、繼承、多態編程

o_OOBase.gif

封裝

封裝最好理解了。封裝是面向對象的特徵之一,是對象和類概念的主要特性。數組

封裝,也就是把客觀事物封裝成抽象的類,而且類能夠把本身的數據和方法只讓可信的類或者對象操做,對不可信的進行信息隱藏。緩存

繼承

面向對象編程 (OOP) 語言的一個主要功能就是「繼承」。繼承是指這樣一種能力:它可使用現有類的全部功能,並在無需從新編寫原來的類的狀況下對這些功能進行擴展。app

經過繼承建立的新類稱爲「子類」或「派生類」。框架

被繼承的類稱爲「基類」、「父類」或「超類」。編程語言

繼承的過程,就是從通常到特殊的過程。ide

要實現繼承,能夠經過「繼承」(Inheritance)和「組合」(Composition)來實現。模塊化

在某些 OOP 語言中,一個子類能夠繼承多個基類。可是通常狀況下,一個子類只能有一個基類,要實現多重繼承,能夠經過多級繼承來實現。函數

 

繼承概念的實現方式有三類:實現繼承、接口繼承和可視繼承。

Ø         實現繼承是指使用基類的屬性和方法而無需額外編碼的能力;

Ø         接口繼承是指僅使用屬性和方法的名稱、可是子類必須提供實現的能力;

Ø         可視繼承是指子窗體(類)使用基窗體(類)的外觀和實現代碼的能力。

在考慮使用繼承時,有一點須要注意,那就是兩個類之間的關係應該是「屬於」關係。例如,Employee 是一我的,Manager 也是一我的,所以這兩個類均可以繼承 Person 類。可是 Leg 類卻不能繼承 Person 類,由於腿並非一我的。

抽象類僅定義將由子類建立的通常屬性和方法,建立抽象類時,請使用關鍵字 Interface 而不是 Class。

OO開發範式大體爲:劃分對象→抽象類→將類組織成爲層次化結構(繼承和合成) →用類與實例進行設計和實現幾個階段。

 

多態

多態性(polymorphisn)是容許你將父對象設置成爲和一個或更多的他的子對象相等的技術,賦值以後,父對象就能夠根據當前賦值給它的子對象的特性以不一樣的方式運做。簡單的說,就是一句話:容許將子類類型的指針賦值給父類類型的指針。

實現多態,有二種方式,覆蓋,重載。

覆蓋,是指子類從新定義父類的虛函數的作法。

重載,是指容許存在多個同名函數,而這些函數的參數表不一樣(或許參數個數不一樣,或許參數類型不一樣,或許二者都不一樣)。

其實,重載的概念並不屬於「面向對象編程」,重載的實現是:編譯器根據函數不一樣的參數表,對同名函數的名稱作修飾,而後這些同名函數就成了不一樣的函數(至少對於編譯器來講是這樣的)。如,有兩個同名函數:function func(p:integer):integer;和function func(p:string):integer;。那麼編譯器作過修飾後的函數名稱多是這樣的:int_func、str_func。對於這兩個函數的調用,在編譯器間就已經肯定了,是靜態的(記住:是靜態)。也就是說,它們的地址在編譯期就綁定了(早綁定),所以,重載和多態無關!真正和多態相關的是「覆蓋」。當子類從新定義了父類的虛函數後,父類指針根據賦給它的不一樣的子類指針,動態(記住:是動態!)的調用屬於子類的該函數,這樣的函數調用在編譯期間是沒法肯定的(調用的子類的虛函數的地址沒法給出)。所以,這樣的函數地址是在運行期綁定的(晚邦定)。結論就是:重載只是一種語言特性,與多態無關,與面向對象也無關!引用一句Bruce Eckel的話:「不要犯傻,若是它不是晚邦定,它就不是多態。」

那麼,多態的做用是什麼呢?

咱們知道,封裝能夠隱藏實現細節,使得代碼模塊化;繼承能夠擴展已存在的代碼模塊(類);它們的目的都是爲了——代碼重用。而多態則是爲了實現另外一個目的——接口重用!多態的做用,就是爲了類在繼承和派生的時候,保證使用「家譜」中任一類的實例的某一屬性時的正確調用。

 

概念講解

泛化(Generalization)

o_Generalization.gif

圖表 1 泛化

在上圖中,空心的三角表示繼承關係(類繼承),在UML的術語中,這種關係被稱爲泛化(Generalization)。Person(人)是基類,Teacher(教師)、Student(學生)、Guest(來賓)是子類。

若在邏輯上B是A的「一種」,而且A的全部功能和屬性對B而言都有意義,則容許B繼承A的功能和屬性。

例如,教師是人,Teacher 是Person的「一種」(a kind of )。那麼類Teacher能夠從類Person派生(繼承)。

若是A是基類,B是A的派生類,那麼B將繼承A的數據和函數。

若是類A和類B絕不相關,不能夠爲了使B的功能更多些而讓B繼承A的功能和屬性。

若在邏輯上B是A的「一種」(a kind of ),則容許B繼承A的功能和屬性。

 

聚合(組合)

o_aggregationBase.gif

圖表 2 組合

若在邏輯上A是B的「一部分」(a part of),則不容許B從A派生,而是要用A和其它東西組合出B。

例如,眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是頭(Head)的一部分,因此類Head應該由類Eye、Nose、Mouth、Ear組合而成,不是派生(繼承)而成。

 

聚合的類型分爲無、共享(聚合)、複合(組合)三類。

 

聚合(aggregation)

 

o_aggregation.gif

圖表 3 共享

上面圖中,有一個菱形(空心)表示聚合(aggregation)(聚合類型爲共享),聚合的意義表示has-a關係。聚合是一種相對鬆散的關係,聚合類B不須要對被聚合的類A負責。

 

組合(composition)

o_composition.gif

圖表 4 複合

這幅圖與上面的惟一區別是菱形爲實心的,它表明了一種更爲堅固的關係——組合(composition)(聚合類型爲複合)。組合表示的關係也是has-a,不過在這裏,A的生命期受B控制。即A會隨着B的建立而建立,隨B的消亡而消亡。

 

依賴(Dependency)

o_Dependency.gif

圖表 5 依賴

這裏B與A的關係只是一種依賴(Dependency)關係,這種關係代表,若是類A被修改,那麼類B會受到影響。

感謝:http://blog.csdn.net/cancan8538/article/details/8057095

二、final, finally, finalize 的區別

一、final修飾符(關鍵字)。被final修飾的類,就意味着不能再派生出新的子類,不能做爲父類而被子類繼承。所以一個類不能既被abstract聲明,又被final聲明。將變量或方法聲明爲final,能夠保證他們在使用的過程當中不被修改。被聲明爲final的變量必須在聲明時給出變量的初始值,而在之後的引用中只能讀取。被final聲明的方法也一樣只能使用,不能重載。

【例】

public  class  finalTest{
final   int  a=6;//final成員變量不能被更改
final   int  b;//在聲明final成員變量時沒有賦值,稱爲空白final
public finalTest(){
b=8;//在構造方法中爲空白final賦值
}
int   do(final x){//設置final參數,不能夠修改參數x的值
return x+1;
}
void  doit(){
final int i = 7;//局部變量定義爲final,不可改變i的值
}
}

 

二、finally是在異常處理時提供finally塊來執行任何清除操做。無論有沒有異常被拋出、捕獲,finally塊都會被執行。try塊中的內容是在無異常時執行到結束。catch塊中的內容,是在try塊內容發生catch所聲明的異常時,跳轉到catch塊中執行。finally塊則是不管異常是否發生,都會執行finally塊的內容,因此在代碼邏輯中有須要不管發生什麼都必須執行的代碼,就能夠放在finally塊中。

三、finalize是方法名。java技術容許使用finalize()方法在垃圾收集器將對象從內存中清除出去以前作必要的清理工做。這個方法是由垃圾收集器在肯定這個對象沒有被引用時對這個對象調用的。它是在object類中定義的,所以全部的類都繼承了它。子類覆蓋finalize()方法以整理系統資源或者被執行其餘清理工做。finalize()方法是在垃圾收集器刪除對象以前對這個對象調用的。

感謝:http://blog.csdn.net/cyl101816/article/details/67640843

三、Java的Integer和int有什麼區別

Java是面向對象的編程語言,一切都是對象,可是爲了編程的方便仍是引入了基本數據類型,爲了可以將這些基本數據類型當成對象操做,Java爲每個基本數據類型都引入了對應的包裝類型(wrapper class),int的包裝類就是Integer,從Java 5開始引入了自動裝箱/拆箱機制,使得兩者能夠相互轉換,對應以下:

原始類型:boolean,char,byte,short,int,long,float,double

包裝類型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

順便一提,Java中的基本數據類型只有以上8個,除了基本類型(primitive type),剩下的都是引用類型(reference type)。

因此最基本的一點區別是:Ingeter是int的包裝類,int的初值爲0,Ingeter的初值爲null。除此以外還有區別,請看代碼:

 

[java] view plain copy

  1. public class TestInteger {  
  2.     public static void main(String[] args) {  
  3.         int i = 128;  
  4.         Integer i2 = 128;  
  5.         Integer i3 = new Integer(128);  
  6.         System.out.println(i == i2); //Integer會自動拆箱爲int,因此爲true  
  7.         System.out.println(i == i3); //true,理由同上  
  8.         Integer i4 = 127;//編譯時被翻譯成:Integer i4 = Integer.valueOf(127);  
  9.         Integer i5 = 127;  
  10.         System.out.println(i4 == i5);//true  
  11.         Integer i6 = 128;  
  12.         Integer i7 = 128;  
  13.         System.out.println(i6 == i7);//false  
  14.         Integer i8 = new Integer(127);  
  15.         System.out.println(i5 == i8); //false  
  16.         Integer i9 = new Integer(128);  
  17.         Integer i10 = new Integer(123);  
  18.         System.out.println(i9 == i10);  //false  
  19.     }  
  20. }  

爲何i4和i5比是true,而i6和i7比是false呢?關鍵就是看valueOf()函數了,這個函數對於-128到127之間的數,會進行緩存, Integer i4 = 127時,會將127進行緩存,下次再寫Integer i5 = 127時,就會直接從緩存中取,就不會new了。因此i4和i5比是true,而i6和i7比是false。

而對於後邊的i5和i8,以及i9和i10,由於對象不同,因此爲false。

以上的狀況總結以下:

1,不管如何,Integer與new Integer不會相等。不會經歷拆箱過程,new出來的對象存放在堆,而非new的Integer常量則在常量池(在方法區),他們的內存地址不同,因此爲false。

2,兩個都是非new出來的Integer,若是數在-128到127之間,則是true,不然爲false。由於java在編譯Integer i2 = 128的時候,被翻譯成:Integer i2 = Integer.valueOf(128);而valueOf()函數會對-128到127之間的數進行緩存。

3,兩個都是new出來的,都爲false。仍是內存地址不同。

4,int和Integer(不管new否)比,都爲true,由於會把Integer自動拆箱爲int再去比。

感謝:http://blog.csdn.net/login_sonata/article/details/71001851

四、重載和重寫的區別

重寫(Override)

重寫是子類對父類的容許訪問的方法的實現過程進行從新編寫, 返回值和形參都不能改變。即外殼不變,核心重寫!

重寫的好處在於子類能夠根據須要,定義特定於本身的行爲。 也就是說子類可以根據須要實現父類的方法。

重寫方法不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的異常。例如: 父類的一個方法申明瞭一個檢查異常 IOException,可是在重寫這個方法的時候不能拋出 Exception 異常,由於 Exception 是 IOException 的父類,只能拋出 IOException 的子類異常。

方法的重寫規則

  • 參數列表必須徹底與被重寫方法的相同;
  • 返回類型必須徹底與被重寫方法的返回類型相同;
  • 訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:若是父類的一個方法被聲明爲public,那麼在子類中重寫該方法就不能聲明爲protected。
  • 父類的成員方法只能被它的子類重寫。
  • 聲明爲final的方法不能被重寫。
  • 聲明爲static的方法不能被重寫,可是可以被再次聲明。
  • 子類和父類在同一個包中,那麼子類能夠重寫父類全部方法,除了聲明爲private和final的方法。
  • 子類和父類不在同一個包中,那麼子類只可以重寫父類的聲明爲public和protected的非final方法。
  • 重寫的方法可以拋出任何非強制異常,不管被重寫的方法是否拋出異常。可是,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明的更普遍的強制性異常,反之則能夠。
  • 構造方法不能被重寫。
  • 若是不能繼承一個方法,則不能重寫這個方法。

重載(Overload)

重載(overloading) 是在一個類裏面,方法名字相同,而參數不一樣。返回類型能夠相同也能夠不一樣。

每一個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。

只能重載構造函數

重載規則

  • 被重載的方法必須改變參數列表(參數個數或類型或順序不同);
  • 被重載的方法能夠改變返回類型;
  • 被重載的方法能夠改變訪問修飾符;
  • 被重載的方法能夠聲明新的或更廣的檢查異常;
  • 方法可以在同一個類中或者在一個子類中被重載。
  • 沒法以返回值類型做爲重載函數的區分標準

 

區別點 重載方法 重寫方法
參數列表 必須修改 必定不能修改
返回類型 能夠修改 必定不能修改
異常 能夠修改 能夠減小或刪除,必定不能拋出新的或者更廣的異常
訪問 能夠修改 必定不能作更嚴格的限制(能夠下降限制)

 

總結

方法的重寫(Overriding)和重載(Overloading)是java多態性的不一樣表現,重寫是父類與子類之間多態性的一種表現,重載是一類中多態性的一種表現。

五、抽象類和接口有什麼區別
接口和抽象類都是繼承樹的上層,他們的共同點以下:
1) 都是上層的抽象層。
2) 都不能被實例化
3) 都能包含抽象的方法,這些抽象的方法用於描述類具有的功能,可是不比提供具體的實現。
他們的區別以下:
1) 在抽象類中能夠寫非抽象的方法,從而避免在子類中重複書寫他們,這樣能夠提升代碼的複用性,這是抽象類的優點;接口中只能有抽象的方法。
2) 一個類只能繼承一個直接父類,這個父類能夠是具體的類也但是抽象類;可是一個類能夠實現多個接口。
Java語言中類的繼承是單繼承緣由是:當子類重寫父類方法的時候,或者隱藏父類的成員變量以及靜態方法的時候,JVM使用不一樣的綁定規則。若是一個類有多個直接的父類,那麼會使綁定規則變得更復雜。爲了簡化軟件的體系結構和綁定機制,java語言禁止多繼承。
接口能夠多繼承,是由於接口中只有抽象方法,沒有靜態方法和很是量的屬性,只有接口的實現類纔會重寫接口中方法。所以一個類有多個接口也不會增長JVM的綁定機制和複雜度。
對於已經存在的繼承樹,能夠方便的從類中抽象出新的接口,可是從類中抽象出新的抽象類就不那麼容易了,所以接口更有利於軟件系統的維護和重構。

圖中若是Sparrow繼承類Bird 類 ,Boyin繼承Airplane類,Sparrow 和Boyin想使用一樣的flay方法那麼是沒有辦法實現的,由於類的繼承是單繼承。

https://pic3.zhimg.com/v2-1f71b697cfd213ce382a35ee73790730_r.jpg
若是Bird和Airplane是接口那麼Boyin想使用一樣的flay方法就很簡單了。在寫一個接口讓Sparrow和Boyin實現這個接口就能夠了以下圖:

做者:每天向上
連接:https://www.zhihu.com/question/20149818/answer/142270191
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

六、說說反射的用途及實現

     反射(Reflection)是Java程序開發語言的特徵之一。它容許運行中的Java程序獲取自身的信息,而且能夠操做類或對象的內部屬性。Oracle官方對反射的解釋是:

Reflection enables Java code to discover information about the fields,methods and constructors of loaded classes,and to use reflected fields, methods, and constructors to operate on their underlying conunterparts, within security restrictions.

The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a give class. It also allows programs to suppress default reflective access control.

      簡而言之,經過反射,咱們能夠在運行時得到程序或者程序集中每個類型的成員和成員的信息。

程序中通常的對象的類型都是在編譯器就肯定下來的,而Java反射機制能夠動態地建立對象並調用其屬性,這樣的對象的類型在編譯器是未知的。因此咱們能夠經過反射機制直接建立對象,即便這個對象的類型在編譯期是未知的。

      反射的核心是JVM在運行時才動態的加載類或者調用方法/訪問屬性,它不須要事先(寫代碼的時候或編譯期)知道運行的對象是誰。

Java反射框架主要提供如下功能:

一、在運行時判斷任意一個對象所屬的類

二、在運行時構造任意一個類的對象

三、在運行時判斷任意一個類所具備的成員變量和方法(經過反射甚至能夠調用private方法)

四、在運行時調用任意一個對象的方法

      反射的主要用途:

反射最重要的用途是開發各類通用的框架。

基本運用

一、獲取Class對象

二、判斷是否爲某個類的實例

三、建立實例

四、獲取方法

五、獲取構造器信息

六、獲取類的成員變量(字段)信息

七、調用方法

八、利用反射建立數組

感謝:http://www.sczyh30.com/posts/Java/java-reflection-1/#%E4%B8%80%E3%80%81%E5%9B%9E%E9%A1%BE%EF%BC%9A%E4%BB%80%E4%B9%88%E6%98%AF%E5%8F%8D%E5%B0%84%EF%BC%9F

相關文章
相關標籤/搜索