默認(rèn)方法
接口部分描述了一個涉及計算機控制汽車制造商的例子,他們發(fā)布了行業(yè)標(biāo)準(zhǔn)接口,描述了可以調(diào)用哪些方法來操作他們的汽車,如果那些計算機控制的汽車制造商為他們的汽車添加新的功能,如飛行,該怎么辦?這些制造商需要指定新的方法,以使其他公司(如電子制導(dǎo)儀器制造商)能夠使其軟件適應(yīng)飛行汽車,這些汽車制造商將在哪里聲明這些與飛行有關(guān)的新方法?如果他們將它們添加到原始接口,那么實現(xiàn)了這些接口的程序員將不得不重寫他們的實現(xiàn),如果他們將它們作為靜態(tài)方法添加,那么程序員會將它們視為實用方法,而不是必要的核心方法。
默認(rèn)方法使你能夠向庫的接口添加新功能,并確保與為這些接口的舊版本編寫的代碼的二進(jìn)制兼容性。
考慮以下接口TimeClient:
import java.time.*; public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); }
以下類SimpleTimeClient實現(xiàn)了TimeClient:
package defaultmethods; import java.time.*; import java.lang.*; import java.util.*; public class SimpleTimeClient implements TimeClient { private LocalDateTime dateAndTime; public SimpleTimeClient() { dateAndTime = LocalDateTime.now(); } public void setTime(int hour, int minute, int second) { LocalDate currentDate = LocalDate.from(dateAndTime); LocalTime timeToSet = LocalTime.of(hour, minute, second); dateAndTime = LocalDateTime.of(currentDate, timeToSet); } public void setDate(int day, int month, int year) { LocalDate dateToSet = LocalDate.of(day, month, year); LocalTime currentTime = LocalTime.from(dateAndTime); dateAndTime = LocalDateTime.of(dateToSet, currentTime); } public void setDateAndTime(int day, int month, int year, int hour, int minute, int second) { LocalDate dateToSet = LocalDate.of(day, month, year); LocalTime timeToSet = LocalTime.of(hour, minute, second); dateAndTime = LocalDateTime.of(dateToSet, timeToSet); } public LocalDateTime getLocalDateTime() { return dateAndTime; } public String toString() { return dateAndTime.toString(); } public static void main(String... args) { TimeClient myTimeClient = new SimpleTimeClient(); System.out.println(myTimeClient.toString()); } }
假設(shè)你要向TimeClient接口添加新功能,例如通過ZonedDateTime對象指定時區(qū)的能力(除了它存儲時區(qū)信息之外,它類似于LocalDateTime對象):
public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); ZonedDateTime getZonedDateTime(String zoneString); }
在對TimeClient接口進(jìn)行此修改之后,你還必須修改類SimpleTimeClient并實現(xiàn)方法getZonedDateTime,但是,你可以改為定義默認(rèn)實現(xiàn),而不是將getZonedDateTime保留為抽象(如上例所示),請記住,抽象方法是在沒有實現(xiàn)的情況下聲明的方法。
package defaultmethods; import java.time.*; public interface TimeClient { void setTime(int hour, int minute, int second); void setDate(int day, int month, int year); void setDateAndTime(int day, int month, int year, int hour, int minute, int second); LocalDateTime getLocalDateTime(); static ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } }
你可以指定接口中的方法定義是一個默認(rèn)方法,在方法簽名的開頭使用default關(guān)鍵字,接口中的所有方法聲明(包括默認(rèn)方法)都是隱式public,因此你可以省略public修飾符。
使用此接口,你不必修改類SimpleTimeClient,并且此類(以及實現(xiàn)TimeClient接口的任何類)將已定義方法getZonedDateTime,以下示例TestSimpleTimeClient從SimpleTimeClient的實例調(diào)用方法getZonedDateTime:
package defaultmethods; import java.time.*; import java.lang.*; import java.util.*; public class TestSimpleTimeClient { public static void main(String... args) { TimeClient myTimeClient = new SimpleTimeClient(); System.out.println("Current time: " + myTimeClient.toString()); System.out.println("Time in California: " + myTimeClient.getZonedDateTime("Blah blah").toString()); } }擴展包含默認(rèn)方法的接口
擴展包含默認(rèn)方法的接口時,可以執(zhí)行以下操作:
完全不要提到默認(rèn)方法,它允許擴展接口繼承默認(rèn)方法。
重新聲明默認(rèn)方法,使其成為抽象方法。
重新定義覆蓋它的默認(rèn)方法。
假設(shè)你按如下方式擴展TimeClient接口:
public interface AnotherTimeClient extends TimeClient { }
任何實現(xiàn)接口AnotherTimeClient的類都將具有默認(rèn)方法TimeClient.getZonedDateTime指定的實現(xiàn)。
假設(shè)你按如下方式擴展TimeClient接口:
public interface AbstractZoneTimeClient extends TimeClient { public ZonedDateTime getZonedDateTime(String zoneString); }
任何實現(xiàn)AbstractZoneTimeClient接口的類都必須實現(xiàn)getZonedDateTime方法,此方法是一個抽象方法,就像接口中的所有其他非默認(rèn)(和非靜態(tài))方法一樣。
假設(shè)你按如下方式擴展TimeClient接口:
public interface HandleInvalidTimeZoneClient extends TimeClient { default public ZonedDateTime getZonedDateTime(String zoneString) { try { return ZonedDateTime.of(getLocalDateTime(),ZoneId.of(zoneString)); } catch (DateTimeException e) { System.err.println("Invalid zone ID: " + zoneString + "; using the default time zone instead."); return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault()); } } }
任何實現(xiàn)HandleInvalidTimeZoneClient接口的類都將使用此接口指定的getZonedDateTime實現(xiàn),而不是接口TimeClient指定的實現(xiàn)。
靜態(tài)方法除了默認(rèn)方法,你還可以在接口中定義靜態(tài)方法(靜態(tài)方法是一種與定義它的類相關(guān)聯(lián)的方法,而不是與任何對象相關(guān)聯(lián)的方法,該類的每個實例都共享其靜態(tài)方法)。這使你可以更輕松地在庫中組織輔助方法,你可以在同一個接口中保留特定于接口的靜態(tài)方法,而不是在多帶帶的類中。以下示例定義一個靜態(tài)方法,該方法檢索與時區(qū)標(biāo)識符對應(yīng)的ZoneId對象,如果沒有與給定標(biāo)識符對應(yīng)的ZoneId對象,它將使用系統(tǒng)默認(rèn)時區(qū)(因此,你可以簡化方法getZonedDateTime)。
public interface TimeClient { // ... static public ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default public ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } }
與類中的靜態(tài)方法一樣,你可以在方法簽名的開頭使用static關(guān)鍵字指定接口中的方法定義是靜態(tài)方法,接口中的所有方法聲明(包括靜態(tài)方法)都是隱式public,因此你可以省略public修飾符。
將默認(rèn)方法集成到現(xiàn)有庫中默認(rèn)方法使你能夠向現(xiàn)有接口添加新功能,并確保與為這些接口的舊版本編寫的代碼的二進(jìn)制兼容性,特別是,默認(rèn)方法使你能夠?qū)⒔邮躭ambda表達(dá)式的方法添加為現(xiàn)有接口的參數(shù),本節(jié)演示如何使用默認(rèn)和靜態(tài)方法增強Comparator接口。
考慮Card和Deck類,此示例將Card和Deck類重寫為接口,Card接口包含兩個枚舉類型(Suit和Rank)和兩個抽象方法(getSuit和getRank):
package defaultmethods; public interface Card extends Comparable{ public enum Suit { DIAMONDS (1, "Diamonds"), CLUBS (2, "Clubs" ), HEARTS (3, "Hearts" ), SPADES (4, "Spades" ); private final int value; private final String text; Suit(int value, String text) { this.value = value; this.text = text; } public int value() {return value;} public String text() {return text;} } public enum Rank { DEUCE (2 , "Two" ), THREE (3 , "Three"), FOUR (4 , "Four" ), FIVE (5 , "Five" ), SIX (6 , "Six" ), SEVEN (7 , "Seven"), EIGHT (8 , "Eight"), NINE (9 , "Nine" ), TEN (10, "Ten" ), JACK (11, "Jack" ), QUEEN (12, "Queen"), KING (13, "King" ), ACE (14, "Ace" ); private final int value; private final String text; Rank(int value, String text) { this.value = value; this.text = text; } public int value() {return value;} public String text() {return text;} } public Card.Suit getSuit(); public Card.Rank getRank(); }
Deck接口包含操作deck中卡片的各種方法:
package defaultmethods; import java.util.*; import java.util.stream.*; import java.lang.*; public interface Deck { ListgetCards(); Deck deckFactory(); int size(); void addCard(Card card); void addCards(List cards); void addDeck(Deck deck); void shuffle(); void sort(); void sort(Comparator c); String deckToString(); Map deal(int players, int numberOfCards) throws IllegalArgumentException; }
PlayingCard類實現(xiàn)了接口Card,而StandardDeck類實現(xiàn)了接口Deck。
StandardDeck類實現(xiàn)了抽象方法Deck.sort,如下所示:
public class StandardDeck implements Deck { private ListentireDeck; // ... public void sort() { Collections.sort(entireDeck); } // ... }
方法Collections.sort對List的實例進(jìn)行排序,其元素類型實現(xiàn)了Comparable接口,成員entireDeck是List的一個實例,其元素的類型為Card,它擴展了Comparable,PlayingCard類實現(xiàn)Comparable.compareTo方法,如下所示:
public int hashCode() { return ((suit.value()-1)*13)+rank.value(); } public int compareTo(Card o) { return this.hashCode() - o.hashCode(); }
方法compareTo導(dǎo)致方法StandardDeck.sort()首先按花色對一副牌進(jìn)行排序,然后按等級排序。
如果你想先按等級排序,然后按花色排序怎么辦?你需要實現(xiàn)Comparator接口以指定新的排序條件,并使用方法sort(List
public void sort(Comparatorc) { Collections.sort(entireDeck, c); }
使用此方法,你可以指定方法Collections.sort如何對Card類的實例進(jìn)行排序,一種方法是實現(xiàn)Comparator接口,以指定你希望卡片的排序方式,示例SortByRankThenSuit執(zhí)行此操作:
package defaultmethods; import java.util.*; import java.util.stream.*; import java.lang.*; public class SortByRankThenSuit implements Comparator{ public int compare(Card firstCard, Card secondCard) { int compVal = firstCard.getRank().value() - secondCard.getRank().value(); if (compVal != 0) return compVal; else return firstCard.getSuit().value() - secondCard.getSuit().value(); } }
以下調(diào)用首先按等級對撲克牌組進(jìn)行排序,然后按照花色進(jìn)行排序:
StandardDeck myDeck = new StandardDeck(); myDeck.shuffle(); myDeck.sort(new SortByRankThenSuit());
但是,這種方法過于冗長,如果你可以指定你想要排序的東西,而不是你想要排序的方式會更好,假設(shè)你是編寫Comparator接口的開發(fā)人員,你可以向Comparator接口添加哪些默認(rèn)或靜態(tài)方法,以使其他開發(fā)人員能夠更輕松地指定排序條件?
首先,假設(shè)你想要按等級對撲克牌進(jìn)行排序,而不考慮花色,你可以按如下方式調(diào)用StandardDeck.sort方法:
StandardDeck myDeck = new StandardDeck(); myDeck.shuffle(); myDeck.sort( (firstCard, secondCard) -> firstCard.getRank().value() - secondCard.getRank().value() );
因為接口Comparator是一個功能性接口,所以可以使用lambda表達(dá)式作為sort方法的參數(shù),在此示例中,lambda表達(dá)式比較兩個整數(shù)值。
如果他們可以通過僅調(diào)用Card.getRank方法創(chuàng)建Comparator實例,那么對于你的開發(fā)人員來說會更簡單,特別是,如果你的開發(fā)人員可以創(chuàng)建一個Comparator實例來比較任何可以從getValue或hashCode等方法返回數(shù)值的對象,那將會很有幫助。使用此靜態(tài)方法comparing增強了Comparator接口:
myDeck.sort(Comparator.comparing((card) -> card.getRank()));
在此示例中,你可以使用方法引用:
myDeck.sort(Comparator.comparing(Card::getRank));
此調(diào)用更好地演示了要排序的內(nèi)容而不是如何進(jìn)行排序。
Comparator接口已經(jīng)通過靜態(tài)方法comparing的其他版本得到了增強,例如comparingDouble和comparingLong,它們使你能夠創(chuàng)建比較其他數(shù)據(jù)類型的Comparator實例。
假設(shè)你的開發(fā)人員想要創(chuàng)建一個可以用多個標(biāo)準(zhǔn)比較對象的Comparator實例,例如,你如何先按等級排序撲克牌,然后按花色排序?和以前一樣,你可以使用lambda表達(dá)式來指定這些排序條件:
StandardDeck myDeck = new StandardDeck(); myDeck.shuffle(); myDeck.sort( (firstCard, secondCard) -> { int compare = firstCard.getRank().value() - secondCard.getRank().value(); if (compare != 0) return compare; else return firstCard.getSuit().value() - secondCard.getSuit().value(); } );
如果可以從一系列Comparator實例構(gòu)建Comparator實例,那么對于你的開發(fā)人員來說會更簡單,Comparator接口已通過默認(rèn)方法thenComparing增強了此功能:
myDeck.sort( Comparator .comparing(Card::getRank) .thenComparing(Comparator.comparing(Card::getSuit)));
Comparator接口已使用其他版本的默認(rèn)方法thenComparing進(jìn)行了增強(例如thenComparingDouble和thenComparingLong),使你可以構(gòu)建比較其他數(shù)據(jù)類型的Comparator實例。
假設(shè)你的開發(fā)人員想要創(chuàng)建一個Comparator實例,使其能夠以相反的順序?qū)ο蠹线M(jìn)行排序,例如,你如何按照等級的降序排序撲克牌組,從Ace到2(而不是從2到Ace)?和以前一樣,你可以指定另一個lambda表達(dá)式,但是,如果你的開發(fā)人員可以通過調(diào)用方法來反轉(zhuǎn)現(xiàn)有的Comparator,那么它會更簡單,使用此功能增強了Comparator接口,默認(rèn)方法reversed:
myDeck.sort( Comparator.comparing(Card::getRank) .reversed() .thenComparing(Comparator.comparing(Card::getSuit)));
這個例子演示了Comparator接口是如何通過默認(rèn)方法、靜態(tài)方法、lambda表達(dá)式和方法引用來增強的,從而創(chuàng)建更具表現(xiàn)力的庫方法,程序員可以通過查看調(diào)用這些方法的方式來快速推斷這些方法的功能,使用這些構(gòu)造來增強庫中的接口。
上一篇:不斷發(fā)展的接口 下一篇:繼承文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/72878.html
摘要:占市場份額,剩下是其他的開發(fā)工具。總之集成開發(fā)工具就是為了提高開發(fā)速度。編寫第一個程序在上點擊右鍵填寫上類名在下面有一個選中創(chuàng)建方法。 使用集成開發(fā)工具eclipse 1、java的集成開發(fā)工具很多,包括:eclipse、Intellij IDEA、netbeans..... eclips...
不斷發(fā)展的接口 考慮一下你開發(fā)的名為DoIt的接口: public interface DoIt { void doSomething(int i, double x); int doSomethingElse(String s); } 假設(shè)稍后你要向DoIt添加第三個方法,這樣現(xiàn)在接口變?yōu)椋?public interface DoIt { void doSomething(i...
接口 軟件工程中存在許多情況,當(dāng)不同的程序員團隊同意一份合約來闡明他們的軟件如何交互時很重要,每個組都應(yīng)該能夠在不知道如何編寫其他組代碼的情況下編寫代碼,一般來說,接口就是這樣的合約。 例如,想象一個未來主義社會,計算機控制的機器人汽車在沒有人工操作員的情況下將乘客運送到城市街道,汽車制造商編寫操作汽車的軟件(當(dāng)然是Java) - 停止,啟動,加速,向左轉(zhuǎn),等等,另一個工業(yè)集團,電子制導(dǎo)儀器制造商...
摘要:典型示例以下結(jié)構(gòu)是比較推薦的組織方式,所有的類和其他都在之下。應(yīng)用主類,該類直接位于下。默認(rèn)情況下,的應(yīng)用主類會自動掃描以及所有子包下的所有類來進(jìn)行初始化。 Spring Boot框架本身并沒有對工程結(jié)構(gòu)有特別的要求,但是按照最佳實踐的工程結(jié)構(gòu)可以幫助我們減少可能會遇見的坑,尤其是Spring包掃描機制的存在,如果您使用最佳實踐的工程結(jié)構(gòu),可以免去不少特殊的配置工作。 典型示例 以下結(jié)...
Java? 教程 Java教程是為JDK 8編寫的,本頁面中描述的示例和實踐沒有利用在后續(xù)版本中引入的改進(jìn)。 Java教程是希望使用Java編程語言創(chuàng)建應(yīng)用程序的程序員的實用指南,其中包括數(shù)百個完整的工作示例和數(shù)十個課程,相關(guān)課程組被組織成教程。 覆蓋基礎(chǔ)知識的路徑 這些教程以書籍的形式提供,如Java教程,第六版,前往Amazon.com購買。 入門 介紹Java技術(shù)和安裝Java開發(fā)軟件并使用...
閱讀 3235·2021-11-23 09:51
閱讀 2480·2021-09-27 13:34
閱讀 2464·2021-09-08 09:45
閱讀 662·2019-08-30 15:44
閱讀 3493·2019-08-29 12:17
閱讀 2759·2019-08-26 12:18
閱讀 2622·2019-08-26 10:10
閱讀 3078·2019-08-23 18:02