面向對象
封裝
- 是指隱藏對象的屬性和實現(xiàn)細節(jié)竟稳,僅對外提供公共訪問方式。
- 提高了代碼的復用性地啰,安全性
通過對象去給成員變量賦值亏吝,可以賦值一些非法的數(shù)據(jù)盏混。
public class Student(){
public int age;
}
//main
Student s = new Student();
s.age = -1; //這是不合理的
所以我們將屬性封裝起來,并讓外界通過我指定的通道訪問和修改我的屬性
用private修飾屬性
private關鍵字:
是一個權限修飾符止喷。
可以修飾成員(成員變量和成員方法)
-
被private修飾的成員只在本類中才能訪問
public class Student(){ private int age; public int getAge(){ return this.age弹谁; } public void setAge(int age){ if(age>0&&age<120){ this.age = age; }else{ system.out.println("輸入錯誤"); } } } //main Student s = new Student(); s.age = -1; //輸入錯誤
繼承
概述
- 多個類中存在相同屬性和行為時,將這些內(nèi)容抽取到單獨一個類中沟于,那么多個類無需再定義這些屬性和行為植康,只要繼承那個類即可销睁。
- 通過extends關鍵字可以實現(xiàn)類與類的繼承
class 子類名 extends 父類名 {} - 單獨的這個類稱為父類,基類或者超類睡毒;這多個類可以稱為子類或者派生類檩赢。
- 有了繼承以后,我們定義一個類的時候偶房,可以在一個已經(jīng)存在的類的基礎上军浆,還可以定義自己的新成員乒融。
好處
-
提高了代碼的復用性
- 多個類相同的成員可以放到同一個類中
-
提高了代碼的維護性
- 如果功能的代碼需要修改,修改一處即可
-
讓類與類之間產(chǎn)生了關系愧捕,是多態(tài)的前提
其實這也是繼承的一個弊端:類的耦合性很強開發(fā)的原則:低耦合申钩,高內(nèi)聚。 耦合:類與類的關系 內(nèi)聚:就是自己完成某件事情的能力
java繼承的注意
-
java只支持單繼承邮偎,不支持多繼承禾进。
一個類只能有一個父類廉涕,不可以有多個父類艇拍。class Son extends Futher{} //ok class Son extends Futher,Mother{}//error
-
Java支持多層繼承(繼承體系)
class GrandFuther{} class Futher extends GrandFuther{} class Son extends Futher{}
子類只能繼承父類所有非私有的成員(成員方法和成員變量)
子類不能繼承父類的構造方法淑倾,但是可以通過super關鍵字去訪問父類構造方法征椒。
-
不要為了部分功能而去繼承
class A { public void method1(){} public void method2(){} } class B { public void method2(){} public void method3(){} } //我們發(fā)現(xiàn)B類中出現(xiàn)了和A類一樣的method2()方法勃救,所以蒙秒,我們就用繼承來體現(xiàn) class B extends A { public void method3(){} } 這樣其實不好宵统,因為這樣你不但有了method2(),還多了method1()。 有可能method1()不是你想要的瓢省。 什么時候考慮使用繼承呢? 繼承其實體現(xiàn)的是一種關系:"is a"痊班。 Person Student Teacher Student是Person的一種
-
直接調用屬性名時涤伐,同名屬性的查找順序(就近原則)
子類方法局部->子類成員->父類成員->找不到報錯(單層繼承情況下)
同: 屬性 -> this.屬性 -> super.屬性
this&super
不能在static中使用,static屬于類的
-
調用成員變量
- this.成員變量 調用本類的成員變量
- super.成員變量 調用父類的成員變量
-
調用構造方法
- this(...) 調用本類的構造方法
- super(...) 調用父類的構造方法
-
調用成員方法
- this.成員方法 調用本類的成員方法
- super.成員方法 調用父類的成員方法
構造函數(shù)的關系
子類不繼承父類的構造函數(shù)祝迂,可以用super調用
子類中所有的構造方法再不寫super的情況下默認都會訪問父類中空參數(shù)的構造方法
因為子類會繼承父類中的數(shù)據(jù)型雳,可能還會使用父類的數(shù)據(jù)掌动。
所以,子類初始化之前柑晒,一定要先完成父類數(shù)據(jù)的初始化眷射。
注意:子類每一個構造方法的第一條語句默認都是:super()佛掖,即使刪除也有;
當子類沒有構造函數(shù)的時候芥被,系統(tǒng)默認提供一個無參構造方法
public class Fu { //父類坐榆,提供了有參構造,所有系統(tǒng)不會提供一個無參構造匹中,即沒有無參構造
private String str = "name";
private int i = 1;
public Fu(String str, int i) {
this.str = str;
this.i = i;
}
}
//--------------------
public class Zi extends Fu{//子類沒有提供構造函數(shù)顶捷,系統(tǒng)自動提供一個無參構造屎篱,但是無參構造第一句默認super(),父類沒有重虑,報錯
//error:Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor
//隱式的父類構造函數(shù)fu()是未定義的堪侯。必須顯式調用另一個構造函數(shù)
}
//--------------------
public class Zi extends Fu{//子類也無法提供無參構造
public Zi() {
//error:Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor
//隱式的父類構造函數(shù)fu()是未定義的伍宦。必須顯式調用另一個構造函數(shù)
}
}
- 子類通過super去顯示調用父類其他的帶參的構造方法
- 子類通過this去調用本類的其他構造方法
- 本類其他構造也必須首先訪問了父類構造
一定要注意:
super(…)或者this(….)必須出現(xiàn)在第一條語句
否則,就會有父類數(shù)據(jù)的多次初始化
所以一般建議任何類都提供無參構造
繼承中的方法
子類與父類的方聲明不一樣关贵,一般情況
- 首先在子類中找
- 然后在父類中找
- 如果還是沒有就報錯卖毁。(不考慮多重繼承)
重寫(Override)
子類中出現(xiàn)了和父類中一模一樣的方法聲明,也被稱為方法覆蓋
- 當子類需要父類的功能炭剪,而功能主體子類有自己特有內(nèi)容時翔脱,可以重寫父類中的方法
注意:
父類中私有方法不能被重寫(子類寫了相當于自己的創(chuàng)建方法届吁,不算重寫)
子類重寫父類方法時绿鸣,訪問權限不能更低
-
父類靜態(tài)方法潮模,子類也必須通過靜態(tài)方法進行重寫痴施。(不算是重寫,但現(xiàn)象是這樣)
public class Fu { public static void pri() { System.out.println("a"); } } //---------------------- public class Zi extends Fu{ //This instance method cannot override the static method from Fu public void pri() { System.out.println("b"); } }
多態(tài)
有繼承關系
有方法重寫(沒有方法重寫的多態(tài)將沒有意義)
有父類引用指向子類對象
多態(tài)中的成員訪問特點:
不能調用調用子類特有的屬性和方法
- 成員變量
- 編譯看左邊锉矢,運行看左邊齿尽。
- 構造方法
- 創(chuàng)建子類對象的時候循头,訪問父類的構造方法炎疆,對父類的數(shù)據(jù)進行初始化。
- 成員方法
- 編譯看左邊全跨,運行看右邊浓若。
- 靜態(tài)方法
- 編譯看左邊蛇数,運行看左邊。(靜態(tài)和類相關碌上,算不上重寫浦徊,所以,訪問還是左邊的)
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父類引用指向子類對象霞丧。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//System.out.println(f.num2); //num2 cannot be resolved or is not a field(Fu中找不到num2)
f.show();
//f.method(); //The method method() is undefined for the type Fu(Fu中找不到method)
f.function();
}
}
好處與弊端
- 多態(tài)的好處:
- 提高了代碼的維護性(繼承保證)
- 提高了代碼的擴展性(由多態(tài)保證)
- 多態(tài)的弊端
- 不能調用調用子類特有的屬性和方法
向上向下轉型
向上轉型
Fu f = new Zi();
向下轉型:把父類的引用強轉為子類的引用
Zi z = (Zi)f;
多態(tài)繼承中的內(nèi)存圖解
多態(tài)中的對象變化內(nèi)存圖解
- 不可以訪問子類的方法
- 不可以強轉成其他子類(ClassCastException)
//ClassCastException
DuoTaiDemo f1 = new Zi();
DuoTaiDemo f2 = new DuoTaiDemo();
DuoTaiDemo f3 = (Zi2)f1;
DuoTaiDemo f4 = (Zi)f2;