1. 程式人生 > >7、 面向物件特性

7、 面向物件特性

1、準備

物件與類:類是具有類似屬性和行為的一類事物的抽象。舉例:人是類,那麼黃藥師就是具體物件。而屬性被抽象為類中的成員變數,行為被抽象為成員方法。

成員變數及成員方法:成員變數通常使用private修飾,阻止本類以外的其他類訪問。成員與區域性變數可以重名,但是需要使用this區分,使用this訪問的為成員變數,直接訪問的為區域性。在方法內訪問變數,如果沒有該名稱的區域性變數會自動查詢是否有該名稱的成員變數。正常定義成員方法時,一般是不需要新增static修飾符的,分為兩種:get或set方法和屬於類的功能的方法。

成員變數及區域性變數區別

類中的位置 記憶體中的位置 生命週期 初始化值
成員變數 類中,方法外 堆記憶體 隨著物件的建立而存在,隨著物件的消失而消失 有預設
區域性變數 方法中或者方法宣告上(形式引數) 棧記憶體 隨著方法的呼叫而存在,隨著方法的呼叫完畢而消失 沒有預設值。必須先定義,賦值,最後使用

建議同學們查查記憶體分析圖,部落格不貼。

2、封裝

原則:將不需要對外提供的內容都隱藏起來。把屬性隱藏,提供公共方法對其訪問。成員變數private,提供對應的get、set方法。

優勢:通過方法來控制成員變數的操作,提高了程式碼的安全性。把程式碼用方法進行封裝,提高了程式碼的複用性。

private關鍵字:是一個許可權修飾符。可以修飾成員(成員變數和成員方法)。被private修飾的成員只在本類(包括其物件)中才能訪問。

this關鍵字:一般出現在類的一個方法的定義當中,代表當前物件的引用。我們通常用其將本物件中的成員與其他作用域區分開來。

public class StudentTest {
	public static void main(String[] args) {
	Student a=new Student();
	Student b=new
Student(); a.setName("龍王"); a.setScore(98); b.setName("獨步王"); b.setScore(96); a.compare(b); System.out.println("參賽者:"+b.getName()+"和"+a.getName()+";刀法能力評判分別為:"+b.getScore()+","+a.getScore()); } } class Student{ private String name; private int score; public String getName() {return name;} public void setName(String name) {this.name = name;} public String getScore(){return score;} public void setScore(){this.score=score;} public void compare(Student s){ if(this.score>s.score(){ System.out.println("勝者是:"+this.name); }else{System.out.println("勝者是:"+s.name);} } }

3、繼承

概念:如果多個類具有相同的屬性和行為,我們可以抽取出共性的內容定義父類,這時再建立相似的類時只要繼承父類即可。子類擁有父類的所有屬性與方法,無需重新定義。並且可以直接使用非私有的父類成員。舉例:父類——動物,子類——貓科、犬科,具體物件——斑點狗。

注意:Java只支援單繼承,不支援多繼承。即只能有一個父類。父類可以繼續有父類。所有類均有父類,只有Object類沒有父類。在所有使用父類型別的地方均可以傳入其子類物件。構造器Constructor不能被繼承,因此不能重寫Override,但可以被過載Overload。

方法重寫:子類可以按照子類自身的邏輯重新定義繼承過來的父類方法,這個重新定義一個方法的過程叫做方法重寫。子類重寫方法時,在宣告前加@Override可檢測該方法是否為重寫的方法。訪問許可權相同或子類方法訪問許可權更大(訪問許可權順序public>預設)。方法名、引數列表、返回值為基本型別時必須相同,返回值為引用型別時相同或子類小。

public class Test{
	public static void main(String[] args) {
	Chinese  c = new Chinese();
	c.setName("張三");//父類繼承方法直接呼叫
	String name = c.getName(); //父類繼承方法直接呼叫
	System.out.println(name); //列印結果為張大力
	c.eat();   //方法重寫後呼叫的為重寫後的方法,按照中國的習慣,使用筷子吃
	}
}
	class Person{
	private String name;
	void eat(){System.out.println("吃飯");}
	public String getName(){return name;}
	public void setName(String s){this.name=s;}
	}
	class Chinese extends Person{
	@override //@override是用於強制規定當前定義的方法一定為重寫的方法
	public void eat() {System.out.println("按照中國的習慣,使用筷子吃");}
	}

抽象:抽象類用來描述一種型別應該具備的基本特徵與功能, 具體如何去完成這些行為由子類通過方法重寫來完成。抽象方法指只有功能宣告,沒有功能主體實現的方法。具有抽象方法的類一定為抽象類。

使用:抽象類無法直接建立物件,只能被子類繼承後,建立子類物件。子類需要繼承抽象父類並完成最終的方法實現細節(即重寫方法,完成方法體)。而此時,方法重寫不再是加強父類方法功能,而是父類沒有具體實現,子類完成了具體實現,我們將這種方法重寫也叫做實現方法。只有覆蓋了抽象類中所有的抽象方法後,其子類才可以例項化。如果存留未實現的抽象方法則該子類仍為一個抽象類,無法建立物件。抽象類不一定包含抽象方法。抽象類可以有非抽象方法。

public class Test {
	public static void main(String[] args) {
	//Animal q = new Animal();抽象類不能建立物件
	Dog d = new Dog();
	d.bark();
	d.sleep();
	d.eat();
	}
}
	abstract class Animal{//abstract在訪問許可權後,返回值型別前修飾方法,方法沒有方法體:
	public abstract void bark()public abstract void sleep();
	public void eat(){System.out.println("吃");}
}
	class Dog extends Animal{
	@Override
	public void bark() {System.out.println("狗汪汪叫!");}
	@Override
	public void sleep() {System.out.println("趴著睡");}
}

4、多型

介面:介面是功能的集合,同樣可看做是一種資料型別,是比抽象類更為抽象的”類”。介面只描述所應該具備的方法,並沒有具體實現,具體的實現由介面的實現類(相當於介面的子類)來完成。這樣將功能的定義與實現分離,優化了程式設計。介面的更為抽象表現為其內的所有方法均為抽象方法,同時不定義普通的成員變數(可以定義靜態常量)。

定義:與定義類的class不同,介面定義時需要使用interface關鍵字。定義介面所在的仍為.java檔案,雖然宣告時使用的為interface關鍵字的編譯後仍然會產生.class檔案。

注意:如同類繼承類後便擁有了父類的成員,可以使用父類的非私有成員。A介面繼承B介面後,A介面便擁有了A、B兩個介面中所有的抽象方法。Java支援一個類同時實現多個介面。 一個類可以有多個介面書寫加上逗號即可implements List,RandomAccess,Cloneable。介面中的成員是有固定修飾符abstract的,如果沒有寫,也會自動加入:(介面中都是常量沒有變數)。

public class Test {
	public static void main(String[] args) {
	DrugDog a= new DrugDog();
	a.eat();
	a.bark();
	a.captureDrug();
	}
}
interface CaptureDrug{
	public abstract void captureDrug();
}
abstract class Dog{
	public abstract void eat();
	public void bark(){System.out.println("汪汪");}
	}
class DrugDog extends Dog implements CaptureDrug{
	public void eat(){System.out.println("吃");}
	public void captureDrug(){System.out.println("緝毒");}
}

多型:Java中多型的程式碼體現在一個子類物件(實現類物件)既可以給這個子類(實現類物件)引用變數賦值,又可以給這個子類(實現類物件)的父類(介面)變數賦值。最終多型體現為父類引用變數可以指向子類物件。多型的前提是必須有子父類關係或者類實現介面關係,否則無法完成多型。在使用多型後的父類引用變數呼叫方法時,會呼叫子類重寫後的方法。多型配合繼承與方法重寫提高了程式碼的複用性與擴充套件性,如果沒有方法重寫,則多型同樣沒有意義。

instanceof關鍵字:通過instanceof關鍵字來判斷某個物件是否屬於某種資料型別。
boolean b = 物件 instanceof 資料型別

轉型:多型本身是子類型別向父類型別向上轉型的過程。向上轉型:當有子類物件賦值給一個父類引用時,便是向上轉型,多型本身就是向上轉型的過程。向下轉型:一個已經向上轉型的子類物件可以使用強制型別轉換的格式,將父類引用轉為子類引用,這個過程是向下轉型。如果是直接建立父類物件,是無法向下轉型的!

細節:編譯時,檢查父類引用變數的資料型別是否包含對應的成員方法與成員變數。執行時,成員方法呼叫子類重寫方法,沒有用private修飾的成員變數訪問時,訪問的為父類型別的。

public class Test {
	public static void main(String[] args) {
	Father f= new Father();
	f.method();
	Son s= new Son();
	s.method();
	Father f2= new Son();//多型本身就是向上轉型。向上轉型後,一切表現形式都是父類的表現形式,不能呼叫子類特有的功能
	f.method();//列印父類方法
	System.out.println(f2.name);//父親
	Son s2=(Son)f2;//向下轉型,使用強制型別轉換進行轉換,向下轉向那個後可以呼叫子類特有方法
	s2.method();//列印子類方法
	System.out.println(s2.name);//兒子
	}
}
	class Father{
	String name="父親";
	public void method(){System.out.println("父類方法");};
}
	class Son extends Father{
	String name="兒子";
	@Override
	public void method(System.out.println("子類方法");){}
}