日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java学习笔记---接口

發(fā)布時間:2023/12/18 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java学习笔记---接口 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

接口和內(nèi)部類為我們提供了一種接口與實現(xiàn)分離的更加結(jié)構(gòu)化的方法;

首先需要學(xué)習(xí)抽象類,它是普通的類與接口之間的一種中庸之道;因為不可能總是使用純接口,所以抽象類仍舊有著重要的作用。

  • 抽象類和抽象方法
  • 接口
  • 完全解耦
  • Java中的多重繼承
  • 通過繼承來擴展接口
  • 適配接口
  • 接口中的域
  • 嵌套接口
  • 接口與工廠

1.抽象類和抽象方法

在上一章的例子中,基類Instrument中的方法往往是“啞”(dump)方法。Instrument類的目的是為它的所有導(dǎo)出類創(chuàng)建一個通用接口。

建立通用接口的理由:

不同的子類可以用不同的方式表示此接口。通接口建立起一種基本形式,以此表示所有導(dǎo)出類的共同部分;

另一種說法是將Instrument類稱作抽象基類,簡稱抽象類。

如果只有一個像Instrument這樣的抽象類,那么該類的對象幾乎沒有任何意義,創(chuàng)建抽象類是希望通過這個通用接口操縱一系列類。

因此,Instrument只是表示了一個接口,沒有具體的實現(xiàn)內(nèi)容;實際上,Java禁止使用這創(chuàng)建抽象類對象。在編譯時會捕獲這些問題:

為此,Java提供一個叫做抽象方法的機制,這種方法是不完整的;僅有聲明而沒有方法體。語法如下:

abstract void f();

包含抽象方法的類叫做抽象類。如果一個類包含一個或多個抽象方法,該類必須被限定為抽象類。(否則,編譯器就會報錯。)

由于為抽象類創(chuàng)建對象是不安全的,所以我們會從編譯器那里得到一條出錯消息,這樣編譯器會確保抽象類的純粹性,不必擔(dān)心誤用它。

如果從一個抽象類繼承,并想創(chuàng)建該新類的對象,那么必須為基類中的所有抽象方法提供方法定義。如果不這么做(也可以選擇不做),那么導(dǎo)出類便也是抽象類,且編譯器將會強制我們用abstract關(guān)鍵字來限定這個類。

我們也能會創(chuàng)建一個沒有任何抽象方法的抽象類。考慮這種情況:如果有一個類,讓其包含任何abstract方法都顯得沒有實際意義,而且我們也想要阻止產(chǎn)生這個類的任何對象,那么這時這樣做就很有用了。

如何將上一章的Instrument類轉(zhuǎn)化成abstract類(抽象類并不需要所有的方法都是抽象的,只要有一個抽象方法就是抽象類)

這里將Instrument類中的play()和adjust()方法變成abstract方法,所以這是一個抽象類,必須以abstract聲明該類,且導(dǎo)出類必須實現(xiàn)這兩個抽象方法,否則導(dǎo)出類仍然是抽象類;

可以看到,除了基類,幾乎沒什么變化。

創(chuàng)建抽象類和抽象方法非常有用,因為它們可以使類的抽象性明確起來,并告訴用戶和編譯器打算怎樣來使用它們。抽象類還是很有用的重構(gòu)工具,因為它們使得我們可以很容易地將公共方法沿著繼承層次結(jié)構(gòu)向上移動。

總結(jié):?

抽象方法:前面由abstract聲明,只要方法體,沒有具體實現(xiàn)

抽象類:含有一個或多個抽象方法的抽象類,但一般不包括全部都是抽象方法,全部都是抽象方法接下來會介紹是接口;抽象類需要使用abstract聲明

抽象類可以被繼承,但不能創(chuàng)建對象,導(dǎo)出類必須實現(xiàn)所有的抽象方法,否則仍然是抽象類,且必須加abstract聲明

2.接口

interface關(guān)鍵字使抽象方法的概念更向前邁進了一步。abstract關(guān)鍵字允許人們在類中創(chuàng)建一個或多個沒有任何定義的方法--提供了接口部分,但是沒有提供任何任何相應(yīng)的具體實現(xiàn),這些實現(xiàn)是由此類的繼承者創(chuàng)建的。

interface這個關(guān)鍵字產(chǎn)生一個完全抽象的類,它根本沒有提供任何具體實現(xiàn)。它允許創(chuàng)建者確定方法名、參數(shù)列表和返回類型,但是沒有任何方法體。接口只提供了形式,而未提供任何具體實現(xiàn)。

任何使用某特定接口的代碼都知道可以調(diào)用該接口的哪些方法,而且僅需知道這些。因此,接口被用來建立類與類之間的協(xié)議

要想創(chuàng)建一個接口,需要用interface關(guān)鍵字來替代calss關(guān)鍵字,就像類一樣,可以在interface關(guān)鍵字前面添加public關(guān)鍵字(但僅限于該接口在與其同名的文件中被定義)。如果不添加public關(guān)鍵字,則它只具有包訪問權(quán)限,這樣就只能在同一個包內(nèi)可用。接口也可以包含域,但是這些域隱式的是static和final的。

要讓一個類遵循某個特定接口(或者是一組接口),需要使用implements關(guān)鍵字,它表示:“interface只是它的外貌,但是現(xiàn)在我要聲明它是如何工作的”,除此之外,它看起來還很像繼承。"樂器"示例的圖說明了這一點:

在程序里,無法證明Instrument是一個普通類、抽象類或者還是一個接口。?

3.完全解耦

只要一個方法操作的是類而非接口,那么你就只能使用這個類及其子類。如果想要將這個方法應(yīng)用于不在此繼承結(jié)構(gòu)中的某個類,那就會出現(xiàn)問題。接口可以在很大程度上放寬這種限制,因此,它使得我們可以編寫可復(fù)用性更好的代碼。

例如:假設(shè)有一個Processor類,他有一個main()方法;另外還有一個process()方法,該方法接受輸入?yún)?shù),修改它的值,然后產(chǎn)生輸出。這個類作為基類而被擴展,用來創(chuàng)建各種不同類型的Processor。在本例中,Processor的子類將修改String對象(返回類型可以是協(xié)變類型,而非參數(shù)類型):

Apply.process()方法可以接受任何類型的Processor,并將其應(yīng)用到一個Object對象上,然后打印結(jié)果。

像本例這樣,創(chuàng)建一個能夠根據(jù)所傳遞的參數(shù)對象的不同而具有不同行為的方法,被稱為策略設(shè)計模式。

這類方法包含所要執(zhí)行的算法中固定不變的部分,而“策略”包含變化的部分。策略就是傳遞進去的參數(shù)對象,它包含要執(zhí)行的代碼。

在這里,Processor對象就是一個策略,在main()中可以看到有三種不同類型的策略應(yīng)用到了String類型的s對象上。

string.toUpperCase();針對String類型,將String全部轉(zhuǎn)換成大寫;

string.toLowerCase()針對String類型,將String全部轉(zhuǎn)換成小寫;

split()方法是String類的一部分,它接受String類型的對象,并以傳遞進來的參數(shù)作為邊界,將該String對象分隔開,然后返回一個數(shù)組String[]。可以當(dāng)做創(chuàng)建String數(shù)組的快捷方法。

再看一個例子:

現(xiàn)在假設(shè)發(fā)現(xiàn)了一組電子濾波器,它們看起來好像適用于Apply.process()方法(好像適用是因為這組濾波器的方法名和參數(shù)都相同,也就是耦合過緊):

Filter和Processor具有相同的接口元素,但是因為它并非繼承自Processor--因為Filter類的創(chuàng)建者壓根不清楚你想要將他用作Processor--因此不能將Filter用于Apply.process()方法,即便這樣做可以正常運行。

這里主要是因為Apply.process()方法和Processor之間的耦合過緊,已經(jīng)超出了所需要的程度,這就使得應(yīng)該復(fù)用Apply.process()的代碼時,復(fù)用卻被禁止了。

另外還需要注意的是,它們的輸入和輸出都是Waveform。

但是,如果Processor是一個接口,那么這些限制就會變得松動,使得你可以復(fù)用結(jié)構(gòu)該接口的Apply.process()。下面是Processor和Apply的修改版本:

復(fù)用代碼的第一種方式是客戶端程序員遵循該接口來編寫它們自己的類,就像下面這樣:

但是經(jīng)常碰到的情況是無法修改你想要使用的類,例如:在電子濾波器中,類庫是發(fā)現(xiàn)的,并不是自己創(chuàng)建的,在這些情況下,可以使用適配器設(shè)計模式。適配器中的代碼將接受你所擁有的接口,并產(chǎn)生你所需要的接口,就像下面這樣:

在這種使用適配器的方式中,FilterAdapter的構(gòu)造器接受你所擁有的接口Filter,然后生成具有你所需要的Processor借口的對象。

在FilterAdapter類中還用到了代理;

將接口從具體實現(xiàn)中解耦使得接口可以應(yīng)用于多種不同的具體實現(xiàn),因此代碼也就更具有可復(fù)用性。?

4.Java中的多重繼承

接口不僅僅是一種更純粹形式的抽象類,接口沒有任何具體實現(xiàn)--也就是說,沒有任何與接口相關(guān)的存儲;因此,也就無法組織多個接口的組合。

在C++中,組合多個類的接口的行為被稱作多重繼承,這會造成很大的壓力,因為每個類都有一個具體實現(xiàn);

在Java中,可以執(zhí)行相同的行為,但是只有一個類可以有具體實現(xiàn);因此,通過組合多個接口,C++中的問題是不會在Java中發(fā)生的。

在導(dǎo)出類中,不強制要求必須有一個是抽象的或“具體的”基類。如果要從一個非接口的類繼承,那么只能從一個類去繼承,其余的基元素必須是接口。

需要將所有的接口名都置于implements關(guān)鍵字之后,用逗號將它們一一隔開。

可以繼承任意多個接口,并可以向上轉(zhuǎn)型為每個接口,因為每個接口都是一個獨立類型。

下面例子展示了一個具體類組合數(shù)個接口之后產(chǎn)生一個新類:

?

Hero組合了具體類ActionCharacter和接口CanFight、CanSwim和CanFly。當(dāng)通過這種方式講一個具體類和多個接口組合到一起時,這個具體類必須放在前面,后面跟著的才是接口。

這里注意到,CanFight接口與ActionCharacter類中的fight()方法的特征簽名是一樣的,而且,在Hero中并沒有提供fight()的定義。

可以擴展接口,但是得到的只是另一個接口。

當(dāng)想要創(chuàng)建對象時,所有的定義首先必須都存在,即使Hero沒有顯式地提供fight()的定義,其定義也因ActionCharacter而隨之而來,這樣就使得創(chuàng)建Hero對象成為了可能。

在Adventure類中,可以看到有四個方法把上述各種接口和具體類作為參數(shù),當(dāng)Hero對象被創(chuàng)建時,它可以被傳遞給這些方法中的任何一個,這意味著它一次被向上轉(zhuǎn)型為每一個接口。Java的這種設(shè)計接口的方式,使得這項工作并不需要程序員付出任何特別的努力。

使用接口的核心原因:

1).為了能夠向上轉(zhuǎn)型為多個基類型(以及由此帶來的靈活性);

2).防止客戶端程序員創(chuàng)建該類的對象,并確保這僅僅是建立一個接口(這與使用抽象類原因相同)

這帶來的一個問題是,應(yīng)該使用接口還是抽象類?

如果要創(chuàng)建不帶任何方法定義和成員變量的基類,那么就應(yīng)該選擇接口而不是抽象類。事實上,若知道某事物應(yīng)該成為一個基類,那么第一選擇應(yīng)該是接口。?

5.通過繼承來擴展接口

通過繼承,可以很容易地在接口中添加新的方法聲明,還可以通過繼承在新接口中組合數(shù)個接口,這兩種方式都可以獲得新的接口。

?

DangerousMonster是Monster的直接擴展,它產(chǎn)生了一個新接口。DragonZilla中實現(xiàn)了這個接口;?

在Vampire中使用的語法僅適用于接口繼承,一般情況下,只可以將extends用于單一類,但是可以引用多個基類接口,只需用逗號將接口名一一分隔開即可。

組合接口時的名字沖突

在實現(xiàn)多重繼承時,會碰到一個小陷阱,在前面的例子中,CanFight和ActionCharacter都有一個相同的void fight()方法。問題不是它們方法相同,問題是,如果它們的簽名(參數(shù))或返回類型不同,會怎么樣呢?

此時困難來了,因為覆蓋、實現(xiàn)和重載令人不快的攪在一起,而且重載方法僅通過返回類型是區(qū)分不開的。當(dāng)撤銷最后兩行的注釋時,下列錯誤消息說明了這一切:

?

在打算組合的不同接口中使用相同的方法名通常會造成代碼可讀性的混亂。?

6.適配接口

接口最吸引人的原因之一就是允許同一個接口具有多個不同的具體實現(xiàn)。在簡單的情況中,它的體現(xiàn)形式通常是一個接受接口類型的方法,而該接口的實現(xiàn)和向該方法傳遞的對象則取決于方法的使用者。

因此,接口的一種常見用法就是前面提到的策略設(shè)計模式。此時你編寫一個執(zhí)行某些操作的方法,而該方法接受一個同樣是你指定的接口。你主要就是要聲明:“你可以用任何你想要的對象來調(diào)用我的方法,只要你的對象遵循我的接口”。這使得方法更加靈活、通用,并更具有可復(fù)用性。

例如,Java SE5的Scanner類的構(gòu)造器接受的就是一個Readable接口,Readable沒有用作Java標(biāo)準(zhǔn)類庫中其他任何方法的參數(shù),它是單獨為Scanner創(chuàng)建的,以使得Scanner不必將其參數(shù)限制為某個特定類。通過這種方式,Scanner可以作用于更多的類型。如果你創(chuàng)建了一個新的類,并且想讓Scanner可以作用于它,那么你就應(yīng)該讓它稱為Readable,就像下面這樣:

也就是說,在Scanner構(gòu)造器內(nèi)部,接受一個參數(shù),這個參數(shù)是Readable的一個對象;

Readable接口可以實現(xiàn)read()方法,在read()內(nèi)部,將輸入內(nèi)容添加到CharBuffer參數(shù)中,或者在沒有任何輸入時返回-1;

假設(shè)你還有一個還未實現(xiàn)Readable的類,怎樣才能讓Scanner作用于它呢?下面這個類就是一個例子,它可以產(chǎn)生隨機浮點數(shù):

還未實現(xiàn)Readable是指,沒有實現(xiàn)read()方法?

再次使用了適配器模式,在這里,被適配的類可以通過繼承和實現(xiàn)Readable接口來創(chuàng)建。因此,通過使用interface關(guān)鍵字提供的偽多重繼承機制,可以生成的既是RandomDoubles又是Readable的新類:

在這種方式中,可以在任何現(xiàn)有類之上添加新的接口,所以這意味著讓方法接受接口類型,是一種讓任何類都可以對該方法進行適配的方式。這就是使用接口而不是類的強大之處。?

7.接口中的域

因為放入接口中的任何域都是static和final的,所以接口就成為了一種很便捷的用來創(chuàng)建常量組的工具。在Java SE5之前,這是產(chǎn)生與C++中的enum(枚舉類型)具有相同效果的類型的唯一途徑。因此,在Java SE5之前的代碼會看到下面這樣的代碼:

Java中標(biāo)識具有常量初始值的static final時,會使用大寫字母的風(fēng)格(在一個標(biāo)識符中用下劃線來分隔多個單詞);接口中的域自動是public的,所以沒有顯式地指明這一點。

有了Java SE5,既可以使用更加強大而靈活的enum關(guān)鍵字,因此,使用接口來群組常量已經(jīng)顯得沒什么意義了。

初始化接口中的域:?

在接口定義的域不能是“空final”,但是可以被非常量表達式初始化。例如:

既然,域是static的,它們就可以在類第一次被加載時初始化,這發(fā)生在任何域首次訪問時。下面是一個測試:

?

當(dāng)然,這些域不是接口的一部分,它們的值被存儲在該接口的靜態(tài)存儲區(qū)域內(nèi)。?

8.嵌套接口

接口可以嵌套在類或其他接口中。這揭示了許多有趣的特性:

在類中嵌套接口的語法是相當(dāng)顯而易見的,就像非嵌套接口一樣,可以擁有public和“包訪問”兩種可視性。

作為一種新添加的方式,接口也可以被實現(xiàn)為private的,就像在A.D中所看到的(相同的語法既適用于嵌套接口,也適用與嵌套類)。那么private的嵌套接口能帶來什么好處呢?

可能會猜想,它只能夠被實現(xiàn)為DImp中的一個private內(nèi)部類,但是A.DImp2展示了它同樣可以被實現(xiàn)為public類。但是,A.DImp2只能被其自身所使用。

你無法說他實現(xiàn)了一個private接口D。因此,實現(xiàn)一個private接口只是一種方式,他可以強制該接口中的方法定義不要添加任何類型信息(也就是說,不允許向上轉(zhuǎn)型)。

getD()方法使我們陷入一個進退兩難的境地,這個問題與private接口相關(guān):它是一個返回對private接口的引用的public方法。你對這個方法的返回值能做什么呢?在main()中,可以看到數(shù)次嘗試使用返回值的行為都失敗了。只有一種方式可成功,那就是將返回值交給有權(quán)使用它的對象(在這里只有D和A有權(quán)使用DImp2類,但前面不是說不允許向上轉(zhuǎn)型嗎?)。在本例中,是另一個A通過receiveD()方法來實現(xiàn)。

接口E說明接口接口彼此之間也可以嵌套,然而,作用域接口的各種規(guī)則,特別是所有的接口元素都必須是public的,在此都會被嚴格執(zhí)行。因此,嵌套在另一個接口中的接口自動就是public的,而不能被聲明為private的。

NestingInterface展示了嵌套接口的各種實現(xiàn)方式。特別要注意的是,當(dāng)實現(xiàn)某個接口時,并不需要實現(xiàn)嵌套在其內(nèi)部的任何接口。而且private接口不能在定義它的類之外被實現(xiàn)。

添加這些特性的最初原因可能是處于對嚴格的語法一致性的考慮,但是作者認為,一旦了解了某種特性,就總能夠找到他的用武之地。

9.接口與工廠

接口是實現(xiàn)多重繼承的途徑,而生成遵循某個接口的對象的典型方式就是工廠方法設(shè)計模式。

這與直接調(diào)用構(gòu)造器不同,在工廠對象上調(diào)用的是創(chuàng)建方法,而該工廠對象將生成接口的某個實現(xiàn)的對象。

理論上,通過這種方式,我們的代碼將完全與接口的實現(xiàn)分離,這就使得我們可以透明地將某個實現(xiàn)替換為另一個實現(xiàn)。下面的實例展示了工廠方法的結(jié)構(gòu):

?如果不是用工廠方法,你的代碼就必須在某處指定將要創(chuàng)建的Service的確切類型,以便調(diào)用合適的構(gòu)造器。

為什么想要創(chuàng)建這種額外級別的間接性?一個常見的原因就是想要創(chuàng)建框架:假設(shè)你正在創(chuàng)建一個對弈游戲系統(tǒng),例如,在相同的棋盤上下國際象棋和西洋跳棋:

如果Games類表示一段復(fù)雜的代碼,那么這種方式就允許你在不同類型的游戲中復(fù)用這段代碼。你可以想象一些能夠從這個模式中受益的更加精巧的游戲。

下一章的工廠實現(xiàn)方式是:內(nèi)部類。

?

?

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/ifreewolf/p/11254012.html

總結(jié)

以上是生活随笔為你收集整理的Java学习笔记---接口的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。