封裝,繼承,多態,接口
封裝
封裝的概述和好處:
- 是面向對象三大特征之一
-
是面向對象編程語言對客觀世界的模擬,客觀世界裏成員變量都是隱藏在對象內部的,外界無法直接操作和修改。
封裝原則:
-
將不需要對外提供的內容都隱藏起來。
-
把屬性隱藏,提供公共方法對其訪問。
-
成員變量private,提供對應的getXxx()/setXxx()方法
好處:
-
通過方法來控制成員變量的操作,提高了代碼的安全性
-
把代碼用方法進行封裝,提高了代碼的復用性
public class Student { String name; //int age; Private int age; Public void setAge(inta) { if(a<0 || a>200) { System.out.println("你給的年齡有誤"); }else { age = a; } } Public int getAge() { returnage; } Public void show() { System.out.println("姓名是:"+name+",年齡是:"+age); } } public class DemoStudent { public static void main(String[] args) { //創建學生對象 Student s = new Student(); s.show(); ????????????? s.name = "柳巖"; //s.age = 18; //s.age = -18; //s.setAge(-18); s.setAge(28); s.show(); } }
繼承:
在程序中,如果想聲明一個類繼承另一個類,需要使用extends關鍵字。
格式:
class 子類 extends 父類 {
}
父類內容,子類可以使用
子類特有內容,可以寫在子類中.
class Employee { String name; // 定義name屬性 // 定義員工的工作方法 publicvoid work() { System.out.println("盡心盡力地工作"); } } /* * 定義講師類Teacher繼承員工類Employee */ classTeacherextends Employee { // 定義一個打印name的方法 publicvoidprintName() { System.out.println("name=" + name); } } /* * 定義測試類 */ publicclass Example01 { publicstaticvoid main(String[] args) { Teachert = newTeacher (); // 創建一個講師類對象 t.name = "小明"; // 為該員工類的name屬性進行賦值 t.printName(); // 調用該員工的printName()方法 t.work(); // 調用Developer類繼承來的work()方法 } }
在上述代碼中,Teacher類通過extends關鍵字繼承了Employee類,這樣Teacher類便是Employee類的子類。從運行結果不難看出,子類雖然沒有定義name屬性和work()方法,但是卻能訪問這兩個成員。這就說明,子類在繼承父類的時候,會自動擁有父類的成員。
小結:
繼承是面向對象的核心特性,是面向對象的學習重點。
繼承是代碼復用的重要方式,是類與類之間的一種關系。
從類與類之間的設計關系來看,子類必須屬於父類的一種時,才會繼承。
父類抽取出了共性的內容,子類可以在父類基礎上擴展新的屬性與行為。
子類擁有父類的所有屬性與方法,無需重新定義。並且可以直接使用非私有的父類成員。
Fu類中的成員變量是非私有的,子類中可以直接訪問,若Fu類中的成員變量私有了,子類是不能直接訪問的。
當子父類中出現了同名成員變量時,在子類中若要訪問父類中的成員變量,必須使用關鍵字super來完成。super用來表示當前對象中包含的父類對象空間的引用。
在子類中,訪問父類中的成員變量格式:
super.父類中的成員變量
class Fu { //Fu中的成員變量。 intnum = 5; } classZi extends Fu { //Zi中的成員變量 intnum = 6; void show() { //子父類中出現了同名的成員變量時 //在子類中需要訪問父類中非私有成員變量時,需要使用super關鍵字 //訪問父類中的num System.out.println("Fu num="+super.num); //訪問子類中的num2 System.out.println("Zi num2="+this.num); } } class Demo5 { public static void main(String[] args) { Zi z = new Zi(); //創建子類對象 z.show(); //調用子類中的show方法 } }
繼承-子父類中成員方法特點
當在程序中通過對象調用方法時,會先在子類中查找有沒有對應的方法,若子類中存在就會執行子類中的方法,若子類中不存在就會執行父類中相應的方法。
class Fu{ publicvoid show(){ System.out.println("Fu類中的show方法執行"); } } classZi extends Fu{ public void show2(){ System.out.println("Zi類中的show2方法執行"); } } public class Test{ public static void main(String[] args) { Zi z = new Zi(); z.show(); //子類中沒有show方法,但是可以找到父類方法去執行 z.show2(); } }
繼承特點
Java支持單繼承
Java支持多層繼承
父類定義了繼承樹中共性內容,子類定義了該類個性內容。
在結合多態後,能使用父類時盡量使用父類,提高程序擴展性。
繼承的註意點:
1.java中不支持類的多繼承
class Fu{ } class Zi extends Fu{ } class Zi2 extends Zi, Object{// 錯誤寫法 }
2. java中支持多層繼承
class Grand{} class Fu extends Grand{} class Zi extends Fu{}
缺點:
1. 不支持多繼承(但是保留了多繼承的機制,通過接口體現)
2. 增強類與類之間的耦合性(通過接口的方式可以解決)
附加知識:
this:
含義:
誰調用了this所在的方法, this就代表誰.
//1. 使用在方法中, 解決了成員變量和局部變量重名的問題
public void setName(String name) { this.name = name; }
//2. 可以調用構造方法, 構造方法之間的相互調用(了解即可)
public Student(){ } public Student(String name){ this(); }
//3. 調用普通的成員方法, 學了繼承之後,可以區分子父類的方法
public void show(){ } public void print(){ this.show(); }
匿名對象:
有名字的對象
Student stu = new Student();
匿名對象:
new Student();
使用場景:
1. 用來臨時調用一個方法
2. 可以作為方法參數
3. 可以作為方法的返回值
多態
多態概述:
多態是繼封裝、繼承之後,面向對象的第三大特性。
現實事物經常會體現出多種形態,如學生,學生是人的一種,則一個具體的同學張三既是學生也是人,即出現兩種形態。
Java中多態的代碼體現在一個子類對象(實現類對象)既可以給這個子類(實現類對象)引用變量賦值,又可以給這個子類(實現類對象)的父類(接口)變量賦值。
如Student類可以為Person類的子類。那麽一個Student對象既可以賦值給一個Student類型的引用,也可以賦值給一個Person類型的引用。
^^^^最終多態體現為父類引用變量可以指向子類對象。!!!!!!!!!!!!!!!!!!!
多態的前提是必須有子父類關系或者類實現接口關系,否則無法完成多態。
在使用多態後的父類引用變量調用方法時,會調用子類重寫後的方法。
具體格式如下:
父類引用指向子類對象就是多態的定義格式。同一個父類的方法會被不同的子類重寫為各自的具體實現。在調用方法時,調用的為各個子類重寫後的方法。
父類類型 變量名 = new 子類類型();
變量名.方法名();
此時,雖然該變量指向的是子類對象,但表現為一個父類的形態,可以調用一切父類的方法,子類特有的方法將不能調用。
我們一般在以下場景當中使用多態:
1 成員變量賦值、局部變量賦值
2 方法傳參(最常用最能體現出多態優點的應用)
3 返回返回值
多態的存在意義
當變量名指向不同的子類對象時,由於每個子類重寫父類方法的內容不同,所以會調用不同的方法。
所以多態的存在意義(優點)為:
配合繼承與方法重寫提高了代碼的復用性與擴展性,如果沒有方法重寫,則多態同樣沒有意義。
向上向下類型轉換
多態本身是子類類型向父類類型向上轉型的過程。
多態的轉型分為向上轉型與向下轉型兩種:
1 向上轉型:當有子類對象賦值給一個父類引用時,便是向上轉型,多態本身就是向上轉型的過程。
使用格式:
父類類型 變量名 = new 子類類型();
如:Person p = new Student();
2 向下轉型:一個已經向上轉型的子類對象可以使用強制類型轉換的格式,將父類引用轉為子類引用,這個過程是向下轉型。如果是直接創建父類對象,是無法向下轉型的!
使用格式:
子類類型 變量名 = (子類類型) 父類類型的變量;
如:Student stu = (Student) p; //變量p 實際上指向Student對象
接口:
接口是功能的集合,同樣可看做是一種數據類型,是比抽象類更為抽象的”類”。
接口只描述所應該具備的方法,並沒有具體實現,具體的實現由接口的實現類(相當於接口的子類)來完成。這樣將功能的定義與實現分離,優化了程序設計。
請記住:一切事物均有功能,即一切事物均有接口。
接口的定義:
與定義類的class不同,接口定義時需要使用interface關鍵字。
定義接口所在的仍為.java文件,雖然聲明時使用的為interface關鍵字的編譯後仍然會產生.class文件。這點可以讓我們將接口看做是一種只包含了功能聲明的特殊類。
定義格式:
public interface 接口名 {
抽象方法1;
抽象方法2;
抽象方法3;
}
使用interface代替了原來的class,其他步驟與定義類相同:
1 接口中的方法均為公共訪問的抽象方法
2 接口中無法定義普通的成員變量
類實現接口
類與接口的關系為實現關系,即類實現接口。實現的動作類似繼承,只是關鍵字不同,實現使用implements。
其他類(實現類)實現接口後,就相當於聲明:”我應該具備這個接口中的功能”。實現類仍然需要重寫方法以實現具體的功能。
格式:
class 類 implements 接口 {
重寫接口中方法
}
在類實現接口後,該類就會將接口中的抽象方法繼承過來,此時該類需要重寫該接口的所有抽象方法,完成具體的邏輯。
1 接口中定義功能,當需要具有該功能時,可以讓類實現該接口,只聲明了應該具備該方法,是功能的聲明。
2 在具體實現類中重寫方法,實現功能,是方法的具體實現。
於是,通過以上兩個動作將功能的聲明與實現便分開了。(此時請重新思考:類是現實事物的描述,接口是功能的集合。)
接口中成員的特點
1、接口中可以定義變量,但是變量必須有固定的修飾符修飾,public static final 所以接口中的變量也稱之為常量,其值不能改變。後面我們會講解static與final關鍵字
2、接口中可以定義方法,方法也有固定的修飾符,public abstract
3、接口不可以創建對象。
4、子類必須覆蓋掉接口中所有的抽象方法後,子類才可以實例化。否則子類是一個抽象類。
interface Demo { ///定義一個名稱為Demo的接口。 public static final int NUM = 3;// NUM的值不能改變 public abstract void show1(); public abstract void show2(); } //定義子類去覆蓋接口中的方法。類與接口之間的關系是 實現。通過 關鍵字 implements class DemoImpl implements Demo { //子類實現Demo接口。 //重寫接口中的方法。 public void show1(){} public void show2(){} }
接口特點
1 接口可以繼承接口
如同類繼承類後便擁有了父類的成員,可以使用父類的非私有成員。A接口繼承B接口後,A接口便擁有了A、B兩個接口中所有的抽象方法。
2 Java支持一個類同時實現多個接口,或一個接口同時繼承多個接口。
3 類可以在繼承一個類的同時,實現多個接口。
4 接口與父類的功能可以重復,均代表要具備某種功能,並不沖突
接口和抽象類的區別:
相同點:
1 都位於繼承的頂端,用於被其他類實現或繼承;
2 都不能直接實例化對象;
3都包含抽象方法,其子類都必須覆寫這些抽象方法;
區別:
1 抽象類為部分方法提供實現,避免子類重復實現這些方法,提高代碼重用性;接口只能包含抽象方法;
2 一個類只能繼承一個直接父類(可能是抽象類),卻可以實現多個接口;(接口彌補了Java的單繼承)
二者的選用:
1 優先選用接口,盡量少用抽象類;
2 需要定義子類的行為,又要為子類提供共性功能時才選用抽象類;
封裝,繼承,多態,接口