鍍金池/ 教程/ Java/ 面向對象編程
異常處理
基本類型與運算
Java 平臺與內存管理
XML
輸入輸出流
JDBC 與數(shù)據(jù)庫
字符串與數(shù)組
Java 多線程
面向對象編程
集合類
UML
J2EE 與 EJB
Java 基本概念
Servlet 與 JSP
關鍵字
常見設計模式
SSH 架構

面向對象編程

1. Java 中的方法覆蓋 (Overriding) 和方法重載 (Overloading) 是什么意思?

Java 中的方法重載發(fā)生在同一個類里面兩個或者是多個方法的方法名相同但是參數(shù)不同的情況。與此相對,方法覆蓋是說子類重新定義了父類的方法。方法覆蓋必須有相同的方法名,參數(shù)列表和返回類型。覆蓋者可能不會限制它所覆蓋的方法的訪問。

2. Overload 和 Override 的區(qū)別? Overloaded 的方法是否可以改變返回值的類型?

Overload 是重載的意思,Override 是覆蓋的意思,也就是重寫。

重載 Overload 表示同一個類中可以有多個名稱相同的方法,但這些方法的參數(shù)列表各不相同(即參數(shù)個數(shù)或類型不同)。

重寫 Override 表示子類中的方法可以與父類中的某個方法的名稱和參數(shù)完全相同,通過子類創(chuàng)建的實例對象調用這個方法時,將調用子類中的定義方法,這相當于把父類中定義的那個完全相同的方法給覆蓋了,這也是面向對象編程的多態(tài)性的一種表現(xiàn)。子類覆蓋父類的方法時,只能比父類拋出更少的異常,或者是拋出父類拋出的異常的子異常,因為子類可以解決父類的一些問題,不能比父類有更多的問題。子類方法的訪問權限只能比父類的更大,不能更小。如果父類的方法是 private 類型,那么,子類則不存在覆蓋的限制,相當于子類中增加了一個全新的方法。

至于 Overloaded 的方法是否可以改變返回值的類型這個問題,要看你倒底想問什么呢?這個題目很模糊。如果幾個 Overloaded 的方法的參數(shù)列表不一樣,它們的返回者類型當然也可以不一樣。但我估計你想問的問題是:如果兩個方法的參數(shù)列表完全一樣,是否可以讓它們的返回值不同來實現(xiàn)重載 Overload。這是不行的,我們可以用反證法來說明這個問題,因為我們有時候調用一個方法時也可以不定義返回結果變量,即不要關心其返回結果,例如,我們調用 map.remove(key) 方法時,雖然 remove 方法有返回值,但是我們通常都不會定義接收返回結果的變量,這時候假設該類中有兩個名稱和參數(shù)列表完全相同的方法,僅僅是返回類型不同,Java 就無法確定編程者倒底是想調用哪個方法了,因為它無法通過返回結果類型來判斷。

Override 可以翻譯為覆蓋,從字面就可以知道,它是覆蓋了一個方法并且對其重寫,以求達到不同的作用。對我們來說最熟悉的覆蓋就是對接口方法的實現(xiàn),在接口中一般只是對方法進行了聲明,而我們在實現(xiàn)時,就需要實現(xiàn)接口聲明的所有方法。除了這個典型的用法以外,我們在繼承中也可能會在子類覆蓋父類中的方法。在覆蓋要注意以下的幾點:

1、覆蓋的方法的標志必須要和被覆蓋的方法的標志完全匹配,才能達到覆蓋的效果;

2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;

3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;

4、被覆蓋的方法不能為 private,否則在其子類中只是新定義了一個方法,并沒有對其進行覆蓋。

Overload 對我們來說可能比較熟悉,可以翻譯為重載,它是指我們可以定義一些名稱相同的方法,通過定義不同的輸入?yún)?shù)來區(qū)分這些方法,然后再調用時,VM 就會根據(jù)不同的參數(shù)樣式,來選擇合適的方法執(zhí)行。在使用重載要注意以下的幾點:

1、在使用重載時只能通過不同的參數(shù)樣式。例如,不同的參數(shù)類型,不同的參數(shù)個數(shù),不同的參數(shù)順序(當然,同一方法內的幾個參數(shù)類型必須不一樣,例如可以是 fun(int,float),但是不能 fun(int,int)); 2、不能通過訪問權限、返回類型、拋出的異常進行重載;

3、方法的異常類型和數(shù)目不會對重載造成影響;

4、對于繼承來說,如果某一方法在父類中是訪問權限是 priavte,那么就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果。

3. Java 中,什么是構造函數(shù)?什么是構造函數(shù)重載?什么是復制構造函數(shù)?

當新對象被創(chuàng)建的時候,構造函數(shù)會被調用。每一個類都有構造函數(shù)。在程序員沒有給類提供構造函數(shù)的情況下,Java 編譯器會為這個類創(chuàng)建一個默認的構造函數(shù)。

Java 中構造函數(shù)重載和方法重載很相似??梢詾橐粋€類創(chuàng)建多個構造函數(shù)。每一個構造函數(shù)必須有它自己唯一的參數(shù)列表。

Java 不支持像 C++ 中那樣的復制構造函數(shù),這個不同點是因為如果你不自己寫構造函數(shù)的情況下,Java不會創(chuàng)建默認的復制構造函數(shù)。

4. 構造器 Constructor 是否可被 Override?

構造器 Constructor 不能被繼承,因此不能重寫 Override,但可以被重載 Overload。

5. Java 支持多繼承么?

不支持,Java 不支持多繼承。每個類都只能繼承一個類,但是可以實現(xiàn)多個接口。

6. 接口和抽象類的區(qū)別是什么?

Java 提供和支持創(chuàng)建抽象類和接口。它們的實現(xiàn)有共同點,不同點在于:

接口中所有的方法隱含的都是抽象的。而抽象類則可以同時包含抽象和非抽象的方法。

類可以實現(xiàn)很多個接口,但是只能繼承一個抽象類

類如果要實現(xiàn)一個接口,它必須要實現(xiàn)接口聲明的所有方法。但是,類可以不實現(xiàn)抽象類聲明的所有方法,當然,在這種情況下,類也必須得聲明成是抽象的。

抽象類可以在不提供接口方法實現(xiàn)的情況下實現(xiàn)接口。

Java 接口中聲明的變量默認都是 final 的。抽象類可以包含非 final 的變量。

Java 接口中的成員函數(shù)默認是 public 的。抽象類的成員函數(shù)可以是 private,protected 或者是 public 。

接口是絕對抽象的,不可以被實例化。抽象類也不可以被實例化,但是,如果它包含 main 方法的話是可以被調用的。

也可以參考 JDK8 中抽象類和接口的區(qū)別

7. 下列說法正確的有()

A.class 中的 constructor 不可省略

B.constructor 必須與 class 同名,但方法不能與class同名

C.constructor在一個對象被 new 時執(zhí)行

D.一個 class 只能定義一個 constructor

答案:C

解析:這里可能會有誤區(qū),其實普通的類方法是可以和類名同名的,和構造方法唯一的區(qū)分就是,構造方法沒有返回值。

8. Java 接口的修飾符可以為?

A. private
B. protected
C. final
D. abstract

答案:CD

解析:接口很重要,為了說明情況,這里稍微啰嗦點:

(1)接口用于描述系統(tǒng)對外提供的所有服務,因此接口中的成員常量和方法都必須是公開(public)類型的,確保外部使用者能訪問它們;

(2)接口僅僅描述系統(tǒng)能做什么,但不指明如何去做,所以接口中的方法都是抽象(abstract)方法;

(3)接口不涉及和任何具體實例相關的細節(jié),因此接口沒有構造方法,不能被實例化,沒有實例變量,只有靜態(tài)(static)變量;

(4)接口的中的變量是所有實現(xiàn)類共有的,既然共有,肯定是不變的東西,因為變化的東西也不能夠算共有。所以變量是不可變(final)類型,也就是常量了。

(5) 接口中不可以定義變量?如果接口可以定義變量,但是接口中的方法又都是抽象的,在接口中無法通過行為來修改屬性。有的人會說了,沒有關系,可以通過 實現(xiàn)接口的對象的行為來修改接口中的屬性。這當然沒有問題,但是考慮這樣的情況。如果接口 A 中有一個public 訪問權限的靜態(tài)變量 a。按照 Java 的語義,我們可以不通過實現(xiàn)接口的對象來訪問變量 a,通過 A.a = xxx; 就可以改變接口中的變量 a 的值了。正如抽象類中是可以這樣做的,那么實現(xiàn)接口 A 的所有對象也都會自動擁有這一改變后的 a 的值了,也就是說一個地方改變了 a,所有這些對象中 a 的值也都跟著變了。這和抽象類有什么區(qū)別呢,怎么體現(xiàn)接口更高的抽象級別呢,怎么體現(xiàn)接口提供的統(tǒng)一的協(xié)議呢,那還要接口這種抽象來做什么呢?所以接口中 不能出現(xiàn)變量,如果有變量,就和接口提供的統(tǒng)一的抽象這種思想是抵觸的。所以接口中的屬性必然是常量,只能讀不能改,這樣才能為實現(xiàn)接口的對象提供一個統(tǒng) 一的屬性。

通俗的講,你認為是要變化的東西,就放在你自己的實現(xiàn)中,不能放在接口中去,接口只是對一類事物的屬性和行為更高層次的抽象。對修改關閉,對擴展(不同的實現(xiàn) implements)開放,接口是對開閉原則的一種體現(xiàn)。

所以:

接口的方法默認是 public abstract;

接口中不可以定義變量即只能定義常量(加上final修飾就會變成常量)。所以接口的屬性默認是 public static final 常量,且必須賦初值。

注意:final 和 abstract 不能同時出現(xiàn)。

9. 下面是 People 和 Child 類的定義和構造方法,每個構造方法都輸出編號。在執(zhí)行 new Child("mike") 的時候都有哪些構造方法被順序調用?請選擇輸出結果

class People {
    String name;

    public People() {
        System.out.print(1);
    }

    public People(String name) {
        System.out.print(2);
        this.name = name;
    }
}

class Child extends People {
    People father;

    public Child(String name) {
        System.out.print(3);
        this.name = name;
        father = new People(name + ":F");
    }

    public Child() {
        System.out.print(4);
    }

}

A. 312
B. 32
C. 432
D. 132

答案:D

解析:考察的又是父類與子類的構造函數(shù)調用次序。在 Java 中,子類的構造過程中必須調用其父類的構造函數(shù),是因為有繼承關系存在時,子類要把父類的內容繼承下來。但如果父類有多個構造函數(shù)時,該如何選擇調用呢?

第一個規(guī)則:子類的構造過程中,必須調用其父類的構造方法。一個類,如果我們不寫構造方法,那么編譯器會幫我們加上一個默認的構造方法(就是沒有參數(shù)的構造方法),但是如果你自己寫了構造方法,那么編譯器就不會給你添加了,所以有時候當你 new 一個子類對象的時候,肯定調用了子類的構造方法,但是如果在子類構造方法中我們并沒有顯示的調用基類的構造方法,如:super(); 這樣就會調用父類沒有參數(shù)的構造方法。

第二個規(guī)則:如果子類的構造方法中既沒有顯示的調用基類構造方法,而基類中又沒有無參的構造方法,則編譯出錯,所以,通常我們需要顯示的:super(參數(shù)列表),來調用父類有參數(shù)的構造函數(shù),此時無參的構造函數(shù)就不會被調用。

總之,一句話:子類沒有顯示調用父類構造函數(shù),不管子類構造函數(shù)是否帶參數(shù)都默認調用父類無參的構造函數(shù),若父類沒有則編譯出錯。

10. 構造器(constructor)是否可被重寫(override)?

答:構造器不能被繼承,因此不能被重寫,但可以被重載。

11. 兩個對象值相同(x.equals(y) == true),但卻可有不同的 hash code,這句話對不對?

答:不對,如果兩個對象 x 和 y 滿足 x.equals(y) == true,它們的哈希碼(hash code)應當相同。Java 對于 eqauls 方法和 hashCode 方法是這樣規(guī)定的:(1)如果兩個對象相同(equals 方法返回 true ),那么它們的 hashCode 值一定要相同;(2)如果兩個對象的 hashCode 相同,它們并不一定相同。當然,你未必要按照要求去做,但是如果你違背了上述原則就會發(fā)現(xiàn)在使用容器時,相同的對象可以出現(xiàn)在 Set 集合中,同時增加新元素的效率會大大下降(對于使用哈希存儲的系統(tǒng),如果哈希碼頻繁的沖突將會造成存取性能急劇下降)。

補充:關于 equals 和 hashCode 方法,很多 Java 程序都知道,但很多人也就是僅僅知道而已,在 Joshua Bloch 的大作《Effective Java》(很多軟件公司,《Effective Java》、《Java 編程思想》以及《重構:改善既有代碼質量》是 Java 程序員必看書籍,如果你還沒看過,那就趕緊去亞馬遜買一本吧)中是這樣介紹 equals 方法的:首先 equals 方法必須滿足自反性(x.equals(x) 必須返回true)、對稱性(x.equals(y) 返回true時,y.equals(x) 也必須返回 true)、傳遞性(x.equals(y)和y.equals(z)都返回 true 時,x.equals(z)也必須返回true)和一致性(當x和y引用的對象信息沒有被修改時,多次調用x.equals(y)應該得到同樣的返回值),而且對于任何非 null 值的引用 x,x.equals(null) 必須返回 false。實現(xiàn)高質量的 equals 方法的訣竅包括:

  1. 使用 == 操作符檢查“參數(shù)是否為這個對象的引用”;
  2. 使用 instanceof 操作符檢查“參數(shù)是否為正確的類型”;
  3. 對于類中的關鍵屬性,檢查參數(shù)傳入對象的屬性是否與之相匹配;
  4. 編寫完 equals 方法后,問自己它是否滿足對稱性、傳遞性、一致性;
  5. 重寫 equals 時總是要重寫 hashCode;
  6. 不要將 equals 方法參數(shù)中的 Object 對象替換為其他的類型,在重寫時不要忘掉 @Override 注解。

12. 接口是否可繼承(extends)接口? 抽象類是否可實現(xiàn)(implements)接口? 抽象類是否可繼承具體類(concrete class)?

答:接口可以繼承接口。抽象類可以實現(xiàn)(implements)接口,抽象類可繼承具體類,但前提是具體類必須有明確的構造函數(shù)。

13. 指出下面程序的運行結果:

class A{  

    static{  
        System.out.print("1");  
    }  

    public A(){  
        System.out.print("2");  
    }  
}  

class B extends A{  

    static{  
        System.out.print("a");  
    }  

    public B(){  
        System.out.print("b");  
    }  
}  

public class Hello{  

    public static void main(String[] args){  
        A ab = new B();  
        ab = new B();  
    }  

}  

答:執(zhí)行結果:1a2b2b。創(chuàng)建對象時構造器的調用順序是:先初始化靜態(tài)成員,然后調用父類構造器,再初始化非靜態(tài)成員,最后調用自身構造器。

14. Class.forName(String className)這個方法的作用

答:通過類的全名獲得該類的類對象

15. 什么是 AOP 和 OOP,IOC 和 DI 有什么不同?

答:

1)面向對象編程(Object Oriented Programming,OOP,面向對象程序設計)是一種計算機編程架構。AOP 是 OOP 的延續(xù),是 Aspect Oriented Programming 的縮寫,意思是面向方面編程。 將通用需求功能從不相關類之中分離出來;同時,能夠使得很多類共享一個行為,一旦行為發(fā)生變化,不必修改很多類,只要修改這個行為就可以。AOP 就是這種實現(xiàn)分散關注的編程方法,它將“關注”封裝在“方面”中

2)控制反轉 IOC(Inversion of Control) 控制指的就是程序相關類之間的依賴關系.傳統(tǒng)觀念設計中,

通常由調用者來創(chuàng)建被調用者的實例, 在 Spring 里,創(chuàng)建被調用者的工作不再由調用者來完成,而是由 Spring 容器完成,依賴關系被反轉了,稱為控制反轉,目的是為了獲得更好的擴展性和良好的可維護性。依賴注入(Dependency injection)創(chuàng)建被調用者的工作由 Spring 容器完成,然后注入調用者,因此也稱依賴注入??刂品崔D和依賴注入是同一個概念。

16. 判斷下列語句是否正確,如果有錯誤,請指出錯誤所在?

interface A{

int add(final A a);

}

class B implements A{

long add(final A a){

return this.hashCode() + a.hashCode();

}

}

答:返回值不是 long 類型

上一篇:J2EE 與 EJB下一篇:SSH 架構