面向對象
面向對象思想
構造器:new就是一個構造器,作用是:①分配空間;②賦初始值(避免錯誤,簡化輸入)
new Object(Parameters)構造器調用構造函數,傳參為了賦初始值;
對象的基本元素是:屬性和方法 類成員(屬性和方法)。屬性最為重要,屬性的集合是一個狀態,方法是一個狀態到另一個狀態的橋梁
封裝:屬性和處理屬性的方法集合起來。
把數據及數據的操作方法放在一起,作為一個相互依存的整體,即對象。
面向對象是基於面向過程而言的,面向對象是將功能等通過對象來實現,將功能封裝進對象之中,讓對象去實現具體的細節;這種思想是將數據作為第一位,而方法或者說是算法作為其次,這是對數據一種優化,操作起來更加的方便,簡化了過程。
面向對象的三個基本特征
封裝,就是把客觀的事物封裝成抽象的類,並且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的信息隱藏。隱藏實現細節,使得代碼模塊化。
繼承,可以使用現有類的所有功能,並在無需重新編寫原來的類的情況下對這些功能進行擴展。可以擴展已存在的代碼模塊。
多態,是允許你將父對象設置成為和一個或更多的他的子對象相等的技術,賦值之后,父對象就可以根據當前賦值給它的子對象的特性以不同的方式運作。父類引用指向子類對象。
封裝
訪問權限的控制常被稱為是具體實現的隱藏。把數據和方法包裝進類中,以及具體實現的隱藏共同被稱為封裝。
|
public |
protected |
default |
private |
同類 |
√ |
√ |
√ |
√ |
同包 |
√ |
√ |
√ |
|
子類 |
√ |
√ |
|
|
通用性 |
√ |
|
|
|
public:可以被所有其他類訪問
protected:自身、子類、及同一個包中類(接受包外的子類訪問)
default:同一包中的類可以訪問,聲明時沒有加修飾符,認為是friendly(拒絕一切外包訪問)
private:只能被自己訪問和修改
類的訪問控制符只有三種:public、private、protected
default是無訪問控制符。
繼承extend
在一個子類被創建的時候,首先會在內存中創建一個父類對象,然后在父類對象外部放上子類獨有的屬性,兩者合起來形成一個子類的對象。所以所謂的繼承使子類擁有父類所有的屬性和方法,但是父類對象中的私有屬性和方法,子類是無法訪問到的,只是擁有,但不能使用。子類不能繼承父類的構造函數,只是顯式或隱式調用,可以從子類調用超類的構造函數。
用new創建子類的對象時,若子類沒有帶參構造函數,將先執行父類的無參,然后再執行自己的構造函數。父類定義了有參的構造函數后,可以不定義無參的構造函數,系統也不會提供默認的無參構造函數。這時子類只能調用父類的有參構造函數。
Java類是單繼承,Java接口可以多繼承。類可以實現多個接口,接口可以繼承(擴展)多個接口
先繼承后實現接口
組合和繼承
組合是指在新類里面創建原有的類的對象,重復利用已有類的功能。(“has - a”)
組合和繼承都允許在新的類中設置子對象,只是組合是顯式的,而繼承是隱式的。組合中的整體類和繼承中的子類對應,組合中的局部類和繼承中的父類對應。
組合和繼承的選擇規則:
① 除非兩個類之間是“is - a”的關系,否則不要輕易地使用繼承。過多的使用繼承會破壞代碼的可維護性,當父類修改時,會影響所有繼承他的子類,增加了程序維護的難度和成本。
②不要僅僅為實現多態而使用繼承,如果類之間沒有“is - a”關系,可以通過實現接口與組合的方式來達到相同的目的。
多態
http://blog.csdn.net/sinat_18882775/article/details/50154491
定義:不同類的對象對同一消息做出響應。同一消息可以根據發送對象的不同而采用多種不同的行為方式。
多態存在的三個必要條件:繼承、重寫、父類引用指向子類對象。
Java中多態的實現方式:接口實現,繼承父類進行方法重寫,同一個類中進行方法重載。
父類引用指向子類對象,該引用不能再訪問子類新增的成員。Animal cat = new Cat()
直接new一個父類實例(Animal a = new Animal())的區別?
答:當父類是接口和抽象類時,不能實例化,只能運用多態,向上轉型。普通類中,可以在子類中重寫父類中的方法,這樣就可以訪問子類中的重寫方法。
重寫和重載
方法重載(overload):
(1)必須是同一個類
(2)方法名(也可以叫函數)一樣
(3)參數類型不一樣或參數數量或順序不一樣
(4)不能通過返回值來判斷重載
方法的重寫(override)子類重寫了父類的同名方法,兩同兩小一大原則:
(1)方法名相同,參數類型相同
(2)子類返回類型是父類返回類型的子類。
(3)子類拋出異常小於等於父類方法拋出異常,
(4)子類訪問權限大於等於父類方法訪問權限。
重載(Overload) |
重寫(Override) |
同一個類中方法之間的關系,水平關系 |
父類與子類之間,垂直關系 |
通過不同的方法參數來區分(參數的類型,個數,順序) |
參數列表、返回值類型必須一致,方法體不同 |
不能通過訪問權限、返回值類型和拋出的異常類型來進行重載 |
子類訪問權限大於等於父類的訪問權限 父類中被重寫的方法不能為private |
在重寫中,運用的是動態單分配,根據new的類型確定對象,從而確定調用的方法
在重載中,運用的是靜態多分派,根據靜態類型確定對象,不能根據new的類型確定調用方法。
多態中,Father f = new Son()
成員變量:編譯運行參考左邊;
成員函數:編譯看左邊,運行看右邊;
靜態函數:編譯運行看左邊。
構造函數
用來在對象實例化時初始化對象的成員變量。
特點:
① 方法名必須和類名相同,不能有返回值(也不能為void);
② 一個類可以有多個構造函數,沒有定義的話,編譯器會在源代碼編譯成字節碼文件的過程中會提供一個沒有參數默認的構造方法。若定義后,不會再創建默認的構造方法;
③構造函數的參數有(0到多個);
④構造函數在對象實例化時會被自動調用,且只運行一次;普通方法是在程序執行到時才調用且可以被該對象調用多次;
⑤構造函數的作用是完成對象的初始化;
⑥構造函數不能被繼承,不能被覆蓋,能被重載。
⑦子類可以通過super()關鍵字來顯示調用父類的構造函數,父類沒有提供無參構造,子類的構造函數中必須顯式得調用父類的構造函數。
⑧父類和子類都沒有定義構造函數時,編譯器都會為父類生成一個默認的無參構造,給子類也生成一個默認的無參的構造函數。
⑨構造方法會在成員變量之后初始化。
⑩構造方法不能被static、final、synchronize、abstract、native修飾,但可以被public、private、protect修飾。
在繼承的時候,父類當然也有構造方法,如果你要創建子類的對象,那么執行的過程首先是調用父類的無參構造方法生成父類的對象,然后再調用子類的無參構造方法來生成子類對象。繼承的時候都是先生成父類的對象,然后再生成子類的對象。
通過使用this關鍵字帶上參數,可以在一個構造函數中調用另外一個構造函數。這是this除了單純表示"當前對象"(注意是針對對象而不是類的概念)之外的第二個作用。但是注意3點:
第一點,必須放在第一行。
第二點,只能調用一個其它的構造函數。(也許可以這樣理解,正是因為有了第一點,如果可以調用多個的話,那么就無法放在"第一行",所以只能允許一次調用)
第三點,只能是構造函數調用構造函數,普通函數無法調用構造函數。
super()和this()
super()關鍵字表示超類的意思,當前類是從超類繼承而來。
this指代當前對象。
只有在重寫(Override)父類的方法中,子類要調用繼承自父類的方法,才使用super關鍵字。
使用super()或者this()方法是必須放在構造函數的第一行。
由於this函數指向的構造函數默認有super()方法,所以規定this()和super()不能同時出現在一個構造函數中。
因為static方法或者語句塊沒有實例時可以使用,而此時不需要構造實例,所以不能用this()和super()。
abstract(抽象類)和Interface(接口)
抽象類
用abstract修飾的類表示抽象類,抽象類位於繼承樹的抽象層,抽象類不能被實例化。
用abstract修飾的方法表示抽象方法,抽象方法沒有方法體。抽象方法用來描述系統具有什么功能,但不提供具體的實現,把具體實現留給繼承該類的子類。
特點:
a.含有抽象方法的類必須聲明為抽象類(不管其中是否有其他方法)
b.抽象類可以沒有抽象方法,可以有普通方法。
c.抽象類必須被繼承,抽象方法必須被重寫(若子類還是抽象類,不需要重寫)
d.抽象類不能被實例化(不能直接構造一個該類的對象)
抽象方法
a.在類中沒有方法體(抽象方法只需聲明,而不需實現某些功能);
b.抽象類中的抽象方法必須被實現;
c.如果一個子類沒有實現父類中的抽象方法,則子類也變成了一個抽象類;
接口
interface 中的方法默認為public abstract (public、abstract可以省略),變量默認為public static final;類中的方法全部都是抽象方法。只有聲明沒有實現,在不同類中有不同的方法實現。
不同點:
(1)接口中只能包含抽象方法和默認方法,不能為普通方法提供方法實現;抽象類中可以包含普通方法。
(2)接口里不能定義靜態方法(jdk1.8下可以定義static方法),抽象類可以定義靜態方法。
(3)接口中只能定義靜態常量,不能定義普通成員變量;抽象類即可以定義變量又可以定義靜態常量。
(4)接口中不包含構造器,抽象類里可以包含構造器,抽象類中的構造器並不是用於創建對象,而是讓其他子類調用這些構造器來完成抽象類的初始化操作。
(5)接口里不能包含初始化塊,但抽象類可以包含。
(6)一個類最多只能有一個父類,包括抽象類;但一個類可以直接實現多個接口,通過實現多個接口可以彌補Java單繼承的不足。
共同點:
(1)接口和抽象類都不能被實例化,都位於繼承樹的頂端,用於被其他類實現的繼承。
(2)接口和抽象類都可以包含抽象方法,實現接口和繼承抽象類的普通子類都必須實現這些方法。
|
抽象類 |
接口 |
方法 |
普通方法、抽象方法 |
只能有抽象方法和默認方法 |
靜態方法 |
可以定義 |
不能定義(jdk1.8下可以定義) |
默認訪問權限 |
jdk1.8前為protected jdk1.8后為default |
jdk1.8前為public jdk1.8為public或default |
變量 |
定義變量、靜態常量 |
只能定義靜態常量 |
構造器 |
可以包含(不是用來創建對象,而是讓其他子類調用,完成初始化操作) |
不能包含 |
初始化塊 |
可以包含 |
不能包含 |
繼承 |
只能有一個父類,但可以實現多個接口 |
接口可以繼承多個接口 |
實例化 |
接口和抽象類都不能被實例化,都位於繼承樹的頂端,用於被其他類實現的繼承。 |
final
final修飾的類,就是最終類,不能被繼承。
final修飾的方法,就是最終方法,最終方法不能被重寫。
final修飾一個引用變量時,是指引用變量不能變,引用變量所指向的對象中的內容還是可以改變的。修飾基本數據類型變量時,內容不能變。
final成員變量必須在初始化代碼塊或在構造器中初始化。
作用:
final類:如果一個類不需要有子類,類的實現細節不允許改變,並且確信這個類不會再被擴展,那么就設計成final類。
final方法:①把方法鎖定,防止任何繼承類修改它的意義和實現。②高效,編譯器在遇到調用final方法時候會轉入內嵌機制,大大提升執行效率。
static
static修飾的變量稱為靜態變量,靜態變量屬於整個類,而局部變量屬於方法,只在該方法內有效。static不能修飾局部變量。static方法內部不能調用非靜態方法。
靜態變量只能在類主體中定義,不能在方法中定義。
static變量只會創建一份,不管創建幾個對象,都共用一個變量。
類方法指被static修飾的方法,無this指針。其他的就是實例方法。類方法可以調用其他類的static方法
類方法和對象方法的區別
1、類方法是屬於整個類的,而實例方法是屬於類的某個對象的。
由於類方法是屬於整個類的,並不屬於類的哪個對象,所以類方法的方法體中不能有與類的對象有關的內容。即類方法體有如下限制:
(1) 類方法中不能引用對象變量;
(2) 類方法中不能調用類的對象方法;
(3) 在類方法中不能使用super、this關鍵字。(this表示當前類的對象,由static修飾的方法是類直接調用,不需要創建對象,所以不能用this)
(4)類方法不能被覆蓋。
2、與類方法相比,對象方法幾乎沒有什么限制:
(1) 對象方法中可以引用對象變量,也可以引用類變量;
(2) 對象方法中可以調用類方法;
(3) 對象方法中可以使用super、this關鍵字。
static關鍵字的作用
為某特定數據類型或對象分配單一的存儲空間,而與創建對象的個數無關;實現某個方法或屬性與類而不是對象關聯在一起。
靜態變量屬於類,在內存中只有一個復制,只要靜態變量所在的類被加載,這個靜態變量就會被分配空間。
類修飾符
http://blog.csdn.net/dawn_after_dark/article/details/74527137
(1)外部修飾類
1、protected 和 private 不能修飾外部類,是因為外部類放在包中,只有兩種可能,包可見和包不可見。
2、final 和 abstract不能同時修飾外部類,因為該類要么能被繼承要么不能被繼承,二者只能選其一。
3、不能用static修飾,因為類加載后才會加載靜態成員變量。所以不能用static修飾類和接口,因為類還沒加載,無法使用static關鍵字。
(2)內部修飾類
內部類與成員變量地位一直,所以可以public、protected、default和private,同時還可以用static修飾,表示嵌套內部類,不用實例化外部類,即可調用。
靜態塊和構造塊
public class B{ public static B t1 = new B(); public static B t2 = new B(); { System.out.println("構造塊"); } static{ System.out.println("靜態塊"); } public static void main (String args){ B t = new B(); } }
以上代碼的輸出結果是:構造塊 構造塊 靜態塊 構造塊
(1)靜態塊:用static聲明,JVM加載類時執行,僅執行一次,按聲明順序執行。
(2)構造塊:類中直接用{}定義,每一次創建對象時執行
靜態域中包含靜態變量、靜態塊和靜態方法,其中需要初始化的是靜態變量和靜態塊。而他們兩個的初始化順序是靠他們的位置決定。
靜態變量只能在類主體中定義,不能在方法中定義。
執行的順序優先級:靜態域>main()>構造塊>構造方法
程序初始化順序
1.父類靜態變量
2.父類靜態代碼塊
3.子類靜態變量
4.子類靜態代碼塊
5.父類非靜態變量
6.父類非靜態代碼塊
7.父類構造器
8.子類非靜態變量
9.子類非靜態代碼塊
10.子類構造器
先靜態后非靜態,先父類后子類。
按成員變量的定義順序進行初始化。即使變量定義散布於方法之中。
內部類
為什么使用內部類:
每個內部類都能獨立地繼承一個接口的實現,所以無論外圍類是否已經繼承了某個(接口)的實現,對於內部類沒有任何影響。能非常好的解決多重繼承的問題。
把一個類定義在另一個類的內部,在類里面的這個類就叫做內部類,外面的類叫做外部類。內部類可以被看做外部類的一個成員。內部類分為4種:
靜態內部類(static inner class)
被聲明為static的內部類,可以不依賴於外部類實例而被實例化,而通常的內部類需要在外部類實例化后才能實例化。靜態內部類不能與外部類有相同的名字,不能訪問外部類的普通成員變量,只能訪問外部類中的靜態成員和靜態方法。
成員內部類(member inner class)
靜態內部類去掉static就是成員內部類,成員內部類為非靜態內部類,可以自由地引用外部類的屬性和方法,無論靜態還是非靜態,但是它與實例綁定在一起,不可以定義靜態屬性和方法。
1.外部類是不能直接使用內部類的成員和方法的,可先創建內部類的對象,然后通過內部類的對象來訪問其成員變量和方法;
2.如果外部類和內部類具有相同的成員變量或方法,內部類默認訪問自己的成員變量或方法,如果要訪問外部類的成員變量,
可以使用 this 關鍵字,如:Outer.this.name
局部內部類(local inner class)
局部內部類是定義在一個代碼塊內的類,它的作用范圍為其所在的代碼塊。局部內部類像局部變量一樣,不能別public、protected、private以及static修飾,只能訪問方法中的final類型的局部變量。
匿名內部類(anonymous class)
http://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html
是這一種沒有類名的內部類,不使用關鍵字class、extends、implements,沒有構造函數,必須繼承其他類或實現一個接口。好處是代碼簡潔,問題是易讀性下降。
匿名內部類不能有構造函數,不能定義靜態變量、方法,不能是public、protected、private、static 。只能創建匿名內部類的一個實例,匿名內部類一定是在new的后面。