1. 程式人生 > >Java 面向物件,封裝,繼承

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