第10天 面向对象
第10天 面向?qū)ο?/h1> 今日任務(wù)
1、接口的思想(接口的第二個(gè)作用)(掌握)
2、抽象類和接口的區(qū)別(了解)
3、多態(tài)技術(shù)(掌握)
4、Object類概述(掌握)
課堂筆記
1、接口的思想(接口的第二個(gè)作用)
?
接口的第一個(gè)作用:給事物體系增加額外功能(擴(kuò)展功能)。
接口的第二個(gè)作用:給事物雙方定義規(guī)則。一方使用規(guī)則,另一方實(shí)現(xiàn)規(guī)則。
?
?
說明:筆記本就是在使用這個(gè)規(guī)則,外圍設(shè)備(鼠標(biāo)、鍵盤等)在實(shí)現(xiàn)這個(gè)規(guī)則。
?
2、抽象類和接口的區(qū)別
?
接口和抽象類都是描述事物的共性行為,并且描述的行為一般都是抽象的。需要子類或?qū)崿F(xiàn)類對(duì)這些行為進(jìn)行實(shí)現(xiàn)或復(fù)寫。
接口和抽象類的區(qū)別:
1、接口中只能定義抽象方法;抽象類中除了具有抽象方法外,還可以定義其它方法;
2、接口可以多實(shí)現(xiàn);而抽象類只能單一繼承;
3、接口用來描述事物擴(kuò)展功能(額外功能);抽象類用來描述事物的共性內(nèi)容(描述不清楚);
4、接口中沒有構(gòu)造函數(shù);抽象類中具有構(gòu)造函數(shù);
?
抽象類和接口的區(qū)別代碼體現(xiàn)如下:
//定義接口
interface Inter
{
????void show();
????//接口中只能有抽象方法
????/*void test()
????{
????????System.out.println("test");
????????
????}*/
}
interface InterA
{
????void show();
}
//定義一個(gè)類來實(shí)現(xiàn)接口
class InterfaceImpl implements Inter,InterA//接口可以多實(shí)現(xiàn)
{
????public void show()
????{
????????System.out.println("接口show");
????}
}
//定義一個(gè)抽象類
abstract class Abs
{
????//抽象類中除了定義抽象方法還可以定義其他方法
????void demo()
????{
????????System.out.println("demo");
????}
????//抽象類中可以有構(gòu)造函數(shù),接口中沒有
????Abs()
????{
????????System.out.println("抽象類中的構(gòu)造函數(shù)");
????}
}
class AbstractDemo extends Abs
{
}
class AbstractAndInter
{
????public static void main(String[] args)
????{
????????InterfaceImpl ip=new InterfaceImpl();
????????ip.show();
????????AbstractDemo abs=new AbstractDemo();
????}
}
?
3、多態(tài)技術(shù):
3.1、多態(tài)介紹
面向?qū)ο笳Z言三大特征:封裝、繼承和多態(tài)。
多態(tài):表示的是一個(gè)事物的多種表現(xiàn)形態(tài)。同一個(gè)事物,以不同的形態(tài)表現(xiàn)出來。
?
多態(tài)來源于生活,在生活中我們經(jīng)常會(huì)對(duì)某一類事物使用它的共性統(tǒng)稱來表示某個(gè)具體的事物,這時(shí)這個(gè)具體的事物就以其他的形式展示出來。
蘋果:說蘋果,說水果。
狗:說狗,說動(dòng)物。
貓:說貓,說動(dòng)物。
?
?
3.2、多態(tài)技術(shù)在Java中的體現(xiàn)
在Java中的多態(tài)代碼體現(xiàn):
使用父類的引用,表示自己的子類對(duì)象。
Cat c = new Cat(); 使用貓類型表示自己,這里不會(huì)發(fā)生多態(tài)現(xiàn)象
Animal a = new Cat(); 使用動(dòng)物的類型再表示貓,這時(shí)就發(fā)生的多態(tài)的現(xiàn)象。
?
在Java中要使用多態(tài)技術(shù):
前提:必須要有繼承/實(shí)現(xiàn);
好處:可以通過父類統(tǒng)一管理子類;
多態(tài)技術(shù)在java中的代碼體現(xiàn):
?
//演示多態(tài)技術(shù)
abstract class Animal
{
????abstract void eat();
????void show()
????{
????????System.out.println("show run .....");
????}
????void show2()
????{
????????System.out.println("show2 run .....");
????}
}
class Cat extends Animal
{
????void eat()
????{
????????System.out.println("貓吃魚");
????}
}
class Dog extends Animal
{
????void eat()
????{
????????System.out.println("狗啃骨頭");
????}
}
?
class DuoTaiDemo
{
????public static void main(String[] args)
????{
????????Cat c = new Cat();
????????demo(c);
????????Dog d = new Dog();
????????demo(d);
????}
????/*
????????在調(diào)用方法的時(shí)候發(fā)生了多態(tài)的現(xiàn)象
????????Animal a = new Cat(); 這里發(fā)生了多態(tài)
????????Animal a = new Dog(); 這里也是多態(tài)
Dog a=new Animal();子類引用是不可以指向父類對(duì)象的
????????我們在使用多態(tài)的時(shí)候,永遠(yuǎn)只能使用父類的類型接受子類的對(duì)象,而不能使用
????????子類的類型接受父類的對(duì)象。
????*/
????public static void demo( Animal a )
????{
????????a.eat();
????????a.show();
????????a.show2();
????}
}
?
注意:我們在使用多態(tài)的時(shí)候,永遠(yuǎn)只能使用父類的類型接受子類的對(duì)象,而不能使用子類的類型接受父類的對(duì)象。
?
3.3多態(tài)的弊端
?
//演示多態(tài)弊端
?
abstract class Animal
{
????abstract void eat();
}
class Cat extends Animal
{
????void eat()
????{
????????System.out.println("貓吃魚");
????}
????//貓有自己的特有行為 抓老鼠
????void catchMouse()
????{
????????System.out.println("貓抓老鼠");
????}
}
class Dog extends Animal
{
????void eat()
????{
????????System.out.println("狗啃骨頭");
????}
????//狗也有自己的行為 看家
????void lookHome()
????{
????????System.out.println("狗看家");
????}
}
class DuoTaiDemo2
{
????public static void main(String[] args)
????{
????????Cat c = new Cat();
????????c.eat();
????????c.catchMouse();
?
?
????????Dog d = new Dog();
????????d.eat();
????????d.lookHome();
?
????????//使用多態(tài)調(diào)用方法
????????Animal a = new Dog();
????????a.eat();
????????a.lookHome();
????}
}
?
?
多態(tài)的弊端:
把一個(gè)子類類型提升成了父類的類型,那么在程序編譯的過程中,編譯不會(huì)考慮具體是哪個(gè)子類類型,而只會(huì)根據(jù)當(dāng)前的父類類型去操作,通過父類的引用在調(diào)用方法的時(shí)候,只會(huì)去父類類型所屬的類中找有沒有這些成員,
如果有編譯通過,如果沒有編譯失敗。
?
多態(tài)弊端總結(jié):
在使用多態(tài)技術(shù)的時(shí)候,程序在編譯的時(shí)候,使用多態(tài)調(diào)用成員(變量和函數(shù)),要求被調(diào)用的成員在父類中一定要存在,如果父類中沒有編譯就會(huì)失敗。(不能使用子類特有功能或者屬性)
?
注意:只要有多態(tài)的地方,一定發(fā)生類型的提升(肯定是把子類對(duì)象使用父類類型在表示)。
?
3.4、多態(tài)中的轉(zhuǎn)型
在使用多態(tài)時(shí),存在一個(gè)弊端:不能使用子類中特有的功能(函數(shù))。
如果在多態(tài)中,必須要使用子類特有的功能,需要在多態(tài)操作時(shí)進(jìn)行類型的轉(zhuǎn)換。
復(fù)習(xí)下之前學(xué)習(xí)過的類型轉(zhuǎn)換:
自動(dòng)類型提升 例: byte b=10; int num=b;
強(qiáng)制類型轉(zhuǎn)換 例: double d=3.14; int n=(int)d;
?
Animal an = new Dog();
Animal是父類類型(父引用類型) an是父引用 new Dog()是子類對(duì)象
在以上代碼中,已存在了類型的轉(zhuǎn)換(向上轉(zhuǎn)型):父類 父引用=new子類();
?
如果一定要在父類引用中使用子類對(duì)象特有的功能,就需要向下轉(zhuǎn)型(大類型向下轉(zhuǎn)換):
說明:子類對(duì)象中特定的功能只能子類對(duì)象自己調(diào)用。
?
如果已經(jīng)發(fā)生多態(tài)現(xiàn)象,但是我們還想調(diào)用子類的特有屬性或者行為,這時(shí)需要使用強(qiáng)制類型轉(zhuǎn)換,把當(dāng)前父類類型轉(zhuǎn)成具體的子類類型。
?
多態(tài)中的類型轉(zhuǎn)換有兩種:
1)向上轉(zhuǎn)型(隱式的類型提升) 父引用指向子類對(duì)象 例:Animal an = new Dog();
2)向下轉(zhuǎn)型(強(qiáng)制類型轉(zhuǎn)換或者把父類類型轉(zhuǎn)成子類類型) 把父引用強(qiáng)制轉(zhuǎn)為子類引用 例:Dog d=(Dog) an;
強(qiáng)制類型轉(zhuǎn)換格式:子類類型 子類引用名=(子類類型)父類引用名;
?
?
多態(tài)類型轉(zhuǎn)換的代碼體現(xiàn):
abstract class Animal
{
????abstract void eat();
}
class Cat extends Animal
{
????void eat()
????{
????????System.out.println("貓吃魚");
????}
????//貓有自己的特有行為 抓老鼠
????void catchMouse()
????{
????????System.out.println("貓抓老鼠");
????}
}
?
class Dog extends Animal
{
????void eat()
????{
????????System.out.println("狗啃骨頭");
????}
????//狗也有自己的行為 看家
????void lookHome()
????{
????????System.out.println("狗看家");
????}
}
class DuoTaiDemo3
{
????public static void main(String[] args)
????{
????????Cat c = new Cat();
????????c.eat();
????????c.catchMouse();
?
????????Dog d = new Dog();
????????d.eat();
????????d.lookHome();
?
????????//使用多態(tài)調(diào)用方法
????????Animal a = new Dog();
????????a.eat();
????????/*
????????????如果已經(jīng)發(fā)生多態(tài)現(xiàn)象,但是我們還想調(diào)用子類的特有屬性或者行為,這時(shí)需要使用
????????????強(qiáng)制類型轉(zhuǎn)換,把當(dāng)前父類類型轉(zhuǎn)成具體的子類類型。
?
????????????在多態(tài)中的類型轉(zhuǎn)換問題:
????????????????1、隱式的類型提升。只要有多態(tài)就會(huì)發(fā)生類型提升(向上轉(zhuǎn)型)。
????????????????2、把父類類型轉(zhuǎn)成子類類型(強(qiáng)制類型轉(zhuǎn)換,向下轉(zhuǎn)型)。
?
????????????什么時(shí)候使用向下轉(zhuǎn)型:
????????????只要在程序中我們需要使用子類的特有屬性或行為(方法、函數(shù))的時(shí)候,才會(huì)使用向下轉(zhuǎn)型。
????????*/
?
????????//(Dog)(a).lookHome();
????????Dog dd = (Dog)a; //多態(tài)的轉(zhuǎn)型
????????dd.lookHome();
?
注意:
1)什么時(shí)候使用向下轉(zhuǎn)型:
????只要在程序中我們需要使用子類的特有屬性或行為(方法、函數(shù))的時(shí)候,才會(huì)使用向下轉(zhuǎn)型。
?
3.5多態(tài)類型轉(zhuǎn)換時(shí)常見異常
在多態(tài)類型轉(zhuǎn)換時(shí)經(jīng)常會(huì)發(fā)生一個(gè)異常錯(cuò)誤:ClassCastException(類型轉(zhuǎn)換異常)。
?
多態(tài)類型轉(zhuǎn)換常見異常代碼演示:
abstract class Animal
{
????abstract void eat();
}
class Cat extends Animal
{
????void eat()
????{
????????System.out.println("貓吃魚");
????}
????//貓有自己的特有行為 抓老鼠
????void catchMouse()
????{
????????System.out.println("貓抓老鼠");
????}
}
?
class Dog extends Animal
{
????void eat()
????{
????????System.out.println("狗啃骨頭");
????}
????//狗也有自己的行為 看家
????void lookHome()
????{
????????System.out.println("狗看家");
????}
}
class DuoTaiDemo3
{
????public static void main(String[] args)
????{
????????Animal a= new Cat();
????????demo(a);//傳遞的是貓的對(duì)象
????}
????public static void demo( Animal a )
????{
????????a.eat();
//把Animal類型的a轉(zhuǎn)成 Dog類的d
Dog d=(Dog)a;//將傳遞過來的貓的對(duì)象強(qiáng)制轉(zhuǎn)換為狗是不可以的,會(huì)發(fā)生轉(zhuǎn)換異常
????????/*
????????????向下轉(zhuǎn)型有風(fēng)險(xiǎn),使用需謹(jǐn)慎。
????????????在Java中要使用向下轉(zhuǎn)型,必須先做類型的判斷,然后在轉(zhuǎn)型
????????????Java中的類型判斷 需要使用關(guān)鍵字 instanceof
????????????格式:
????????????????被轉(zhuǎn)的引用變量名 instanceof 被轉(zhuǎn)成的類型
????????????????如果引用變量所在的那個(gè)對(duì)象 和被轉(zhuǎn)成的類型一致,這個(gè)表達(dá)式返回的是true,否則是false
?
????????????在多態(tài)中使用轉(zhuǎn)型的時(shí)候,一定要判斷,防止類型轉(zhuǎn)換異常的發(fā)生:
????????????????如果在程序發(fā)生ClassCastException,一定是把不是這種類型的對(duì)象轉(zhuǎn)成了這種類型。
????????*/
????????if( a instanceof Dog )
????????{
????????????Dog d = (Dog)a;
????????????d.lookHome();
????????}
????????else if( a instanceof Cat )
????????{
????????????Cat c = (Cat)a;
????????????c.catchMouse();
????????}????
????}
}
?
?
向下轉(zhuǎn)型有風(fēng)險(xiǎn),使用需謹(jǐn)慎。在Java中要使用向下轉(zhuǎn)型,必須先做類型的判斷,然后在轉(zhuǎn)型Java中的類型判斷 需要使用關(guān)鍵字 instanceof。
????????????格式:
????????????????被轉(zhuǎn)的引用變量名 instanceof 被轉(zhuǎn)成的類型
如果引用變量所在的那個(gè)對(duì)象 和被轉(zhuǎn)成的類型一致,這個(gè)表達(dá)式返回的是true,否則是false。
在多態(tài)中使用轉(zhuǎn)型的時(shí)候,一定要判斷,防止類型轉(zhuǎn)換異常的發(fā)生:
如果在程序發(fā)生ClassCastException,一定是把不是這種類型的對(duì)象轉(zhuǎn)成了這種類型。
?
總結(jié):
只要有多態(tài),就會(huì)有類型的轉(zhuǎn)換。
把子類對(duì)象賦值給父類的引用,這時(shí)發(fā)生了向上的轉(zhuǎn)型(隱式類型轉(zhuǎn)換)。
如果我們需要使用子類的特有行為或?qū)傩?#xff0c;這時(shí)必須向下轉(zhuǎn)型,需要把父類的引用轉(zhuǎn)成具體所指的那個(gè)對(duì)象的類型。
在向下轉(zhuǎn)型的時(shí)候一定要做類型的判斷,防止ClassCastException異常的發(fā)生。
?
判斷格式:
if( 父類引用變量名 instanceOf 子類對(duì)象所屬的類名 )
{
進(jìn)行轉(zhuǎn)換。
}
3.6、多態(tài)中調(diào)用成員的細(xì)節(jié)(掌握)
學(xué)習(xí)多態(tài)中的成員使用規(guī)律:需要掌握的是以多態(tài)形式使用成員,需要考慮程序的編譯和運(yùn)行2個(gè)階段。
3.6.1多態(tài)調(diào)用成員變量
在使用多態(tài)時(shí),子父類中存在相同的成員變量:
?
結(jié)論:
在多態(tài)中,使用父類的引用(f)訪問成員變量,子父類中存在一模一樣的成員變量時(shí):
1)代碼在編譯的時(shí)期(javac 源文件):需要查看父類中有沒有這個(gè)成員變量,如果有,編譯通過,沒有編譯失敗。
2)編譯通過的前提下,運(yùn)行(java 類文件)時(shí)期:這時(shí)操作的依然是父類中的成員變量。
記住:多態(tài)時(shí),子父類中存在一模一樣的成員變量時(shí),引用變量,編譯運(yùn)行都看引用類(父類)中的變量。(編譯時(shí)以等號(hào)左邊作為參考,運(yùn)行時(shí)也是以等號(hào)左邊作為參考)
注意:如果發(fā)生多態(tài)時(shí),只要是在其他類中使用成員變量,那么這個(gè)成員變量必須存在于父類中,無論子類中是否含有對(duì)應(yīng)的成員變量,如果父類中沒有成員變量,那么編譯和運(yùn)行都不會(huì)通過,和子類中是否含有成員變量沒有關(guān)系。
?
3.6.2多態(tài)調(diào)用非靜態(tài)成員函數(shù)
在多態(tài)中,使用父類引用調(diào)用成員函數(shù)的時(shí)候,一般函數(shù)都復(fù)寫存在。
在使用多態(tài)時(shí),子父類中存在一模一樣的成員方法時(shí):
?
結(jié)論:
在多態(tài)中,使用父類的引用(f)調(diào)用函數(shù)的時(shí)候,子父類中存在一模一樣的成員方法時(shí):
1)代碼在編譯的時(shí)期(javac 源文件):要看父類中有沒有這個(gè)函數(shù),有,編譯通過,沒有編譯失敗。
2)編譯通過的前提下,運(yùn)行(java 類文件)時(shí)期:運(yùn)行的是子類中復(fù)寫父類之后的那個(gè)函數(shù)。如果沒有復(fù)寫,運(yùn)行的肯定還是父類的函數(shù)。
記住:多態(tài)時(shí),子父類中存在一模一樣的成員方法時(shí),編譯時(shí)以等號(hào)左邊作為參考,運(yùn)行時(shí)是以等號(hào)右邊作為參考。
3.6.3多態(tài)調(diào)用靜態(tài)成員函數(shù)
在使用多態(tài)時(shí),子父類中存在一模一樣的靜態(tài)方法時(shí):
?
靜態(tài)的成員是隨著類的加載而存在,和創(chuàng)建的對(duì)象沒有任何關(guān)系,只跟類有關(guān)系。在java中,使用對(duì)象去調(diào)用靜態(tài)成員,底層JVM還是會(huì)以對(duì)象所屬的類型(類)去調(diào)用靜態(tài)成員。因此使用多態(tài)調(diào)用靜態(tài)函數(shù)的時(shí)候,編譯運(yùn)行都要看父類中的函數(shù)。
?
結(jié)論:
在使用多態(tài)時(shí),子父類中存在一模一樣的靜態(tài)方法時(shí):
編譯時(shí)期是以等號(hào)左邊作為參考,運(yùn)行時(shí)期也是以等號(hào)左邊作為參考。
也就是說,在使用多態(tài)時(shí),子父類中存在一模一樣的靜態(tài)方法時(shí),與子類是否存在靜態(tài)函數(shù)沒有關(guān)系,只和父類中有關(guān)系。
?
總結(jié)多態(tài)中成員使用規(guī)律:
成員變量和靜態(tài)成員函數(shù),編譯運(yùn)行都看左邊(父類中的)。只有非靜態(tài)成員函數(shù),編譯看父類,運(yùn)行看子類對(duì)象。
3.7、多態(tài)的練習(xí)
練習(xí)的目的:需要掌握多態(tài)中,自始至終只有子類對(duì)象存在,沒有父類的對(duì)象,并且把子類對(duì)象交給父類的引用在使用。
?
練習(xí)黑旋風(fēng)和黑旋風(fēng)老爸的故事。
黑旋風(fēng):
講課(){}
看電影(){}
黑旋風(fēng)老爸:
講課(){}
釣魚(){}
?
//多態(tài)練習(xí)
class Dad
{
????void teach()
????{
????????System.out.println("黑旋風(fēng)老爸講論語");
????}
????void fish()
????{
????????System.out.println("黑旋風(fēng)老爸釣魚");
????}
}
class Hxf extends Dad
{
????void teach()
????{
????????System.out.println("黑旋風(fēng)講Java");
????}
????void lookFilm()
????{
????????System.out.println("黑旋風(fēng)在看速7");
????}
}
?
class DuoTaiTest
{
????public static void main(String[] args)
????{
????????/*
????????Hxf hxf = new Hxf ();
????????hxf .teach();
????????hxf .fish();
????????*/
????????Dad dad = new Hxf (); //多態(tài)
????????dad .teach();
???? dad .fish();
//dad.lookFilm();//編譯報(bào)錯(cuò),因?yàn)楦割愔袥]有l(wèi)ookFilm這個(gè)函數(shù)
???? /*
????????????現(xiàn)在我就想調(diào)用子類中特有的函數(shù),怎么辦?
????????????我們這里需要使用強(qiáng)制類型轉(zhuǎn)換,將父類轉(zhuǎn)換為子類
????????*/
????????Hxf hxf = (Hxf)dad; //黑旋風(fēng)卸妝 向下轉(zhuǎn)型
????????hxf .lookFilm();
????}
}
?
?
4、Object類概述
在學(xué)習(xí)面向?qū)ο缶幊趟枷?#xff0c;遇到需求時(shí),先去找有沒有解決問題的功能存在。這些解決問題的功能通常是封裝在類中(功能類),使用這些功能類基本可以解決開發(fā)中大部分的問題(例:折半查找、選擇排序等)。
問題:這些解決問題的功能類都在哪里?
在java設(shè)計(jì)時(shí),已經(jīng)提供了很多解決問題的封裝類。這些解決問題的封裝類,我們統(tǒng)稱為:API
在開發(fā)中,只要去相應(yīng)的包(文件夾)中去找對(duì)應(yīng)的封裝類就可以解決問題。
API:application programming interface。應(yīng)用程序接口。我們這里通常把a(bǔ)pi簡稱為幫助文檔。
想要使用java提供的解決各種問題的API,就需要先學(xué)會(huì)如何查閱API文檔。
4.1 查閱API文檔的技巧
使用"索引"查找相應(yīng)的信息
如下圖操作,點(diǎn)擊選項(xiàng),選擇顯示標(biāo)簽
?
點(diǎn)擊完顯示標(biāo)簽后,會(huì)出現(xiàn)如下圖所示界面:
?
然后點(diǎn)擊索引,會(huì)出現(xiàn)如下圖所示的界面:
在查找框里輸入要查找的類或者接口即可。
?
在搜索框里輸入要查找的類,選中并雙擊或者回車。
?
4.2 如何查閱源代碼
在開發(fā)中,除了查閱API以外,還經(jīng)常會(huì)查看JDK的源代碼,幫助解決開發(fā)中的問題。
在安裝JDK時(shí),隨著JDK版本的安裝,在JDK安裝目錄也存在一個(gè)當(dāng)前版本的JDK源碼文件
?
查看源代碼的步驟:(前提:需要知道要查找的功能類屬于哪個(gè)包)
?
?
?
4.3 Object類說明
在所有類中的構(gòu)造函數(shù)中有個(gè)隱式的super語句,找父類。如果一個(gè)類沒有顯示指定它的父類,那么這個(gè)類的父類默認(rèn)就是Object類。Object類的構(gòu)造函數(shù)中是沒有隱式的super的。
通過API的查閱,可以得到:
1、Object是java提供的功能類(API中的類)和開發(fā)人員自己書寫的類的父類;
2、因?yàn)樗械念惗祭^承了Object類,所以繼承了Object類的子類可以使用Ojbect類中的功能(函數(shù));
疑問:既然自己定義的類也要繼承Object類,那為什么在代碼中沒有顯式書寫繼承Object?
Object類屬于java.lang包下。而java.lang包會(huì)被JVM在運(yùn)行時(shí)自動(dòng)加載,繼承了Object的子類也不需要顯式書寫,JVM會(huì)自動(dòng)為書寫的類添加繼承。
Object類中的常用函數(shù):
equals 方法 toString 方法
4.4、equals方法介紹
需求:判斷學(xué)生是否為同齡人
?
/*
????判斷兩個(gè)學(xué)生是否是同齡人
*/
//定義一個(gè)學(xué)生類
class Student
{
????//屬性
????String name;
????int age;
????//定義構(gòu)造函數(shù)給屬性初始化值
????Student(String name,int age)
????{
????????this.name=name;
????????this.age=age;
????}
????/*
????????定義一個(gè)函數(shù)根據(jù)外界傳遞過來的值比較年齡是否相等,
????????使用return關(guān)鍵字將比較的結(jié)果返回給調(diào)用者
????????Student a=new Student("技導(dǎo)",18)
????????因?yàn)閏ompareAge函數(shù)是s對(duì)象調(diào)用的,所以在這個(gè)函數(shù)中的隱式變量this
????????記錄著s對(duì)象的堆內(nèi)存地址名
????*/
????public boolean compareAge(Student a)
????{
????????/*
????????????this.age表示黑旋風(fēng)的年齡17
????????????a.age表示技導(dǎo)的年齡18
????????*/
????????return this.age==a.age;
????}
}
class ObjectDemo1
{
????public static void main(String[] args)
????{
????????/*
????????????創(chuàng)建兩個(gè)對(duì)象
????????????下面的兩個(gè)對(duì)象表示在對(duì)空間中開辟兩個(gè)不同的空間
????????????一個(gè)空間叫做s,另一個(gè)空間叫做s1
????????*/
????????Student s=new Student("黑旋風(fēng)",17);
????????Student s1=new Student("技導(dǎo)",17);
????????//使用黑旋風(fēng)的對(duì)象s調(diào)用compareAge函數(shù)
????????//使用flag來接受返回回來的值
????????boolean flag=s.compareAge(s1);
????????/*
????????????如果返回回來的值是true,說明是同齡人
????????????如果返回回來的值是false,說明不是同齡人
????????*/
????????if(flag==true)
????????{
????????????System.out.println("是同齡人");
????????}else
????????{
????????????System.out.println("不是同齡人");
????????}
????}
}
?
使用以上方式可以解決問題。
?
面向?qū)ο?#xff1a;遇到需求時(shí),先去找有沒有存在已經(jīng)解決問題的功能(功能是封裝在類中)。
有,就直接使用封裝了功能的功能類解決問題。
?
以上需求中,是需要解決判斷是否為同齡人的功能。(其實(shí)就是一個(gè)判斷是否相等的功能)
首先,去找java API中是否有比較功能。
問題:Student類中不具備比較功能,但是,Student類繼承了Object類,所以可以去Object類中找是否存在解決問題的功能
?
Object類中的功能:
?
使用Object類中的eqauls函數(shù)解決需求中的問題:
?
以上程序運(yùn)行結(jié)果不正確。
分析:為什么使用Object類中的equals功能會(huì)存在結(jié)果不正確呢?
查看Object類中的equals功能的源代碼
上述代碼中的Object類中的this 表示的是調(diào)用這個(gè)equals函數(shù)的那個(gè)對(duì)象,obj是調(diào)用equals方法時(shí)傳遞進(jìn)來的那個(gè)對(duì)象,而this中保存的是對(duì)象的內(nèi)存地址,obj中接受的也是傳遞進(jìn)來的那個(gè)對(duì)象內(nèi)存地址。所以這里使用== ,其實(shí)是在比較2個(gè)對(duì)象的內(nèi)存地址是否相等。(就是堆內(nèi)存中的地址)
?
結(jié)論:Object類中的equals方法中,比較的是堆中的地址是否相等
?
而我們真正在開發(fā)中要比較2個(gè)對(duì)象是否相等,不應(yīng)該去比較內(nèi)存地址,而應(yīng)該比較的是對(duì)象中的數(shù)據(jù)是否相同。單單使用Object類中的equals功能,并不能直接解決我們需求中的問題。遇到這種情況,在開發(fā)中的做法是:重寫Object類中的equals函數(shù),因此所有的程序中都應(yīng)該復(fù)寫Object類中的equals。
?
?
/*
????判斷兩個(gè)學(xué)生是否是同齡人
*/
//定義一個(gè)學(xué)生類
class Student
{
????//屬性
????String name;
????int age;
????//定義構(gòu)造函數(shù)給屬性初始化值
????Student(String name,int age)
????{
????????this.name=name;
????????this.age=age;
????}
????//重寫Object類中的equals函數(shù)(重寫:和父類中的方法一模一樣)
????public boolean equals(Object obj) {
????????/*
????????????因?yàn)檫@里發(fā)生了多態(tài),所以不能使用父類的對(duì)象obj調(diào)用父類中不存在的屬性age,
????????????所以會(huì)報(bào)錯(cuò)。所以我們應(yīng)該使用子類Student對(duì)象來調(diào)用子類中的屬性age
????????????而這里obj是父類對(duì)象,我們需要使用向下轉(zhuǎn)型將父類對(duì)象obj轉(zhuǎn)換為子類對(duì)象
????????????因?yàn)榘l(fā)生向下類型轉(zhuǎn)換,為了防止發(fā)生轉(zhuǎn)換異常,所以我們要判斷子類對(duì)象類型
????????*/
????????Student s=null;
????????if(obj instanceof Student)
????????{
????????????s=(Student)obj;
????????}
return this.age==s.age;
}
}
class ObjectDemo2
{
????public static void main(String[] args)
????{
????????/*
????????????創(chuàng)建兩個(gè)對(duì)象
????????????下面的兩個(gè)對(duì)象表示在對(duì)空間中開辟兩個(gè)不同的空間
????????????一個(gè)空間叫做s,另一個(gè)空間叫做s1
????????*/
????????Student s=new Student("黑旋風(fēng)",17);
????????Student s1=new Student("技導(dǎo)",17);
????????//使用黑旋風(fēng)的對(duì)象s調(diào)用compareAge函數(shù)
????????//使用flag來接受返回回來的值
????????//boolean flag=s.compareAge(s1);
????????/*
????????????public boolean equals(Object obj) {
????????????????這里的this記錄著調(diào)用這個(gè)方法的對(duì)象s的堆中內(nèi)存地址名
????????????????obj表示傳遞進(jìn)來的參數(shù)對(duì)象s1,Object obj=new Student("技導(dǎo)",17);這里發(fā)生多態(tài)
????????????????obj里面存放的也是s1中的堆中內(nèi)存地址
????????????????s和s1的堆中內(nèi)存地址名不同
???????????????? return (this == obj);
????????????}
????????????public boolean compareAge(Student a)
????????????{
???????? ?
????????????????return this.age==a.age;
????????????}
????????*/
????????boolean flag=s.equals(s1);
????????System.out.println(flag);
???????? ?
????????/*
????????????如果返回回來的值是true,說明是同齡人
????????????如果返回回來的值是false,說明不是同齡人
????????*/
????????if(flag==true)
????????{
????????????System.out.println("是同齡人");
????????}else
????????{
????????????System.out.println("不是同齡人");
????????}
????}
}
?
?
?
總結(jié):
關(guān)系運(yùn)算中的==和equals的區(qū)別:
4.5、toString方法介紹
需求:輸出Student類的具體信息,也就是根據(jù)輸出Student類的對(duì)象來輸出Student的具體名字和姓名。
以上程序的運(yùn)行結(jié)果,不符合需求。要求是想要輸出學(xué)生類中的具體信息,比如通過打印對(duì)象的名字stu,我們希望打印出具體的stu對(duì)象所擁有的名字和年齡,而打印一串地址名在開發(fā)中沒有什么太大意義。
?
問題:為什么輸出stu時(shí),顯示的結(jié)果:Student@7ea06d25?為什么輸出的是一個(gè)引用地址而不是我們想要的對(duì)象的屬性的值呢?我們應(yīng)該怎么做才能打印出屬性的值而不是打印一串地址的值呢?
這里我們需要借助Object類中的toString方法來解決,toString是一個(gè)方法,它需要對(duì)象來調(diào)用,toString的意思是將調(diào)用它的對(duì)象轉(zhuǎn)換成字符串形式。
我們在打印對(duì)象的時(shí)候也可以按照如下方法去做:
System.out.println(stu.toString());打印的結(jié)果和我們寫System.out.println(stu);是一樣的。
在上述打印語句中println()的方法中打印對(duì)象stu的時(shí)候,如果不加 .toString()方法,在println()的方法中默認(rèn)也是使用對(duì)象stu調(diào)用toString()方法,所以在開發(fā)中寫與不寫toString()方法是一樣的。
?
?
?
根據(jù)以上分析我們想要建立自定義對(duì)象的表現(xiàn)形式,我們需要覆蓋超類(所有類的父類)中的toString()方法就可以了。
在Student類中可以重寫toString方法,讓程序輸出學(xué)生類的具體信息,代碼實(shí)現(xiàn)如下:
?
小結(jié):
在開發(fā)中,如果子類繼承父類時(shí),父類中已經(jīng)存在了解決問題的功能,但是父類中的功能并不能滿足子類的需求,這時(shí),子類就需要重寫(覆蓋)父類中的方法。
轉(zhuǎn)載于:https://www.cnblogs.com/beyondcj/p/5860863.html
總結(jié)
- 上一篇: 10.Java设计模式 工厂模式,单例模
- 下一篇: 拒绝干扰 解决Wi-Fi的最大问题《转》