繼承
繼承的原則
- 一個很好的經驗:“類B是類A的一個特殊化嗎?”
- 如果是則讓類B做類A的子類
class Human
{
public String name = "彭晨";
public int age = 22;
}
class Student extends Human
{
public double score = 99;
}
class Postgraduate extends Student
{
public String daoshi = "郝斌";
}
class M
{
public static void main(String[] args)
{
Postgraduate gd = new Postgraduate();
System.out.printf("%s %d %f %s\n",gd.name,gd.age,gd.score,gd.daoshi);
}
}
程序運行示例:
————————————————————————————————————————
彭晨 22 99.000000 郝斌
————————————————————————————————————————
-
一個新類從已有的類那裏獲得其已有的屬性和方法,這種現象叫做類的繼承
-
這個新類被稱爲子類或者派生類,已有的那個類叫做父類或者叫做基類
-
繼承的好處
- 代碼得到極大的重用
- 形成一種類的層次體系結構
- 爲多態創造條件(OOP第三個特點)
-
繼承的實現方式
-
class SubClass extends SuperClass
-
{
…
-
}
-
同包繼承權限問題(重點)
- 子類的所有方法內部都可以訪問父類除私有成員以外的所有成員,所謂子類的所有方法也包括子類的私有方法
- 通過子類對象名可以訪問
- 父類除私有成員外的所有成員
- 子類本身的除私有成員外的所有成員
- 附註,私有成員包括私有屬性和私有方法
- 子類可以繼承父類除私有屬性和私有方法以外的所有成員
- 父類的私有成員不可以被子類繼承,其他的成員都可以被子類繼承
- 不同包繼承問題等講到包再說!!
class A
{
public int i;
protected int j;
private int k;
public void g()
{
}
protected void f()
{
}
private void b()
{
}
}
class B extends A
{
private void m()
{
i = 20;
j = 30;
// k =40; //error k 在 A 中是 private 訪問控制
g();
f();
}
}
class M
{
public static void main(String[] args)
{
B bb = new B();
bb.i = 10;
bb.j = 40;
bb.b();
bb.m();
bb.k = 3;
}
}
程序運行示例:
————————————————————————————————————————
M.java:39: 錯誤: 找不到符號
bb.b();
^
符號: 方法 b()
位置: 類型爲B的變量 bb
M.java:40: 錯誤: m() 在 B 中是 private 訪問控制
bb.m();
^
M.java:41: 錯誤: k 在 A 中是 private 訪問控制
bb.k = 3;
^
3 個錯誤
————————————————————————————————————————
子類訪問父類成員的三種方式
- 在子類內部訪問父類成員
- 通過子類對象名訪問父類成員
- 通過子類的類名訪問父類成員
經驗證,子類通過上述三種方式的任何一種都無法訪問父類私有成員,因此我們可以得出結果:
私有成員無法被子類繼承
class A
{
public static int i;
protected int j;
private static int k;
}
class B extends A
{
public static void g()
{
i = 20;
// k = 20;
}
}
class M
{
public static void main(String[] args)
{
//B bb = new B();
//bb.i = 99;//OK
B.g();
System.out.printf("%d\n",B.k);
/**
程序運行示例:
———————————————————————————
k 在 A 中是 private 訪問控制
System.out.printf("%d\n",B.k);
^
1 個錯誤
————————————————————————————
*/
System.out.printf("%d\n",B.i);
/**
程序運行示例:
———————————————————————————
20
————————————————————————————
*/
}
}
super()相關
class A
{
public int i;
public int j;
public A()
{
}
public A(int i,int j)
{
this.i = i;
this.j = j;
}
}
class B extends A
{
public int k;
public void f(int i)
{
// super(i);
/**
程序運行示例:
———————————————————————————————————————
M.java:22: 錯誤: 對super的調用必須是構造器中的第一個語句
super(i);
^
1 個錯誤
————————————————————————————————————————
*/
}
public B(int i,int j,int k)
{
// this.i = i; //一定要明白爲什麼i前面可以加this
// this.j = j;
// A(i,j);
/**
程序運行示例:
———————————————————————————————————————
M.java:24: 錯誤: 找不到符號
A(i,j);
^
符號: 方法 A(int,int)
位置: 類 B
1 個錯誤
————————————————————————————————————————
*/
// super(i,j);//OK
/**
程序運行示例:
———————————————————————————————————————
10 39 22
————————————————————————————————————————
*/
this.k = k;
}
}
class M
{
public static void main(String[] args)
{
B bb = new B(10,39,22);
System.out.printf("%d %d %d\n",bb.i,bb.j,bb.k);
}
}
上述代碼總結:
1、 每個子類構造方法的第一條語句,都是隱含地調用super(),如果父類沒有這種形式的構造函數,那麼在編譯的時候 就會報錯。
2、如果顯示的寫出super()語句,則必須保證該語句是第一條語句,否則會出錯
3、super();如果不寫,則編譯器會自動添加,所以此時如果父類沒有無參的構造函數就會出錯。
4、既可以顯示寫super();前提是父類必須有無參的構造函數
5、調用父類的構造函數的語句必須藉助於super(),不能直接寫父類的的類名,該與C++不同
6、一個構造函數中不能寫多個super(參數列表)語句;
總結
- 私有不能被繼承
- 私有物理上已經被繼承過來,只不過邏輯上程序員不能去訪問它
- 因此繼承必須慎重,否則會浪費內存
- Java只支持單繼承,不允許多重繼承(這一缺陷通過接口來稍稍彌補了一下)
- 單繼承就是一個類只能有一個父類
- 多繼承就是一個類可以多個父類
- 可以有多層繼承,即一個類可以繼承某一個類的子類,如類B繼承了類A,類C又可以繼承類B,那麼類C也間接繼承了類A
- 子類可以繼承父類所有的成員變量和成員方法,但子類永遠無法繼承父親的構造方法,在子類的構造方法中可使用語句super(參數列表)調用父類的構造方法。