Java 面向物件,封裝,繼承
1相關概念的理解
1.1面向過程、面向物件
面向過程與面向物件都是程式設計中,編寫程式的一種思維方式。
面向過程的程式設計方式,是遇到一件事時,思考“我該怎麼做”,然後一步步實現的過程。(職員思想)
面向物件的程式設計方式,是遇到一件事時,思考“我該讓誰來做”,然後那個“誰”就是物件,他要怎麼做這件事是他自己的事,反正最後一群物件合力能把事就好就行了。(領導思想)
1.2面向物件思維方式的好處
面向物件思維方式是一種更符合人們思考習慣的思想
面向過程思維方式中更多的體現的是執行者(自己做事情),面向物件中更多的體現是指揮者(指揮物件做事情)。
面向物件思維方式將複雜的問題簡單化。
2類與物件
2.1定義類
事物其實就是由特點(屬性)和行為(功能)組成的。
通過計算機語言Java來描述這個事物,就是定義類,
定義類的格式:
public class 類名 {
//可編寫0至n個屬性
資料型別 變數名1;
資料型別 變數名2;
//可編寫0至n個方法
修飾符 返回值型別 方法名(引數){
執行語句;
}
}
Tips:自定義類中:有main方法,其他方法就要加static,沒有main,就不用加。
例:
public class Car { String color;//顏色 int tyre;//輪胎個數 //功能:跑 public void run(){ System.out.println("顏色為"+color+",輪胎個數為"+tyre+"的小汽車在跑"); } }
public class Test { public static void main(String[] args) { Car c=new Car(); c.color="紅色"; c.tyre=4; c.run(); } }
2.2成員變數和成員方法
類的真正意義就是在描述事物。屬性和功能統稱為事物中的成員。
事物的成員分為兩種:成員屬性和成員功能。
成員屬性在程式碼中的體現就是成員變數
成員功能在程式碼中的體現就是成員方法
2.3類和物件的區別
類是對某一類事物的抽象描述,而物件用於表示現實中該類事物的個體。
舉例:
類是模型
物件是實體
設計時,是先有實體,再抽象出模型。
實際生產時,是先有模型,再有實體。
實際程式設計時,也是如此。
2.4區域性變數和成員變數區別
1)定義的位置不同
成員變數定義在類中
區域性變數定義在方法中或塊(大擴號)中
例:
public class Student { String name; //成員變數 int age; //成員變數 String sex; //成員變數 public void study(String name){ //區域性變數 int book=0; //區域性變數 System.out.println("這個學生姓名為"+name+",年齡為"+age+",性別為"+sex); //這個name就成了區域性變數,就近原則 System.out.println("這個學生讀了"+book+"本書"); } }
2)在記憶體中的位置不同
成員變數儲存在堆記憶體的物件中
區域性變數儲存在棧記憶體的方法中
3)生命週期不同
成員變數隨著物件的出現而出現在堆中,隨著物件的消失而從堆中消失
區域性變數隨著方法的執行而出現在棧中,隨著方法的彈棧而消失
4)初始化不同
成員變數因為在堆記憶體中,所有預設的初始化值
區域性變數沒有預設的初始化值,必須手動的給其賦值才可以使用
2.5基本型別和引用型別作為引數傳遞
例:
public class Test2 { public static void main(String[] args) { int a=1; double b=2; method1(a,b); System.out.println(a); System.out.println(b); } public static void method1(int a,double b){ a=20; b=30; } }
public class Test3 { public static void main(String[] args) { Student s=new Student(); s.name="同學1"; s.age=38; s.sex="男"; method1(s); s.study(); } public static void method1(Student s){ s.name="同學2"; s.age=18; s.sex="男"; } }
當引用變數作為引數傳遞時,這時其實是將引用變數空間中的記憶體地址(引用)複製了一份傳遞給了method1方法的s引用變數。這時會有兩個引用同時指向堆中的同一個物件。當執行method1方法中的s.name="同學2"時,會根據s所持有的引用找到堆中的物件,並將其s屬性的值改為同學2,method1方法彈棧。
由於是兩個引用指向同一個物件,不管是哪一個引用改變了引用的所指向的物件的中的值,其他引用再次使用都是改變後的值。
3封裝
面向物件三大特徵:封裝,繼承,多型
封裝的概念:隱藏了實現細節,還要對外提供可以訪問的方式
3.1封裝表現
1)方法就是一個最基本封裝體。
2)類也是一個封裝體。
3.2封裝的好處
1)提高了程式碼的複用性。
2)隱藏了實現細節,還要對外提供可以訪問的方式。便於呼叫者的使用。這是核心之一,也可以理解為就是封裝的概念。
3)提高了安全性。
封裝舉例:機箱
3.3私有private
舉例:定義一個Person類
Public class Person { String name; int age; }
public class Test { public static void main(String[] args) { Person p1=new Person(); p1.name="小紅帽"; p1.age=-100; //不安全因素 System.out.println(p1.name); System.out.println(p1.age); } }
通過上述程式碼發現,雖然用Java程式碼把Person描述清楚了,但有個嚴重的問題,就是Person中的屬性的行為可以任意訪問和使用。這明顯不符合實際需求(如程式碼中年齡為負值)。
解決辦法:需要使用一個Java中的關鍵字也是一個修飾符 private(私有,許可權修飾符)。只要將Person的屬性和行為私有起來,這樣就無法直接訪問:
public class Person { private String name; private int age; }
這時,Test類中訪問不到了:
然後在Person類中提供對外訪問介面:
public class Person { private String name; private int age; //賦值方法 public void setName(String n){ name=n; } public void setAge(int a){ if(a>=0&&a<=200){ age=a; }else{ age=0; } } //取值方法 public String getName(){ return name; } public int getAge(){ return age; } }
在Test中:
public class Test { public static void main(String[] args) { Person p1=new Person(); p1.setName("小紅帽"); p1.setAge(-100); System.out.println(p1.getName()); System.out.println(p1.getAge()); } }
總結:
類中不需要對外提供的內容都私有化,包括屬性和方法。
以後再描述事物,屬性都私有化,並提供setXxx,getXxx方法對其進行訪問。
注意:私有僅僅是封裝的體現形式而已。
在eclipse中有可以自動新增這兩個方法的功能:
建好成員變數(並私有)後,在程式碼區右鍵-- Source-- Generate Getters and Setters
選擇上變數,就會自動建好了:
3.4 this關鍵字
3.4.1成員變數和區域性變數同名問題
可以在成員變數名前面加上this.來區別成員變數和區域性變數。
3.2.2 this代表本類物件
具體代表哪個物件:
哪個物件呼叫了this所在的方法,this就代表哪個物件。
例:比較年齡
public class Person { private String name; private int age; //賦值方法 public void setName(String n){ name=n; } public void setAge(int a){ if(a>=0&&a<=200){ age=a; }else{ age=0; } } //取值方法 public String getName(){ return name; } public int getAge(){ return age; } //判斷是否同齡人 public boolean compare(Person p){ //傳入一個物件 return this.age==p.age; } }
public class CompareAge { public static void main(String[] args) { Person p1=new Person(); p1.setName("張"); p1.setAge(18); Person p2=new Person(); p2.setName("趙"); p2.setAge(18); boolean flag=p1.compare(p2); System.out.println(flag); } }
3.4.3記憶體解釋(圖稍後再放)
4 繼承
繼承描述的是事物之間的所屬關係,通過繼承可以使多種事物之間形成一種關係體系。
在Java中,類的繼承是指在一個現有類的基礎上去構建一個新的類,構建出來的新類被稱作子類,現有類被稱作父類,子類會自動擁有父類所有可繼承的屬性和方法。
4.1繼承的格式和使用
class 子類 extends 父類 {}
先有父類,再有子類
分析時,是先有子類,再抽象出父類
例:
//員工(父類) public class Emp { String name; int age; public void work(){ System.out.println(name+"員工正在工作"); } }
//研發部員工繼承自員工 public class Rcenter extends Emp { }
//維護部員工繼承自員工 public class Mcenter extends Emp{ //子類獨有方法 public void speak(){ System.out.println("我叫"+name); } }
//測試 public class Test { public static void main(String[] args) { Rcenter r=new Rcenter(); r.name="小豬"; r.age=18; System.out.println(r.name); System.out.println(r.age); r.work(); Mcenter m=new Mcenter(); m.name="小狗"; m.age=17; m.work(); m.speak(); } }
4.2繼承的好處
1)繼承的出現提高了程式碼的複用性,提高軟體開發效率。
2)繼承的出現讓類與類之間產生了關係,提供了多型的前提。
4.3繼承中注意事項
1)類只支援單繼承,不允許多繼承。也就是說一個類只能有一個直接父類(人只能有一個親生父親)
class A{}
class B{}
class C extends A,B{} // 錯誤:C類不可以同時繼承A類和B類
2)多個類可以繼承一個父類(父親可以有多個兒子)
class A{}
class B extends A{}
class C extends A{} // 類B和類C都可以繼承類A
3)多層繼承是可以的,即一個類的父類可以再去繼承另外的父類(祖父,父,兒子)
class A{}
class B extends A{} // 類B繼承類A,類B是類A的子類
class C extends B{} // 類C繼承類B,類C是類B的子類,同時也是類A的子類
4)子類和父類是一種相對概念。一個類是某個類父類的同時,也可以是另一個類的子類。
4.4成員變數、成員方法的變化
1)如果子類父類中出現不同名的成員變數,這時的訪問是沒有任何問題
2)父類中的成員變數是非私有的,子類中可以直接訪問,若父類中的成員變數私有了,子類是不能直接訪問的
3)當父類和子類中有相同的成員變數時,自己有,用自己的,自己沒有,用父類的。(就近原則)
4)當子父類中出現了同名成員變數時,在子類中若要訪問父類中的成員變數,必須使用關鍵字super來完成。super用來表示當前物件中包含的父類物件空間的引用。
Super表示父類物件(super只能子類用)
格式:super.父類中的成員變數
例:
public class Fu { int a=1; }
public class Zi extends Fu{ int a=2; public void method(){ int a=3; System.out.println("a="+a); System.out.println("a="+this.a); System.out.println("a="+super.a); } }
public class Test { public static void main(String[] args) { Zi z=new Zi(); System.out.println("a="+z.a); z.method(); } }
5)若子類中存在就會執行子類中的方法,若子類中不存在就會執行父類中相應的方法。
4.5方法重寫(覆蓋)
4.5.1概念
子類中出現與父類一模一樣的方法時,會出現覆蓋操作,也稱為override重寫、複寫或者覆蓋。
例:
public class Fu { public void show(){ System.out.println("這是父類方法"); } }
public class Zi extends Fu{ //方法重寫 public void show(){ System.out.println("這是子類方法"); } }
public class Test { public static void main(String[] args) { Zi z=new Zi(); z.show(); } }
4.5.2方法重寫(覆蓋)的應用
當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法,這樣,即沿襲了父類的功能,又定義了子類特有的內容。
在子類中,訪問父類中的成員方法格式:
super.父類中的成員方法();
例:
public class Phone { public void show(){ System.out.println("顯示電話號碼"); } public void sendM(){ System.out.println("發簡訊"); } public void call(){ System.out.println("打電話"); } }
public class Iphone extends Phone{ public void show(){ super.show(); //父類方法 System.out.println("顯示姓名"); System.out.println("顯示頭像"); } }
public class Test { public static void main(String[] args) { Iphone i=new Iphone(); i.show(); i.sendM(); i.call(); } }
4.5.3方法重寫注意事項
1)子類方法覆蓋父類方法,必須要保證許可權大於等於父類許可權(修飾符 default或不寫小於public,以後會再學)。
class Fu(){ void show(){} public void method(){} } class Zi extends Fu{ public void show(){} //編譯執行沒問題 void method(){} //編譯錯誤 }
2)寫法上注意:必須一模一樣:方法的返回值型別 方法名 引數列表都要一樣
3)必須有父類,才有方法重寫的概念
對比記憶:方法過載:在同一個類中
練習1:
專案經理類
屬性:姓名 工號 工資 獎金
行為:工作work(列印姓名、工號、工資、獎金)
程式設計師類
屬性:姓名 工號 工資
行為:工作work(列印姓名、工號、工資)
練習2:
已知學生類和老師類如下:
屬性:姓名,年齡
行為:吃飯
老師有特有的方法:講課
學生有特有的方法:學習
練習3:
已知貓類和狗類:
屬性:毛的顏色,腿的個數
行為:吃飯
貓特有行為:抓老鼠catchMouse
狗特有行為:看家lookHome