Java基礎(chǔ)第九天
繼承概述引入 首先我來(lái)寫(xiě)兩個(gè)代碼: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //定義學(xué)生類
class Student
{
public void study(){
System.out.println( "在教室學(xué)習(xí)" );
}
}
//定義老師類
class Teacher
{
public void teach(){
System.out.println( "在教室教書(shū)" );
}
}
|
我們觀察上面兩個(gè)代碼: 發(fā)現(xiàn)name,,age成員變量,以及getXxx()/setXxx(),還有eat()等都是相同的。 如果我們后來(lái)繼續(xù)定義類,,舉例:工人類,,軍人類,。他們是不是也具備這些內(nèi)容。 那么,,我們每一次定義這樣的類的時(shí)候,,都要把這些重復(fù)的內(nèi)容都重新定義一遍。 麻煩不?麻煩,。所以,,我們要考慮改進(jìn)? 如何改進(jìn)呢? 我這樣想的:我能不能把這些相同的內(nèi)容給定義到一個(gè)獨(dú)立的類中。
然后,讓這多個(gè)類和這個(gè)獨(dú)立的類產(chǎn)生一個(gè)關(guān)系,,有了這個(gè)關(guān)系后,, 這多個(gè)類就可以具備這個(gè)獨(dú)立的類的功能。 為了實(shí)現(xiàn)這個(gè)效果,,java就提供了一個(gè)技術(shù):繼承,。
父親: 4個(gè)兒子 繼承怎么表示呢?繼承的格式是什么樣子的呢? 1 2 3 4 5 | class Fu {}
class Zi extends Fu {
}
|
我們就回頭修改我們的代碼: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class Person
{
String name;
int age;
public void eat(){
System.out.println( "吃飯" );
}
}
class Student extends Person
{
public void study(){
System.out.println( "在教室學(xué)習(xí)" );
}
}
class Teacher extends Person
{
public void teach(){
System.out.println( "在教室教書(shū)" );
}
}
class Worker extends Person
{
public void work(){
System.out.println( "在工作" );
}
}
|
繼承概述多個(gè)類中存在相同屬性和行為時(shí),將這些內(nèi)容抽取到單獨(dú)一個(gè)類中,,那么多個(gè)類無(wú)需再定義這些屬性和行為,,只要繼承那個(gè)類即可。 通過(guò)extends關(guān)鍵字可以實(shí)現(xiàn)類與類的繼承 class 子類名 extends 父類名 {} 單獨(dú)的這個(gè)類稱為父類,,基類或者超類,;這多個(gè)類可以稱為子類或者派生類。 有了繼承以后,,我們定義一個(gè)類的時(shí)候,,可以在一個(gè)已經(jīng)存在的類的基礎(chǔ)上,還可以定義自己的新成員,。
繼承的案例和繼承的好處通過(guò)一個(gè)具體案例來(lái)演示代碼 案例1:學(xué)生類和老師,。定義兩個(gè)功能(吃飯,睡覺(jué)) 案例2:加入人類后改進(jìn),。
/* 繼承概述: 把多個(gè)類中相同的內(nèi)容給提取出來(lái)定義到一個(gè)類中,。
如何實(shí)現(xiàn)繼承呢? Java提供了關(guān)鍵字:extends
格式: class 子類名 extends 父類名 {}
好處: A:提高了代碼的復(fù)用性 B:提高了代碼的維護(hù)性 C:讓類與類之間產(chǎn)生了關(guān)系,是多態(tài)的前提 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | class Person
{
String name;
int age;
public void eat(){
System.out.println( "吃飯" );
}
}
class Student extends Person
{
public void study(){
System.out.println( "在教室學(xué)習(xí)" );
}
}
class Teacher extends Person
{
public void teach(){
System.out.println( "在教室教書(shū)" );
}
}
class Worker extends Person
{
public void work(){
System.out.println( "在工作" );
}
}
class PersonTest
{
public static void main(String[] args)
{
Student s = new Student();
s.eat();
s.study();
Teacher t = new Teacher();
t.eat();
t.teach();
Worker w = new Worker();
w.eat();
w.work();
System.out.println( "Hello World!" );
}
}
|
繼承的好處提高了代碼的復(fù)用性 多個(gè)類相同的成員可以放到同一個(gè)類中 提高了代碼的維護(hù)性 如果功能的代碼需要修改,,修改一處即可 讓類與類之間產(chǎn)生了關(guān)系,,是多態(tài)的前提 Java中繼承的特點(diǎn)Java只支持單繼承,不支持多繼承,。 一個(gè)類只能有一個(gè)父類,,不可以有多個(gè)父類。 class SubDemo extends Demo{} //ok class SubDemo extends Demo1,Demo2...//error Java支持多層繼承(繼承體系) class A{} class B extends A{} class C extends B{} /* Java中繼承的特點(diǎn): A:Java只支持單繼承,,不支持多繼承。 有些語(yǔ)言是支持多繼承,,格式:extends 類1,類2,... B:Java支持多層繼承(繼承體系) */ /* class Father {} class Mother {} class Son exnteds Father {} //正確的 class Son extends Father,Mother {} // 錯(cuò)誤的 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class GrandFather {
public void show() {
System.out.println( "我是爺爺" );
}
}
class Father extends GrandFather {
public void method(){
System.out.println( "我是老子" );
}
}
class Son extends Father {}
class ExtendsDemo2 {
public static void main(String[] args) {
Son s = new Son();
s.method(); //使用父親的
s.show(); //使用爺爺?shù)?/code>
}
}
|
Java中繼承的注意事項(xiàng)子類只能繼承父類所有非私有的成員(成員方法和成員變量) 其實(shí)這也體現(xiàn)了繼承的另一個(gè)弊端:打破了封裝性 子類不能繼承父類的構(gòu)造方法,,但是可以通過(guò)super(后面講)關(guān)鍵字去訪問(wèn)父類構(gòu)造方法。 不要為了部分功能而去繼承 我們到底在什么時(shí)候使用繼承呢? 繼承中類之間體現(xiàn)的是:”is a”的關(guān)系,。 /* 繼承的注意事項(xiàng): A:子類只能繼承父類所有非私有的成員(成員方法和成員變量) B:子類不能繼承父類的構(gòu)造方法,,但是可以通過(guò)super(馬上講)關(guān)鍵字去訪問(wèn)父類構(gòu)造方法。 C:不要為了部分功能而去繼承 class A { public void show1(){} public void show2(){} }
class B { public void show2(){} public void show3(){} }
//我們發(fā)現(xiàn)B類中出現(xiàn)了和A類一樣的show2()方法,,所以,,我們就用繼承來(lái)體現(xiàn) class B extends A { public void show3(){} } 這樣其實(shí)不好,因?yàn)檫@樣你不但有了show2(),還多了show1()。 有可能show1()不是你想要的,。
那么,,我們什么時(shí)候考慮使用繼承呢? 繼承其實(shí)體現(xiàn)的是一種關(guān)系:"is a"。 Person Student Teacher 水果 蘋(píng)果 香蕉 橘子
采用假設(shè)法,。 如果有兩個(gè)類A,B,。只有他們符合A是B的一種,或者B是A的一種,,就可以考慮使用繼承,。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class GrandFather
{
public int num1 = 10 ;
public void show(){
System.out.println( "我是爺爺" );
}
}
class Father extends GrandFather
{
public int num2 = 100 ;
public int num1 = 100000 ;
public void method(){
int num3 = 1000 ;
int num1 = 20 ;
System.out.println( "我是老子" );
System.out.println( super .num1);
System.out.println(num3);
System.out.println(num1);
System.out.println( this .num1);
}
}
class Son extends Father
{
public void fuction(){
System.out.println( super .num1);
System.out.println(num2);
}
}
class ExtendsDemo2
{
public static void main(String[] args)
{
Son son = new Son();
son.show();
son.method();
son.fuction();
System.out.println( "Hello World!" );
}
}
|
繼承中成員變量的關(guān)系 案例演示 子父類中同名和不同名的成員變量 /* 類的組成: 成員變量: 構(gòu)造方法: 成員方法: 而現(xiàn)在我們又講解了繼承,所以,,我們就應(yīng)該來(lái)考慮一下,,類的組成部分的各自關(guān)系。
繼承中成員變量的關(guān)系: A:子類中的成員變量和父類中的成員變量名稱不一樣,,這個(gè)太簡(jiǎn)單,。 B:子類中的成員變量和父類中的成員變量名稱一樣,這個(gè)怎么玩呢? 在子類方法中訪問(wèn)一個(gè)變量的查找順序: a:在子類方法的局部范圍找,,有就使用 b:在子類的成員范圍找,,有就使用 c:在父類的成員范圍找,有就使用 d:如果還找不到,,就報(bào)錯(cuò),。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Father {
public int num = 10 ;
}
class Son extends Father {
public int num = 20 ;
public void show() {
int num = 30 ;
System.out.println(num);
System.out.println( this .num);
System.out.println( super .num);
}
}
class ExtendsDemo5 {
public static void main(String[] args) {
Son s = new Son();
s.show();
}
}
|
繼承中構(gòu)造方法的關(guān)系子類中所有的構(gòu)造方法默認(rèn)都會(huì)訪問(wèn)父類中空參數(shù)的構(gòu)造方法 為什么呢? 因?yàn)樽宇悤?huì)繼承父類中的數(shù)據(jù),可能還會(huì)使用父類的數(shù)據(jù),。所以,,子類初始化之前,一定要先完成父類數(shù)據(jù)的初始化,。 每一個(gè)構(gòu)造方法的第一條語(yǔ)句默認(rèn)都是:super() /* 繼承中構(gòu)造方法的關(guān)系 A:子類中所有的構(gòu)造方法默認(rèn)都會(huì)訪問(wèn)父類中空參數(shù)的構(gòu)造方法 B:為什么呢? 因?yàn)樽宇悤?huì)繼承父類中的數(shù)據(jù),,可能還會(huì)使用父類的數(shù)據(jù)。 所以,,子類初始化之前,,一定要先完成父類數(shù)據(jù)的初始化。
注意:子類每一個(gè)構(gòu)造方法的第一條語(yǔ)句默認(rèn)都是:super(); */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class Father {
int age;
public Father() {
System.out.println( "Father的無(wú)參構(gòu)造方法" );
}
public Father(String name) {
System.out.println( "Father的帶參構(gòu)造方法" );
}
}
class Son extends Father {
public Son() {
//super();
System.out.println( "Son的無(wú)參構(gòu)造方法" );
}
public Son(String name) {
//super();
System.out.println( "Son的帶參構(gòu)造方法" );
}
}
class ExtendsDemo6 {
public static void main(String[] args) {
//創(chuàng)建對(duì)象
Son s = new Son();
System.out.println( "------------" );
Son s2 = new Son( "林青霞" );
}
}
|
如何父類中沒(méi)有構(gòu)造方法,,該怎么辦呢? 子類通過(guò)super去顯示調(diào)用父類其他的帶參的構(gòu)造方法 子類通過(guò)this去調(diào)用本類的其他構(gòu)造方法 本類其他構(gòu)造也必須首先訪問(wèn)了父類構(gòu)造 一定要注意: super(…)或者this(….)必須出現(xiàn)在第一條語(yǔ)句上 否則,,就會(huì)有父類數(shù)據(jù)的多次初始化 /* 如果父類沒(méi)有無(wú)參構(gòu)造方法,那么子類的構(gòu)造方法會(huì)出現(xiàn)什么現(xiàn)象呢? 報(bào)錯(cuò),。 如何解決呢? A:在父類中加一個(gè)無(wú)參構(gòu)造方法 B:通過(guò)使用super關(guān)鍵字去顯示的調(diào)用父類的帶參構(gòu)造方法 C:子類通過(guò)this去調(diào)用本類的其他構(gòu)造方法 子類中一定要有一個(gè)去訪問(wèn)了父類的構(gòu)造方法,,否則父類數(shù)據(jù)就沒(méi)有初始化。
注意事項(xiàng): this(...)或者super(...)必須出現(xiàn)在第一條語(yǔ)句上,。 如果不是放在第一條語(yǔ)句上,,就可能對(duì)父類的數(shù)據(jù)進(jìn)行了多次初始化,,所以必須放在第一條語(yǔ)句上。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | class Father {
/*
public Father() {
System.out.println("Father的無(wú)參構(gòu)造方法");
}
*/
public Father(String name) {
System.out.println( "Father的帶參構(gòu)造方法" );
}
}
class Son extends Father {
public Son() {
super ( "隨便給" );
System.out.println( "Son的無(wú)參構(gòu)造方法" );
//super("隨便給");
}
public Son(String name) {
//super("隨便給");
this ();
System.out.println( "Son的帶參構(gòu)造方法" );
}
}
class ExtendsDemo7 {
public static void main(String[] args) {
Son s = new Son();
System.out.println( "----------------" );
Son ss = new Son( "林青霞" );
}
}
|
面試題一 /* 看程序?qū)懡Y(jié)果: A:成員變量就近原則 B:this和super的問(wèn)題 this訪問(wèn)本類的成員 super訪問(wèn)父類的成員 C:子類構(gòu)造方法執(zhí)行前默認(rèn)先執(zhí)行父類的無(wú)參構(gòu)造方法 D:一個(gè)類的初始化過(guò)程 成員變量進(jìn)行初始化 默認(rèn)初始化 顯示初始化 構(gòu)造方法初始化
結(jié)果: fu zi 30 20 10 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class Fu
{
public int num = 10 ;
public Fu(){
System.out.println( "fu" );
}
}
class Zi extends Fu
{
public int num = 20 ;
public Zi(){
System.out.println( "Zi" );
}
public void show(){
int num = 30 ;
System.out.println(num); //30
System.out.println( this .num); //20
System.out.println( super .num); //10
}
}
class ExtendsTest
{
public static void main(String[] args)
{
Zi z = new Zi();
z.show();
System.out.println( "Hello World!" );
}
}
|
面試題二/* 看程序?qū)懡Y(jié)果: A:一個(gè)類的靜態(tài)代碼塊,構(gòu)造代碼塊,構(gòu)造方法的執(zhí)行流程 靜態(tài)代碼塊 > 構(gòu)造代碼塊 > 構(gòu)造方法 B:靜態(tài)的內(nèi)容是隨著類的加載而加載 靜態(tài)代碼塊的內(nèi)容會(huì)優(yōu)先執(zhí)行 C:子類初始化之前先會(huì)進(jìn)行父類的初始化
結(jié)果是: 靜態(tài)代碼塊Fu 靜態(tài)代碼塊Zi 構(gòu)造代碼塊Fu 構(gòu)造方法Fu 構(gòu)造代碼塊Zi 構(gòu)造方法Zi */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | class Fu
{
static {
System.out.println( "靜態(tài)代碼塊Fu" );
}
{
System.out.println( "構(gòu)造代碼塊Fu" );
}
public Fu(){
System.out.println( "構(gòu)造方法Fu" );
}
}
class Zi extends Fu
{
static {
System.out.println( "靜態(tài)代碼塊Zi" );
}
{
System.out.println( "構(gòu)造代碼塊Zi" );
}
public Zi(){
//super();
System.out.println( "構(gòu)造方法Zi" );
}
}
class ExtendsTest2
{
public static void main(String[] args)
{
Zi z = new Zi();
System.out.println( "Hello World!" );
}
}
|
繼承中成員方法的關(guān)系案例演示 子父類中同名和不同名的成員方法 結(jié)論: 通過(guò)子類對(duì)象去訪問(wèn)一個(gè)方法 首先在子類中找 然后在父類中找 如果還是沒(méi)有就報(bào)錯(cuò),。(不考慮父親的父親…) /* 繼承中成員方法的關(guān)系: A:子類中的方法和父類中的方法聲明不一樣,,這個(gè)太簡(jiǎn)單。 B:子類中的方法和父類中的方法聲明一樣,,這個(gè)該怎么玩呢? 通過(guò)子類對(duì)象調(diào)用方法: a:先找子類中,,看有沒(méi)有這個(gè)方法,有就使用 b:再看父類中,,有沒(méi)有這個(gè)方法,,有就使用 c:如果沒(méi)有就報(bào)錯(cuò)。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Father {
public void show() {
System.out.println( "show Father" );
}
}
class Son extends Father {
public void method() {
System.out.println( "method Son" );
}
public void show() {
System.out.println( "show Son" );
}
}
class ExtendsDemo8 {
public static void main(String[] args) {
//創(chuàng)建對(duì)象
Son s = new Son();
s.show();
s.method();
//s.fucntion(); //找不到符號(hào)
}
}
|
方法重寫(xiě)概述方法重寫(xiě)概述 子類中出現(xiàn)了和父類中一模一樣的方法聲明,,也被稱為方法覆蓋,,方法復(fù)寫(xiě)。 使用特點(diǎn): 如果方法名不同,,就調(diào)用對(duì)應(yīng)的方法 如果方法名相同,,最終使用的是子類自己的 方法重寫(xiě)的應(yīng)用: 當(dāng)子類需要父類的功能,,而功能主體子類有自己特有內(nèi)容時(shí),,可以重寫(xiě)父類中的方法,這樣,,即沿襲了父類的功能,,又定義了子類特有的內(nèi)容,。 /* 方法重寫(xiě):子類中出現(xiàn)了和父類中方法聲明一模一樣的方法。
方法重載: 本類中出現(xiàn)的方法名一樣,,參數(shù)列表不同的方法,。與返回值無(wú)關(guān)。 子類對(duì)象調(diào)用方法的時(shí)候: 先找子類本身,,再找父類,。
方法重寫(xiě)的應(yīng)用: 當(dāng)子類需要父類的功能,而功能主體子類有自己特有內(nèi)容時(shí),,可以重寫(xiě)父類中的方法,。 這樣,即沿襲了父類的功能,,又定義了子類特有的內(nèi)容,。
案例: A:定義一個(gè)手機(jī)類。 B:通過(guò)研究,,我發(fā)明了一個(gè)新手機(jī),,這個(gè)手機(jī)的作用是在打完電話后,,可以聽(tīng)天氣預(yù)報(bào),。 按照我們基本的設(shè)計(jì),,我們把代碼給寫(xiě)出來(lái)了。 但是呢?我們又發(fā)現(xiàn)新手機(jī)應(yīng)該是手機(jī),,所以,,它應(yīng)該繼承自手機(jī)。 其實(shí)這個(gè)時(shí)候的設(shè)計(jì),,并不是最好的,。 因?yàn)槭謾C(jī)打電話功能,是手機(jī)本身就具備的最基本的功能,。 所以,,我的新手機(jī)是不用在提供這個(gè)功能的。 但是,,這個(gè)時(shí)候,,打電話功能就沒(méi)有了。這個(gè)不好,。 最終,,還是加上這個(gè)功能。由于它繼承了手機(jī)類,,所以,,我們就直接使用父類的功能即可。 那么,,如何使用父類的功能呢?通過(guò)super關(guān)鍵字調(diào)用 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Phone {
public void call(String name) {
System.out.println( "給" +name+ "打電話" );
}
}
class NewPhone extends Phone {
public void call(String name) {
//System.out.println("給"+name+"打電話");
super .call(name);
System.out.println( "可以聽(tīng)天氣預(yù)報(bào)了" );
}
}
class ExtendsDemo9 {
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.call( "林青霞" );
}
}
|
方法重寫(xiě)的注意事項(xiàng)父類中私有方法不能被重寫(xiě) 子類重寫(xiě)父類方法時(shí),,訪問(wèn)權(quán)限不能更低 父類靜態(tài)方法,子類也必須通過(guò)靜態(tài)方法進(jìn)行重寫(xiě),。(其實(shí)這個(gè)算不上方法重寫(xiě),,但是現(xiàn)象確實(shí)如此,至于為什么算不上方法重寫(xiě),,多態(tài)中我會(huì)講解) /* 方法重寫(xiě)的注意事項(xiàng) A:父類中私有方法不能被重寫(xiě) 因?yàn)楦割愃接蟹椒ㄗ宇惛揪蜔o(wú)法繼承 B:子類重寫(xiě)父類方法時(shí),,訪問(wèn)權(quán)限不能更低 最好就一致 C:父類靜態(tài)方法,子類也必須通過(guò)靜態(tài)方法進(jìn)行重寫(xiě) 其實(shí)這個(gè)算不上方法重寫(xiě),,但是現(xiàn)象確實(shí)如此,,至于為什么算不上方法重寫(xiě),多態(tài)中我會(huì)講解
子類重寫(xiě)父類方法的時(shí)候,,最好聲明一模一樣,。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | class Father {
//private void show() {}
/*
public void show() {
System.out.println("show Father");
}
*/
void show() {
System.out.println("show Father");
}
/*
public static void method() {
}
*/
public void method() {
}
}
class Son extends Father {
//private void show() {}
/*
public void show() {
System.out.println("show Son");
}
*/
public void show() {
System.out.println("show Son");
}
public static void method() {
}
/*
public void method() {
}
*/
}
class ExtendsDemo10 {
public static void main(String[] args) {
Son s = new Son();
s.show();
}
}
|
面試題1:方法重寫(xiě)和方法重載的區(qū)別?方法重載能改變返回值類型嗎? 方法重寫(xiě): 在子類中,出現(xiàn)和父類中一模一樣的方法聲明的現(xiàn)象,。
方法重載: 同一個(gè)類中,,出現(xiàn)的方法名相同,參數(shù)列表不同的現(xiàn)象,。 方法重載能改變返回值類型,,因?yàn)樗头祷刂殿愋蜔o(wú)關(guān),。 Override:方法重寫(xiě) Overload:方法重載 2:this關(guān)鍵字和super關(guān)鍵字分別代表什么?以及他們各自的使用場(chǎng)景和作用。 this:代表當(dāng)前類的對(duì)象引用 super:代表父類存儲(chǔ)空間的標(biāo)識(shí),。(可以理解為父類的引用,,通過(guò)這個(gè)東西可以訪問(wèn)父類的成員) 場(chǎng)景: 成員變量: this.成員變量 super.成員變量 構(gòu)造方法: this(...) super(...) 成員方法: this.成員方法 super.成員方法 繼承練習(xí)學(xué)生案例和老師案例講解 使用繼承前 使用繼承后 父類中成員private修飾,子類如何訪問(wèn)呢? /* 學(xué)生案例和老師案例講解
學(xué)生: 成員變量,;姓名,,年齡 構(gòu)造方法:無(wú)參,帶參 成員方法:getXxx()/setXxx() 老師: 成員變量,;姓名,,年齡 構(gòu)造方法:無(wú)參,帶參 成員方法:getXxx()/setXxx()
看上面兩個(gè)類的成員,,發(fā)現(xiàn)了很多相同的東西,,所以我們就考慮抽取一個(gè)共性的類: 人: 成員變量;姓名,,年齡 構(gòu)造方法:無(wú)參,,帶參 成員方法:getXxx()/setXxx()
學(xué)生 繼承 人 老師 繼承 人 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | class Person
{
//姓名
private String name;
private int age;
public Person(){
}
public Person(String name, int age){
this .name = name;
this .age = age;
}
public void setName(String name){
this .name = name;
}
public String getName(){
return name;
}
public void setAge( int age){
this .age = age;
}
public int getAge(){
return age;
}
}
class Student extends Person
{
public Student(){
}
public Student(String name, int age){
super (name,age);
}
}
class Teacher extends Person
{
public Teacher(){
}
public Teacher(String name, int age){
super (name,age);
}
}
class Worker extends Person
{
public Worker(){
}
public Worker(String name, int age){
super (name,age);
}
}
class ExtendsTest4
{
public static void main(String[] args)
{
Student s1 = new Student();
s1.setName( "林青霞" );
s1.setAge( 27 );
System.out.println(s1.getName()+ " \t" +s1.getAge());
Student s2 = new Student( "楊冪" , 23 );
System.out.println(s2.getName()+ " \t" +s2.getAge());
Teacher t1 = new Teacher();
t1.setName( "鄧麗君" );
t1.setAge( 38 );
System.out.println(t1.getName()+ " \t" +t1.getAge());
Teacher t2 = new Teacher( "張三豐" , 54 );
System.out.println(t2.getName()+ " \t" +t2.getAge());
Worker w1 = new Worker();
w1.setName( "楊過(guò)" );
w1.setAge( 25 );
System.out.println(w1.getName()+ " \t" +w1.getAge());
Worker w2 = new Worker( "李思思" , 36 );
System.out.println(w2.getName()+ " \t" +w2.getAge());
}
}
|
貓狗案例講解分析和實(shí)現(xiàn) /* 貓狗案例講解
先找到具體的事物,然后發(fā)現(xiàn)具體的事物有共性,,才提取出一個(gè)父類,。
貓: 成員變量:姓名,年齡,,顏色 構(gòu)造方法:無(wú)參,,帶參 成員方法: getXxx()/setXxx() eat() palyGame() 狗: 成員變量:姓名,年齡,,顏色 構(gòu)造方法:無(wú)參,,帶參 成員方法: getXxx()/setXxx() eat() lookDoor()
共性: 成員變量:姓名,年齡,,顏色 構(gòu)造方法:無(wú)參,,帶參 成員方法: getXxx()/setXxx() eat()
把共性定義到一個(gè)類中,這個(gè)類的名字叫:動(dòng)物,。 動(dòng)物類: 成員變量:姓名,,年齡,顏色 構(gòu)造方法:無(wú)參,,帶參 成員方法: getXxx()/setXxx() eat()
貓: 構(gòu)造方法:無(wú)參,,帶參 成員方法:palyGame() 狗: 構(gòu)造方法:無(wú)參,帶參 成員方法:lookDoor() */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | class Animal
{
private String name;
private int age;
private String color;
public Animal(){}
public Animal(String name, int age,String color){
this .name = name;
}
public void setName(String name){
this .name = name;
this .age = age;
this .color = color;
}
public String getName(){
return name;
}
public void setAge( int age){
this .age = age;
}
public int getAge(){
return age;
}
public void setColor(String color){
this .color = color;
}
public String getColor(){
return color;
}
public void eat(){
System.out.println( "別睡了,,起來(lái)吃飯吧" );
}
}
class Cat extends Animal
{
public Cat(){}
public Cat(String name, int age,String color){
super (name,age,color);
}
public void playGame(){
System.out.println( "貓玩英雄聯(lián)盟" );
}
}
class Dog extends Animal
{
public Dog(){}
public Dog(String name, int age,String color){
super (name,age,color);
}
public void lookDoor(){
System.out.println( "狗看家" );
}
}
class ExtendsTest5
{
public static void main(String[] args)
{
Cat c1 = new Cat();
c1.setName( "Tom" );
c1.setAge( 3 );
c1.setColor( "白色" );
System.out.println( "貓的名字是:" +c1.getName()+ ";年齡是:" +c1.getAge()+ ";顏色是:" +c1.getColor());
c1.eat();
c1.playGame();
System.out.println( "---------------" );
Cat c2 = new Cat( "杰瑞" , 5 , "土豪金" );
System.out.println( "貓的名字是:" +c2.getName()+ ";年齡是:" +c2.getAge()+ ";顏色是:" +c2.getColor());
c2.eat();
c2.playGame();
System.out.println( "---------------" );
Dog d1 = new Dog();
d1.setName( "Tom" );
d1.setAge( 3 );
d1.setColor( "白色" );
System.out.println( "狗的名字是:" +d1.getName()+ ";年齡是:" +d1.getAge()+ ";顏色是:" +d1.getColor());
d1.eat();
d1.lookDoor();
System.out.println( "---------------" );
Dog d2 = new Dog( "杰瑞" , 5 , "土豪金" );
System.out.println( "狗的名字是:" +d2.getName()+ ";年齡是:" +d2.getAge()+ ";顏色是:" +d2.getColor());
d2.eat();
d2.lookDoor();
}
}
|
final關(guān)鍵字 final關(guān)鍵字是最終的意思,,可以修飾類,成員變量,,成員方法,。 修飾類,,類不能被繼承 修飾變量,變量就變成了常量,,只能被賦值一次 修飾方法,方法不能被重寫(xiě) /* 繼承的代碼體現(xiàn)
由于繼承中方法有一個(gè)現(xiàn)象:方法重寫(xiě),。 所以,,父類的功能,就會(huì)被子類給覆蓋調(diào),。 有些時(shí)候,,我們不想讓子類去覆蓋掉父類的功能,只能讓他使用,。 這個(gè)時(shí)候,,針對(duì)這種情況,Java就提供了一個(gè)關(guān)鍵字:final
final:最終的意思,。常見(jiàn)的是它可以修飾類,,方法,變量,。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class Fu {
public final void show() {
System.out.println( "這里是絕密資源,任何人都不能修改" );
}
}
class Zi extends Fu {
// Zi中的show()無(wú)法覆蓋Fu中的show()
public void show() {
System.out.println( "這是一堆垃圾" );
}
}
class ZiDemo {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
|
Final特性/* final可以修飾類,,方法,變量
特點(diǎn): final可以修飾類,,該類不能被繼承,。 final可以修飾方法,該方法不能被重寫(xiě),。(覆蓋,,復(fù)寫(xiě)) final可以修飾變量,該變量不能被重新賦值,。因?yàn)檫@個(gè)變量其實(shí)常量,。
常量: A:字面值常量 "hello",10,true B:自定義常量 final int x = 10; */ //final class Fu //無(wú)法從最終Fu進(jìn)行繼承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Fu {
public int num = 10 ;
public final int num2 = 20 ;
/*
public final void show() {
}
*/
}
class Zi extends Fu {
// Zi中的show()無(wú)法覆蓋Fu中的show()
public void show() {
num = 100 ;
System.out.println(num);
//無(wú)法為最終變量num2分配值
//num2 = 200;
System.out.println(num2);
}
}
class FinalDemo {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
|
final關(guān)鍵字面試題final修飾局部變量 在方法內(nèi)部,該變量不可以被改變 在方法聲明上,,分別演示基本類型和引用類型作為參數(shù)的情況 基本類型,,是值不能被改變 引用類型,是地址值不能被改變 /* 面試題:final修飾局部變量的問(wèn)題 基本類型:基本類型的值不能發(fā)生改變,。 引用類型:引用類型的地址值不能發(fā)生改變,,但是,該對(duì)象的堆內(nèi)存的值是可以改變的,。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | class Student {
int age = 10 ;
}
class FinalTest {
public static void main(String[] args) {
//局部變量是基本數(shù)據(jù)類型
int x = 10 ;
x = 100 ;
System.out.println(x);
final int y = 10 ;
//無(wú)法為最終變量y分配值
//y = 100;
System.out.println(y);
System.out.println( "--------------" );
//局部變量是引用數(shù)據(jù)類型
Student s = new Student();
System.out.println(s.age);
s.age = 100 ;
System.out.println(s.age);
System.out.println( "--------------" );
final Student ss = new Student();
System.out.println(ss.age);
ss.age = 100 ;
System.out.println(ss.age);
//重新分配內(nèi)存空間
//無(wú)法為最終變量ss分配值
ss = new Student();
}
}
|
final修飾變量的初始化時(shí)機(jī) 在對(duì)象構(gòu)造完畢前即可 /* final修飾變量的初始化時(shí)機(jī) A:被final修飾的變量只能賦值一次,。 B:在構(gòu)造方法完畢前。(非靜態(tài)的常量) */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Demo {
//int num = 10;
//final int num2 = 20;
int num;
final int num2;
{
//num2 = 10;
}
public Demo() {
num = 100 ;
//無(wú)法為最終變量num2分配值
num2 = 200 ;
}
}
class FinalTest2 {
public static void main(String[] args) {
Demo d = new Demo();
System.out.println(d.num);
System.out.println(d.num2);
}
}
|
多態(tài)多態(tài)概述某一個(gè)事物,,在不同時(shí)刻表現(xiàn)出來(lái)的不同狀態(tài),。 舉例: 貓可以是貓的類型,。貓 m = new 貓(); 同時(shí)貓也是動(dòng)物的一種,也可以把貓稱為動(dòng)物,。 動(dòng)物 d = new 貓(); 在舉一個(gè)例子:水在不同時(shí)刻的狀態(tài) 多態(tài)前提和體現(xiàn) 有繼承關(guān)系 有方法重寫(xiě) 有父類引用指向子類對(duì)象 多態(tài)案例及成員訪問(wèn)特點(diǎn)/* 多態(tài):同一個(gè)對(duì)象(事物),,在不同時(shí)刻體現(xiàn)出來(lái)的不同狀態(tài)。 舉例: 貓是貓,,貓是動(dòng)物,。 水(液體,固體,,氣態(tài)),。
多態(tài)的前提: A:要有繼承關(guān)系。 B:要有方法重寫(xiě),。 其實(shí)沒(méi)有也是可以的,,但是如果沒(méi)有這個(gè)就沒(méi)有意義。 動(dòng)物 d = new 貓(); d.show(); 動(dòng)物 d = new 狗(); d.show(); C:要有父類引用指向子類對(duì)象,。 父 f = new 子();
用代碼體現(xiàn)一下多態(tài),。
多態(tài)中的成員訪問(wèn)特點(diǎn): A:成員變量 編譯看左邊,運(yùn)行看左邊,。 B:構(gòu)造方法 創(chuàng)建子類對(duì)象的時(shí)候,,訪問(wèn)父類的構(gòu)造方法,對(duì)父類的數(shù)據(jù)進(jìn)行初始化,。 C:成員方法 編譯看左邊,,運(yùn)行看右邊。 D:靜態(tài)方法 編譯看左邊,,運(yùn)行看左邊,。 (靜態(tài)和類相關(guān),算不上重寫(xiě),,所以,,訪問(wèn)還是左邊的)
由于成員方法存在方法重寫(xiě),所以它運(yùn)行看右邊,。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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) {
//要有父類引用指向子類對(duì)象,。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//找不到符號(hào)
//System.out.println(f.num2);
f.show();
//找不到符號(hào)
//f.method();
f.function();
}
}
|
成員訪問(wèn)特點(diǎn)成員變量 編譯看左邊,運(yùn)行看左邊 成員方法 編譯看左邊,,運(yùn)行看右邊 靜態(tài)方法 編譯看左邊,,運(yùn)行看左邊 所以前面我說(shuō)靜態(tài)方法不能算方法的重寫(xiě) 多態(tài)的好處 提高了程序的維護(hù)性(由繼承保證) 提高了程序的擴(kuò)展性(由多態(tài)保證) /* 多態(tài)的好處: A:提高了代碼的維護(hù)性(繼承保證) B:提高了代碼的擴(kuò)展性(由多態(tài)保證)
貓狗案例代碼 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | class Animal
{
public void eat(){
System.out.println( "eat" );
}
public void sleep(){
System.out.println( "sleep" );
}
}
class Cat extends Animal
{
public void eat(){
System.out.println( "貓吃魚(yú)" );
}
public void sleep(){
System.out.println( "貓趴著睡" );
}
}
class Dog extends Animal
{
public void eat(){
System.out.println( "狗吃肉" );
}
public void sleep(){
System.out.println( "狗站著睡" );
}
}
class Ultraman extends Animal
{
public void eat(){
System.out.println( "奧特曼打小怪獸" );
}
public void sleep(){
System.out.println( "奧特曼不用睡覺(jué)" );
}
}
class AnimalTools
{
public static void animalTools(Animal a){
a.eat();
a.sleep();
}
}
class DuoTai
{
public static void main(String[] args)
{
Animal cat = new Cat();
AnimalTools.animalTools(cat);
Animal dog = new Dog();
AnimalTools.animalTools(dog);
Animal ultraman = new Ultraman();
AnimalTools.animalTools(ultraman);
//System.out.println("Hello World!");
}
}
|
多態(tài)的弊端不能訪問(wèn)子類特有功能 那么我們?nèi)绾尾拍茉L問(wèn)子類的特有功能呢? 多態(tài)中的轉(zhuǎn)型 /* 多態(tài)的弊端: 不能使用子類的特有功能。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | class Fu {
public void show() {
System.out.println( "show fu" );
}
}
class Zi extends Fu {
public void show() {
System.out.println( "show zi" );
}
public void method() {
System.out.println( "method zi" );
}
}
class DuoTaiDemo3 {
public static void main(String[] args) {
//測(cè)試
Fu f = new Zi();
f.show();
f.method();
}
}
|
多態(tài)中的轉(zhuǎn)型問(wèn)題向上轉(zhuǎn)型 從子到父 父類引用指向子類對(duì)象 向下轉(zhuǎn)型 從父到子 父類引用轉(zhuǎn)為子類對(duì)象 /* 多態(tài)的弊端: 不能使用子類的特有功能,。
我就想使用子類的特有功能?行不行? 行,。
怎么用呢? A:創(chuàng)建子類對(duì)象調(diào)用方法即可。(可以,但是很多時(shí)候不合理,。而且,,太占內(nèi)存了) B:把父類的引用強(qiáng)制轉(zhuǎn)換為子類的引用。(向下轉(zhuǎn)型)
對(duì)象間的轉(zhuǎn)型問(wèn)題: 向上轉(zhuǎn)型: Fu f = new Zi(); 向下轉(zhuǎn)型: Zi z = (Zi)f; //要求該f必須是能夠轉(zhuǎn)換為Zi的,。 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | class Fu {
public void show() {
System.out.println( "show fu" );
}
}
class Zi extends Fu {
public void show() {
System.out.println( "show zi" );
}
public void method() {
System.out.println( "method zi" );
}
}
class DuoTaiDemo4 {
public static void main(String[] args) {
//測(cè)試
Fu f = new Zi();
f.show();
//f.method();
//創(chuàng)建子類對(duì)象
//Zi z = new Zi();
//z.show();
//z.method();
//你能夠把子的對(duì)象賦值給父親,,那么我能不能把父的引用賦值給子的引用呢?
//如果可以,但是如下
Zi z = (Zi)f;
z.show();
z.method();
}
}
|
多態(tài)成員訪問(wèn)及轉(zhuǎn)型的理解多態(tài)的問(wèn)題理解: class 孔子爹 { public int age = 40;
public void teach() { System.out.println("講解JavaSE"); } }
class 孔子 extends 孔子爹 { public int age = 20;
public void teach() { System.out.println("講解論語(yǔ)"); }
public void playGame() { System.out.println("英雄聯(lián)盟"); } }
//Java培訓(xùn)特別火,很多人來(lái)請(qǐng)孔子爹去講課,,這一天孔子爹被請(qǐng)走了 //但是還有人來(lái)請(qǐng),,就剩孔子在家,,價(jià)格還挺高??鬃右幌?,我是不是可以考慮去呢? //然后就穿上爹的衣服,帶上爹的眼睛,,粘上爹的胡子,。就開(kāi)始裝爹 //向上轉(zhuǎn)型 孔子爹 k爹 = new 孔子(); //到人家那里去了 System.out.println(k爹.age); //40 k爹.teach(); //講解論語(yǔ) //k爹.playGame(); //這是兒子才能做的
//講完了,下班回家了 //脫下爹的裝備,,換上自己的裝備 //向下轉(zhuǎn)型 孔子 k = (孔子) k爹; System.out.println(k.age); //20 k.teach(); //講解論語(yǔ) k.playGame(); //英雄聯(lián)盟 多態(tài)內(nèi)存圖
多態(tài)中對(duì)象變化的內(nèi)存圖解
/* ClassCastException:類型轉(zhuǎn)換異常 一般在多態(tài)的向下轉(zhuǎn)型中容易出現(xiàn) */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | class Animal {
public void eat(){}
}
class Dog extends Animal {
public void eat() {}
public void lookDoor() {
}
}
class Cat extends Animal {
public void eat() {
}
public void playGame() {
}
}
class DuoTaiDemo5 {
public static void main(String[] args) {
//內(nèi)存中的是狗
Animal a = new Dog();
Dog d = (Dog)a;
//內(nèi)存中是貓
a = new Cat();
Cat c = (Cat)a;
//內(nèi)存中是貓
Dog dd = (Dog)a; //ClassCastException
}
|
案例練習(xí)
/* 多態(tài)練習(xí):貓狗案例 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | class Animal {
public void eat(){
System.out.println( "吃飯" );
}
}
class Dog extends Animal {
public void eat() {
System.out.println( "狗吃肉" );
}
public void lookDoor() {
System.out.println( "狗看門(mén)" );
}
}
class Cat extends Animal {
public void eat() {
System.out.println( "貓吃魚(yú)" );
}
public void playGame() {
System.out.println( "貓捉迷藏" );
}
}
class DuoTaiTest {
public static void main(String[] args) {
//定義為狗
Animal a = new Dog();
a.eat();
System.out.println( "--------------" );
//還原成狗
Dog d = (Dog)a;
d.eat();
d.lookDoor();
System.out.println( "--------------" );
//變成貓
a = new Cat();
a.eat();
System.out.println( "--------------" );
//還原成貓
Cat c = (Cat)a;
c.eat();
c.playGame();
System.out.println( "--------------" );
//演示錯(cuò)誤的內(nèi)容
//Dog dd = new Animal();
//Dog ddd = new Cat();
//ClassCastException
//Dog dd = (Dog)a;
}
}
|
不同地方飲食文化不同的案例 Person eat() SouthPerson eat() NorthPerson eat()
/* 不同地方飲食文化不同的案例 */ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | class Person {
public void eat() {
System.out.println( "吃飯" );
}
}
class SouthPerson extends Person {
public void eat() {
System.out.println( "炒菜,吃米飯" );
}
public void jingShang() {
System.out.println( "經(jīng)商" );
}
}
class NorthPerson extends Person {
public void eat() {
System.out.println( "燉菜,吃饅頭" );
}
public void yanJiu() {
System.out.println( "研究" );
}
}
class DuoTaiTest2 {
public static void main(String[] args) {
//測(cè)試
//南方人
Person p = new SouthPerson();
p.eat();
System.out.println( "-------------" );
SouthPerson sp = (SouthPerson)p;
sp.eat();
sp.jingShang();
System.out.println( "-------------" );
//北方人
p = new NorthPerson();
p.eat();
System.out.println( "-------------" );
NorthPerson np = (NorthPerson)p;
np.eat();
np.yanJiu();
}
}
|
|