繼承 extends
多個類有共同的成員變量和成員方法碘橘,可以抽取到另外一個類(父類)仰禽,再讓多個類去繼承這個父類坟瓢,這些類就可以獲取到父類中的成員。
public class ExtendsDemo {
public static void main(String[] args) {
Dota dead = new Dota();
dead.start(); // 啟動游戲
Lol l = new Lol();
l.start(); // 啟動游戲
}
}
class Game {
String name;
double version;
String agent;
public void start() {
System.out.println("啟動游戲");
}
public void exit() {
System.out.println("退出游戲");
}
}
class Dota extends Game {} // Dota繼承Game類
class Lol extends Game {} // Lol繼承Game類
Java中繼承的特點(diǎn)
- 只支持單繼承诚镰,不支持多繼承(即只可以有一個父類)
class sub extends Demo{} // ok
class sub extends Demo1,Demo2{} // error
- 支持多層繼承(繼承體系)
class A{}
class B extends A{}
class C extends B{}
Java中成員變量繼承的特點(diǎn)
- 子類中只能獲取父類中非private的成員變量
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName();
c.sayAge();
}
}
class Dad {
String name = "dad";
private int age = 40;
}
class Child extends Dad {
public void sayName () {
System.out.println(name);
}
public void sayAge () {
System.out.println(age);
}
}
上述例子中月杉,提示Dad.age
這個字段不可見。所以子類中只能獲取父類中非private的成員變量
- 如果子類和父類中的成員變量名字一樣腌歉,那么遵循就近原則
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName(); // child 就近原則 輸出子類中的成員屬性
}
}
class Dad {
String name = "dad";
}
class Child extends Dad {
String name = "child";
public void sayName () {
System.out.println(name);
}
}
- 對于上述的就近原則,可以通過
super
關(guān)鍵字來獲取父類中的成員變量和方法
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName(); // dad
}
}
class Dad {
String name = "dad";
}
class Child extends Dad {
String name = "child";
public void sayName () {
System.out.println(super.name); // super.name 獲取父類中的成員
}
}
- 當(dāng)涉及到局部變量和成員變量重名時(shí),得使用
this
來獲取當(dāng)前類中的成員
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();
c.sayName();
}
}
class Dad {
String name = "dad";
}
class Child extends Dad {
String name = "child";
public void sayName () {
String name = "testName";
System.out.println("父類:" + super.name); // super.name 獲取父類中的成員
System.out.println("當(dāng)前類:" + this.name); // this.name 獲取當(dāng)前類中的成員
System.out.println("局部變量:" + name); // name 獲取當(dāng)前作用域中的局部變量
}
}
Java中成員方法繼承的特點(diǎn)
方法繼承支持重寫(不是重載),子類中的方法和父類中吟吝。的方法完全一致時(shí)剑逃,可以在子類中重寫這個方法蛹磺。子類的對象調(diào)用時(shí)調(diào)用的是子類重寫的方法
關(guān)于重寫有一些注意點(diǎn):
- 在子類重寫的方法中,可以使用
super.methodName()
來執(zhí)行父類中的方法俗或,這么寫既可以使用父類的功能,也可以追加子類的邏輯帅腌。 - 重寫前可以添加注解
@Override
加強(qiáng)規(guī)范 - 不能重寫父類中private的成員變量速客,子類中方法的權(quán)限(如:public)必須要比父類中的權(quán)限等級高溺职。
定義方法的時(shí)候智亮,可以不寫權(quán)限修飾(比如: public), 那么就代表默認(rèn)權(quán)限(如void show() {}
)
Java中構(gòu)造方法的執(zhí)行順序
- 如果子類的構(gòu)造方法中的第一行代碼中沒有調(diào)用父類或者子類的構(gòu)造方法時(shí),那么會默認(rèn)調(diào)用父類的無參構(gòu)造方法
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();// Super Constructor---no Args Sub Constructor---no Args
}
}
class Dad {
public Dad () {
System.out.println("Super Constructor---no Args");
}
public Dad (int num) {
System.out.println("Super Constructor---have Args");
}
}
class Child extends Dad {
public Child () {
System.out.println("Sub Constructor---no Args"); // 第一行沒有調(diào)用父類構(gòu)造方法,默認(rèn)調(diào)用父類無參構(gòu)造
}
public Child (int num) {
System.out.println("Sub Constructor---have Args");
- 可以使用
super()
來在子類的構(gòu)造方法的第一行中調(diào)用父類的構(gòu)造方法
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();// Super Constructor---have Args Sub Constructor---no Args
}
}
class Dad {
public Dad () {
System.out.println("Super Constructor---no Args");
}
public Dad (int num) {
System.out.println("Super Constructor---have Args");
}
}
class Child extends Dad {
public Child () {
super(1); // 調(diào)用了父類的構(gòu)造方法
System.out.println("Sub Constructor---no Args");
}
public Child (int num) {
System.out.println("Sub Constructor---have Args");
}
}
- 不管有沒有參數(shù)削锰,父類的構(gòu)造方法總是優(yōu)先于子類的構(gòu)造方法被執(zhí)行
public class ExtendsDemo {
public static void main(String[] args) {
Child c = new Child();// Super Constructor---no Args Sub Constructor---have Args Sub Constructor---no Args
}
}
class Dad {
public Dad () {
System.out.println("Super Constructor---no Args");
}
public Dad (int num) {
System.out.println("Super Constructor---have Args");
}
}
class Child extends Dad {
public Child () {
this(1); // 調(diào)用了子類的有參構(gòu)造方法
System.out.println("Sub Constructor---no Args");
}
public Child (int num) {
System.out.println("Sub Constructor---have Args");//有參構(gòu)造第一行中沒調(diào)用父類的構(gòu)造方法颅夺,于是默認(rèn)調(diào)用父類的無參構(gòu)造
}
}
this 和 super的區(qū)別
this: 當(dāng)前對象的引用
super:子類對象的父類引用
在構(gòu)造方法中的第一行中吧黄,直接寫this()
或者super()
就是默認(rèn)調(diào)用構(gòu)造方法。
如果子類中沒有制定的成員屬性赵抢,而只有父類中有的時(shí)候烦却,調(diào)用this.xxx
就是訪問的父類的成員屬性
繼承的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 提高代碼的復(fù)用性和可維護(hù)性
缺點(diǎn):
- 類的耦合性增強(qiáng)了
- 開發(fā)的原則:高內(nèi)聚低耦合
- 內(nèi)聚:就是自己完成某件事的能力
- 耦合:類和類的關(guān)系
抽象類
abstract: 關(guān)鍵字车吹,用于修飾方法和類
抽象方法:不同類的方法是相似的窄驹,但是具體邏輯不太一樣,只能抽取聲明丈咐,沒有具體的方法體棵逊。 即沒有方法體的方法就是抽象方法,抽象方法只能在抽象類中使用蛙讥。
抽象類: 有抽象方法的類必須是抽象類次慢。
如果有其他類繼承了抽象類,那必須要重寫其中的抽象方法侵蒙,或者這個類必須也是抽象類。
public class ExtendsDemo {
public static void main(String[] args) {}
}
abstract class Animal { // 有抽象方法的類必須是抽象類
public abstract void eat(); // abstract修飾的是方法是抽象方法 沒有方法體
}
class Cat extends Animal { // 如果一個類繼承了抽象類犁功,而且同時(shí)還不也是一個抽象類的話,那么必須要重寫抽象類中的抽象方法
@Override
public void eat() { // 重寫抽象類中的抽象方法
System.out.println("貓吃魚");
}
}
abstract class Dog extends Animal {} // 抽象類的Dog 本身也是一個抽象類 就不需要重寫抽象方法了
抽象類的特點(diǎn):
- 抽象方法只能在抽象類中
- 抽象類不能實(shí)例化(不能new)
- 抽象類可以有非抽象類(非抽象類被繼承不需要強(qiáng)制重寫)
抽象類的成員的特點(diǎn):
- 成員變量
- 可以有成員變量
- 可以有常量(被final修飾)
- 成員方法
- 可以有抽象方法和非抽象方法
- 構(gòu)造方法
- 可以有構(gòu)造方法(但是不能創(chuàng)建對象)靴庆,因?yàn)樾枰獙︻愔械某蓡T變量進(jìn)行初始化
final: 修飾類炉抒、成員變量、成員方法塞茅,修飾了之后不能被繼承
抽象類的細(xì)節(jié):
- abstract 不可以和 final, private 共存
- 可以有構(gòu)造函數(shù)(因?yàn)橛谐蓡T變量野瘦,要初始化成員變量,同時(shí)還要被繼承,子類繼承父類也要調(diào)用父類的構(gòu)造函數(shù))
- 內(nèi)部也可以沒有抽象方法(當(dāng)不想讓這個不可以類實(shí)例化的時(shí)候,當(dāng)然也可以使用private構(gòu)造函數(shù)來達(dá)到一樣的效果)