1. 程式人生 > >java基礎知識-面試(一)

java基礎知識-面試(一)

java基礎知識-面試

  • 面向物件的三大特性
    1)封裝
    就是把同一類事物的屬性和方法歸到同一個類中,方便使用
    防止該類的程式碼和資料被外部類定義的程式碼隨意訪問
    要訪問該類的資料和程式碼必須通過嚴格的方法控制
    封裝的主要功能在於我們能修改自己的實現程式碼,而不用修改哪些呼叫程式的程式碼片段。

優點:減少耦合,類內部自由修改,可以對類成員變數進行更精確的控制,隱藏資訊、實現細節。

最佳實踐:
為了實現良好的封裝,通常將類的成員變數宣告為private ,通過public的set和get方法完成對屬性的操作

2)繼承
繼承就是子類繼承父類的特徵和行為,使得子類物件(例項)具有父類的例項域和方法

特性:
子類擁有父類的非private屬性,方法
子類可以擁有自己的屬性和方法,即子類可以對父類進行擴充套件
子類可以用自己的方式實現父類的方法
java的繼承是單繼承
關鍵字:extends

3)多型
封裝和繼承幾乎都是為多型而準備的
多型是同一個行為具有多個不同表現實行或形態的能力
多型是一個介面,使用不同的例項而執行不同的操作

多型存在的三個必要條件:
繼承
重寫
父類引用指向子類物件

  • 過載和重寫區別
    重寫(Override)
    重寫是子類對付類的允許訪問的方法的實現過程進行重新編寫,返回值和形參都不能改變。
    子類根據需要實現自己的方法

過載(Overload)
是在一個類裡面,方法名字相同,而引數不同(個數和型別不同),返回型別可以相同也可以不同
最常用的就是構造器的過載

方法過載是一個類的多型性表現,而方法重寫是子類與父類的一種多型性的表現。

重寫發生在子類和父類之間,重寫要求子類被重寫方法與父類被重寫方法有相同的返回型別,比父類被重寫方法更好的訪問,不能比父類被重寫方法宣告更多的異常。—執行時多型

重寫原則:
引數列表必須完全與被重寫方法的一致,返回型別必須完全與被重寫的方法的返回型別一致
構造方法不能被重寫,宣告為final的方法不能被重寫,宣告為static的方法不能被重寫,但是能夠被再次申明

訪問許可權不能比父類中被重寫的方法的訪問許可權更低。

重寫的父類方法能夠丟擲任何非強制異常(也叫非執行異常),無論被重寫的方法是否丟擲異常,但是,重寫的方法不能丟擲新的強制性異常,或者比被重寫方法宣告更廣泛的強制性異常,反之則可以。

  • 多型的實現機制
    多型允許基類(父類)指標或引用指向派生類(子類)的物件,而在具體訪問方法時實現動態繫結。
    編譯時多型(過載)
    執行時多型(重寫)

多型是針對類的方法而言的,對於類的成員變數是定義的時候確定的,即編譯的時候就確定的。

  • 是否可以繼承String類
    String是final型別的,所以不能被繼承
    java類支援多繼承嗎?可以實現多個介面嗎?
    java不支援多繼承,但是類可以實現多個介面,間接的實現多繼承,也可以通過內部類。

  • 介面和抽象類有什麼區別
    介面和抽象類都是繼承樹的上層,他們的共同點如下:
    1)都是上層的抽象層
    2)都不能夠被例項化
    3)都能包含抽象的方法,這些抽象的方法用於描述類具備的功能

區別:
在抽象類中可以寫非抽象的方法,從而避免在子類中重複書寫,提高程式碼複用性–抽象類的優勢,而介面當中只能有抽象的方法(jdk8之後也可以有實現方法)
一個類只能繼承一個直接父類,這個父類可以是具體的類也可以是抽象類,但是一個類可以實現多個介面,介面的設計具有更大的擴充套件性,而抽象類的設計必須十分謹慎。
抽象級別:介面 大於 抽象類 大於 實現類
介面的設計目的:是針對類的行為進行約束,側重於動作,而抽象類的設計目的是程式碼複用。
抽象類是 is a的關係,介面是has a的關係。

  • java中修飾符的作用域以及可見性
    public :當前類、子類,同一包、其他包都可以訪問
    protected:當前類,子類以及同一包可以訪問,其它包不可以
    default:當前類和同一包可以訪問,子類和其他包不可以
    private:當前類可以訪問,同一包、子類、其它包都不可以訪問

==和equals方法的區別:
兩個操作用於物件的比較,檢查物件的相等性,但是區別在與equals是方法,而==是操作符
一般使用==比較原生型別如:boolean、int、char等等,使用equals比較物件
如果兩個引用指向相同的物件==返回true,equals方法的返回結果依賴於具體的實現,一般重寫equals方法,也重寫hashcode方法,
字串的對比使用的是equals代替==操作符

靜態變數和例項變數的區別?
一個static方法內不可以呼叫非static方法
因為非靜態方法是與物件關聯在一起的,必須建立一個物件後,才可以在該物件上進行方法呼叫,而靜態方法呼叫不需要建立物件,也就是說,當一個靜態方法被呼叫時,如果從一個static方法中發出對非static方法的呼叫,那麼非靜態方法關聯到哪個物件上呢?這個邏輯無法成立。

static方法是靜態方法,是屬於類的方法;非static方法是屬於物件的方法,所以要想在static方法中呼叫非static方法要先建立一個物件,再由這個物件來呼叫。
本質是JVM載入順序決定的,載入static方法的時候非靜態方法還沒有初始化,當然不能呼叫了

靜態變數和例項變數的區別?
1)在語法定義上的區別:靜態變數前要加static關鍵字,而例項變數前則不加
2)在程式執行時的區別:例項變數是屬於某個物件的屬性,必須建立了例項物件,其中的例項變數才會被分配記憶體空間,才可以使用這個例項變數
靜態變數不屬於某個例項物件,而是屬於類,所以也稱為類變數,只要程式載入了類的位元組碼,不用建立任何例項物件,靜態變數就會分配記憶體空間,而且只分配一次,靜態變數就可以被使用了。總之,例項變數必須建立後才可以通過這個物件來使用,靜態變數則直接可以使用類名來呼叫。

Integer和int的型別
Integer是int提供的封裝類,從java5之後引入了自動裝箱、拆箱機制,使得兩者可以相互轉換,而int是java基本資料型別
Integer預設值是null,而int預設值是0
Integer是物件,用一個引用指向這個物件,而int是基本型別,直接儲存資料。
Integer提供了好多與整數相關的操作方法,例如:將一個字串轉換成整數等.
Integer會有快取
這裡寫圖片描述

String、StringBuilder、StringBuffer:
1.執行速度方面,StringBuilder大於StringBuffer大於String
String最慢的原因:String為字串常量,而StringBuilder和StringBuffer均為字串變數,即String物件一旦被建立後該物件是不可更改的,但後兩者的物件是變數,是可以更改的

2.執行緒安全:StringBuilder是執行緒不安全的,而StringBuffer是執行緒安全的(StringBuffer中很多方法帶有synchronized關鍵字)–同步關鍵字

3.總結:String:適用於少量字串操作的情況;
StringBuilder:適用於在單執行緒下在字元緩衝區進行大量操作的情況;
StringBuffer:適用於在多執行緒下在字元緩衝區進行大量操作的情況

String中的常用方法有哪些:
length()、isEmpty()、split()、toLowerCase()、toUpperCase()
subString()、trim()、concat(“abc”)、contains(“a”)

java程式初始化的順序是什麼樣子的?
一般遵循三個原則:
1.靜態變數優先於非靜態變數初始化,其中靜態變數只初始化一次,而非靜態變數可能會初始化很多次
2.父類優先子類進行初始化
3.按照成員變數定義順序進行初始化,即使變數定義散佈於方法之中,它們依然在方法呼叫之前(包括建構函式)先初始化。
父類靜態欄位初始化
父類靜態程式碼塊
子類靜態欄位初始化
子類靜態程式碼塊
父類普通欄位初始化
父類構造程式碼塊({//程式碼}) –優先於建構函式執行
父類建構函式
子類普通欄位初始化
子類構造程式碼塊
子類建構函式

很明顯的看出,static欄位,程式碼塊的在執行順序優先於非sattic、程式碼塊,這是因為靜態域是屬於類的,在類載入後就一直存在,而普通域則需要建立物件才能訪問。而在建立物件時,要先載入父類,然後再載入子類,因此父類的靜態欄位初始化和靜態程式碼塊執行優先於子類

應用:單例模式的設計(只建立一次物件的目的)

簡單介紹反射機制?

反射是框架設計的靈活
使用的前提條件:必須先得到代表位元組碼的Class,Class類用於表示.class檔案(位元組碼)

什麼是反射機制?
java反射是在執行狀態中,對任意一個類,都能夠知道這個類的所有屬性和方法,對於任何一個物件,都能夠呼叫它的任意一個屬性和方法,這種動態獲取資訊以及動態呼叫物件的方法的功能稱為java的反射機制

要想剖析一個類,必須首先獲得該類的位元組碼檔案物件,而剖析使用的就是Class類中的方法,所以先要獲得每一個位元組碼檔案對應的Class型別的物件

Class是反射的基石
1.Class是一個類,一個描述類的類,封裝了描述方法的Method,描述欄位的Filed,描述構造器的Constructor等屬性,通過反射可以得到類的各個成分。
2.對於每個類而言,JRE都為其保留一個不變的Class型別的物件,一個Class物件包含了特定某個類的有關資訊。
3.Class物件只能由JVM建立
4.一個類在JVM中只有一個Class例項
5.反射相關的類:java.lang.reflect包下

獲取Class物件的三種方式:
1.Object—getClass(); 通過已知物件獲取
2.任何資料型別(包括基本資料型別)都有一個靜態的Class屬性 通過類名.Class

3.通過Class的靜態方法:
Class.forName(String calssName):最常用

這裡寫圖片描述

應用:使用JDBC連線資料庫的時候,都使用的反射,一般都是通過配置檔案書寫連線哪個資料庫,比如:mysql、oracle等,以及對應的關鍵資訊

簡單來說:
反射就是把各種java類中的各種成分對映成一個個的java物件
成員變數、方法、構造方法、構造方法、包等資訊
利用反射技術可以對一個類進行剖析,把各個組成部分對映成一個個物件
核心類:
Class:代表一個類
Constructor類:代表類的構造方法
Filed類:代表類的成員變數
Method:代表類的方法
這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

反射中,Class.forName和classloader的區別:
相同點:java中Class.forName()和classloader都可以用來對類進行載入
不同點:
class.forName除了將類的.class檔案載入到jvm中之外,還會對類進行解釋,執行類中的static塊
而classloader只做一件事情,就是將.class檔案載入到jvm中,不會執行static中的內容,只有在newinstance才會去執行static塊。
calssforName(name,initialize,loader)帶參函式也可以控制是否載入static塊,並且只有呼叫了newinstance才會建構函式,來建立類的物件,jvm底層可以控制—–一般不會干預
這裡寫圖片描述

Try catch finally的問題
當在try、catch中有return時,finally是否會執行?
總結:
1.不管有沒有異常,finally中的程式碼都會執行
2.當try、catch中有return語句時,finally中的程式碼依然會繼續執行
3.finally是在return後面的表示式運算之後執行的,此時並沒有返回運算後的值,而是把值儲存起來,不管finally對該值做了任何改變,返回的值都不會改變,依然返回儲存起來的值,也就是說方法的返回值是在finally運算之前就確定了的。

4.如果return的資料是引用資料型別,而在finally中對該引用資料型別的屬性值的改變起作用,try 中return返回的就是finally中改變後的屬性值

5.finally程式碼最好不要包含return,程式會提前退出,也就是說返回的值不是try catch中的值

先執行try中的語句,包括return後面的表示式
有異常時,先執行catch中的語句,包括return 後面的表示式;
然後執行fianlly中的語句,如果finally裡面有return語句,會提前退出
最後執行try 中的return,有異常執行catch中return;

在執行try catch 中的return之前一定會執行finally中的程式碼(如果finally存在),如果finally中有return語句,就會執行finally中的return方法,所以finally中的return語句一定會被執行的,比那一起吧finally中的retrun語句標識為一個warning

final、finally、finalize
final是最終的意思,表示不能被改變,可用於成員變數、方法和類
修飾變數:變數一旦被初始化不可改變
修飾方法:方法不能被覆蓋
修飾類:類不能夠被繼承

finally:異常處理關鍵字,finally中的主體總會執行,無論異常發生與否
finalize:類的finalize方法,可以告訴垃圾回收器應該執行的操作,該方法從Object繼承而來,在從堆中永久刪除物件之前,呼叫該物件的finalize方法
注意:無法確切的保證垃圾回收器何時呼叫該方法,也無法保證呼叫不同物件方法的順序,

常見異常:
這裡寫圖片描述

finally:finally語句塊總是會被執行,它主要用於回收在try中開啟的物理資源,如資料庫連線,網路連線,只有finally執行完成之後,才會回來執行try catch 塊中的return語句或者throw語句,如果finally中使用了throw或者return終止方法的語句,則就不會跳回執行,直接終止

throw:丟擲異常
throws:用在方法簽名中,用於宣告該方法可能丟擲的異常

java中的異常框架:
Throwable (Interface)
Error Exception
RunTimeException

Throwable:
它是java語言中所有錯誤或異常的超類
它包含兩個子類:Error和Exception
Throwable包含了其執行緒建立時執行執行緒執行堆疊的快照,它提供了printStackTrance()等介面用於獲取堆疊跟蹤資料資訊

Exception 以及子類是Throwable的一種形式,它指出了合理的應用程式想要捕獲的條件

3.RuntimeException
是那些可能在java虛擬機器正常執行期間丟擲的異常的超類
編譯器不會檢查執行時異常
如果程式碼產生RuntimeException,則需要通過修改程式碼避免。

Error:和Exception一樣,也是Throwable的子類,它用於指示合理程式不應該出現試圖捕獲的嚴重問題,編譯器也不會檢查

java異常分為兩類:
1,被檢查的異常(Checked Exception)
Exception中除了執行時異常就都稱為編譯異常

2.執行時異常(RuntimeException)—RuntimeException以及其子類
3.錯誤(Error)
記憶體溢位