面向對象的想法是模擬現實世界。java
把某樣東西的狀態數據和它的行爲封裝起來,從而達到易用、重用、隱藏內部狀態的目的。安全
通常的變量,如: int a, double b 等,this
咱們定義它以後,它就是一個被動的數據,等特着其它代碼來操做它。spa
而對象,不只含有數據,還有在數據上操做的方法,這樣,數據自己就可能隱藏起來了。設計
外界只須要調用對象的方法來達到操控對象的目的。指針
這對外界而言,增長了易用性,由於這些專門針對該對象的方法,進行了精心設計,能夠避免複雜度,避免一些誤用。code
對對象而言,由於不直接操做它的數據,就達到了保護內部數據的目的,增長了安全性。對象
這樣看來,相比於普通的變量,對象就比如是更智能化的數據。blog
對象是一種複合類型,或說複雜類型。get
由於對象中,可能會包含多個數據,以刻畫對象當前所處的狀態,又包含多個方法,描述對象能夠作出的行爲。
定義一個普通的數據, int a = 100; 就行了,這個類型很簡單。
若是還須要第 2 個, int b = ... 也就搞定。
但若是直接定義一個對象,不管怎麼設計語法,要給出多個數據,多個方法,都確定會冗長。
剛寫好,而後老闆又要再定義 10 個這樣的對象,那就要悲劇了。
爲避免重複與冗長,一個很天然的想法,是先定義一本身的新「類型」,地位至關於 int,
在這個類型中,把對象應該包含的數據、方法一次性描述清楚。
而後用這個新的類型再去定義對象,不就很清晰天然了嗎?
這個新類型,就是咱們所說的----類
以下代碼定義了平面上的"點",它包含 x, y 座標,還有方法,好比:到原點的距離, distance。
1 class MyPoint 2 { 3 private double x; 4 private double y; 5 6 public double distance(){ 7 return Math.sqrt(x * x + y * y); 8 } 9 public void set(double x1, double y1){ 10 x = x1; 11 y = y1; 12 } 13 public double getx(){ 14 return x; 15 } 16 public double gety(){ 17 return y; 18 } 19 }
這段代碼中對 MyPoint 的描述比較簡陋,只有 2 個數據,3 個方法。
數據前邊以 private修飾,表示外界不能直接存取這些數據,達到保護的目的。
但這樣一來,總得給外界提供某種可以訪問 x, y 的方式,不然這些數據就沒什麼價值了。
因此纔有下面的 set, getx, gety 方法,它們負責對 x y 設定新值,以及讀取 x y 的值。
下面看看怎樣使用 MyPoint 這個新類型。
1 public class A0411 2 { 3 public static void main(String[] args){ 4 MyPoint p1 = new MyPoint(); 5 p1.set(10,20); 6 System.out.println(p1.distance()); 7 System.out.println(p1.getx()); 8 System.out.println(p1.gety()); 9 } 10 }
你可能會以爲,這麼繞着彎去操做 x, y 到底有什麼好處呢,看起來還不如直接定義 x, y 更舒服呢。
的確,面向對象在效率上確實有些隕失,但換來了安全性。當軟件變大,變複雜後,安全性、隔離性就很重要了。
對這麼個簡單狀況,固然看不出什麼優點來。
若是必定要看優點,這樣想吧,好比咱們須要對 x y 的值進行限幅操做,x y 的值被限定在 -1000 到 1000 之間,
超出的,取範圍內與設定最接近的值。
此時,咱們只須要對 set 方法進行修改就能夠了,不須要更動其它代碼,尤爲是不須要驚動使用 MyPoint 的代碼,這是個很大的優點,
由於在大型項目中,MyPoint 和使用 MyPoint 的代碼極可能是兩個不一樣的人,甚至是兩個不一樣的團隊寫出來的。
public void set(double x1, double y1){ if(x1 < -1000) x1 = -1000; if(x1 > 1000) x1 = 1000; if(y1 < -1000) y1 = -1000; if(y1 > 1000) y1 = 1000; x = x1; y = y1; }
這也正是「封裝」的含義。
外界只能調用方法,提供必要的參數,而無權干涉對象內部如何處理。
更理論化地說,外界只能向對象發出請求,至於對象如何響應這個請求,外界沒法左右。
外界: 求求你,快把你的座標改成 1200,900 吧。
對象: 纔不呢! 1200超範圍了,我就設爲 1000,900 吧,愛咋地咋地。
不少時候,咱們但願對象剛剛建立之後就持有正確的狀態,而不是每次都很繁瑣地去初始化它的狀態。
好比,MyPoint,可能因爲某種特殊的要求,每次對象默認的初始位置在(100,100)。
這能夠由一個特殊的方法---構造方法來實現。
1 class MyPoint 2 { 3 private double x; 4 private double y; 5 6 public MyPoint(){ 7 x = 100; 8 y = 100; 9 } 10 11 public double distance(){ 12 return Math.sqrt(x * x + y * y); 13 } 14 public void set(double x1, double y1){ 15 if(x1 < -1000) x1 = -1000; 16 if(x1 > 1000) x1 = 1000; 17 if(y1 < -1000) y1 = -1000; 18 if(y1 > 1000) y1 = 1000; 19 x = x1; 20 y = y1; 21 } 22 public double getx(){ 23 return x; 24 } 25 public double gety(){ 26 return y; 27 } 28 } 29 30 public class A0416 31 { 32 public static void main(String[] args){ 33 MyPoint p1 = new MyPoint(); 34 System.out.println(p1.getx() + ", " + p1.gety()); 35 System.out.println(p1.distance()); 36 } 37 }
咱們能夠注意到構造方法與普通方法的不一樣之處。
首先是名字,構造方法與類同名。
而後是調用,構造方法被自動調用了。每次建立對象的時候都會自動地調用構造方法。
還有就是,在對象的整個生存期間,構造方法只會被調用一次。
固然,像普通方法同樣,構造方法也能夠有參數。這些參數在建立對象的時候傳入。
1 class MyPoint 2 { 3 private double x; 4 private double y; 5 6 public MyPoint(){ 7 x = 100; 8 y = 100; 9 } 10 11 public MyPoint(int x1, int y1){ 12 this(); 13 set(x1,y1); 14 } 15 16 public double distance(){ 17 return Math.sqrt(x * x + y * y); 18 } 19 public void set(double x1, double y1){24 if(x>=-1000 && x<=1000) x = x1; 25 if(y>=-1000 && y<=1000) y = y1; 26 } 27 public double getx(){ 28 return x; 29 } 30 public double gety(){ 31 return y; 32 } 33 } 34 35 public class A0416 36 { 37 public static void main(String[] args){ 38 MyPoint p1 = new MyPoint(10,20); 39 System.out.println(p1.getx() + ", " + p1.gety()); 40 System.out.println(p1.distance()); 41 } 42 }
這裏,新增長了一個含有參數的構造方法,與原來的沒有參數的構造方法並存。
這種不一樣的方法具備相同的名字的現象,叫「方法重載」。編譯器根據你傳入的參數的個數和類型能夠很容易區分出你想調用的是哪一個方法,
實際上,在編譯器看來,這兩個方法與不一樣名字的方法根本就沒什麼大不一樣。
還有一個奇怪的語法, this(),這是去調用了不含參數的那個構造方法。
之因此這樣作,是由於 set 方法改變了策略,它對不符合要求的參數,直接忽略了。
爲了防止對象剛建立的時候傳入了很差的參數,咱們先用默認的構造方法保個底,再去試着設置新的值。
那爲何不寫 MyPoint(); 而是搞這麼個怪模樣的 this() 呢?
箇中苦衷外人不知。
原來系統對構造方法特殊對待,要保證它不會隨便被調用,怎麼保證?根本不讓你寫出 MyPoint() 這樣的語句來,會直接編譯錯。
固然在一個構造方法中調用另外一個構造方法應該容許,畢竟這個構造方法自身也保證了不會被調用屢次,
這樣一來就須要網開一面,須要弄出個新的語法來。
那爲何選個 this,有什麼典故不?
有,這是後面要講的 this 引用,一言難盡,暫按下不表。
類與對象的關係就比如「圖紙」與「房屋」的關係。
類描述了對象的構成,對象的行爲。但畢竟它只是「描述」,若是不建立對象,還都只是構想。
類是建立對象所遵守的「施工圖紙」。
由一個類,咱們能夠建立任意多的對象。
最多見的建立對象的手段是 new 關鍵字。每次new 都建立一個對象。
建立對象後會在這個對象上,當即調用構造方法,來初始化對象的內部狀態。
爲了更精確地理解對象的行爲,仍是要區分兩個概念:對象和對它的引用。
在java中,咱們永遠都沒法直接接觸到對象自己,咱們所持有的全部變量,都只多是對象的引用。
引用的本質就是c 語言中的指針概念。但它要更容易使用和管理,固然功能會弱一些。
c 語言中的對指針的許多操做,在 java 中是禁止的。好比: p++ 這樣的常見操做。
MyPoint p = new MyPoint();
這句話中,p 實質是引用,並非對象自己。
咱們能夠經過p 訪問對象的方法,或訪問它的數據(若是其數據定義爲 public的話)
也能夠把p 值賦值給另外一個變量。
MyPoint q = p;
注意,些時,Mypoint 對象只有一個,q 只是個指針,由於賦值,使得p, q 都指向了同一個對象。