成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java? 教程(默認(rèn)方法)

zhisheng / 3450人閱讀

默認(rèn)方法

接口部分描述了一個(gè)涉及計(jì)算機(jī)控制汽車制造商的例子,他們發(fā)布了行業(yè)標(biāo)準(zhǔn)接口,描述了可以調(diào)用哪些方法來(lái)操作他們的汽車,如果那些計(jì)算機(jī)控制的汽車制造商為他們的汽車添加新的功能,如飛行,該怎么辦?這些制造商需要指定新的方法,以使其他公司(如電子制導(dǎo)儀器制造商)能夠使其軟件適應(yīng)飛行汽車,這些汽車制造商將在哪里聲明這些與飛行有關(guān)的新方法?如果他們將它們添加到原始接口,那么實(shí)現(xiàn)了這些接口的程序員將不得不重寫他們的實(shí)現(xiàn),如果他們將它們作為靜態(tài)方法添加,那么程序員會(huì)將它們視為實(shí)用方法,而不是必要的核心方法。

默認(rèn)方法使你能夠向庫(kù)的接口添加新功能,并確保與為這些接口的舊版本編寫的代碼的二進(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實(shí)現(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接口添加新功能,例如通過(guò)ZonedDateTime對(duì)象指定時(shí)區(qū)的能力(除了它存儲(chǔ)時(shí)區(qū)信息之外,它類似于LocalDateTime對(duì)象):

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);
}

在對(duì)TimeClient接口進(jìn)行此修改之后,你還必須修改類SimpleTimeClient并實(shí)現(xiàn)方法getZonedDateTime,但是,你可以改為定義默認(rèn)實(shí)現(xiàn),而不是將getZonedDateTime保留為抽象(如上例所示),請(qǐng)記住,抽象方法是在沒有實(shí)現(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));
    }
}

你可以指定接口中的方法定義是一個(gè)默認(rèn)方法,在方法簽名的開頭使用default關(guān)鍵字,接口中的所有方法聲明(包括默認(rèn)方法)都是隱式public,因此你可以省略public修飾符。

使用此接口,你不必修改類SimpleTimeClient,并且此類(以及實(shí)現(xiàn)TimeClient接口的任何類)將已定義方法getZonedDateTime,以下示例TestSimpleTimeClientSimpleTimeClient的實(shí)例調(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());
    }
}
擴(kuò)展包含默認(rèn)方法的接口

擴(kuò)展包含默認(rèn)方法的接口時(shí),可以執(zhí)行以下操作:

完全不要提到默認(rèn)方法,它允許擴(kuò)展接口繼承默認(rèn)方法。

重新聲明默認(rèn)方法,使其成為抽象方法。

重新定義覆蓋它的默認(rèn)方法。

假設(shè)你按如下方式擴(kuò)展TimeClient接口:

public interface AnotherTimeClient extends TimeClient { }

任何實(shí)現(xiàn)接口AnotherTimeClient的類都將具有默認(rèn)方法TimeClient.getZonedDateTime指定的實(shí)現(xiàn)。

假設(shè)你按如下方式擴(kuò)展TimeClient接口:

public interface AbstractZoneTimeClient extends TimeClient {
    public ZonedDateTime getZonedDateTime(String zoneString);
}

任何實(shí)現(xiàn)AbstractZoneTimeClient接口的類都必須實(shí)現(xiàn)getZonedDateTime方法,此方法是一個(gè)抽象方法,就像接口中的所有其他非默認(rèn)(和非靜態(tài))方法一樣。

假設(shè)你按如下方式擴(kuò)展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());
        }
    }
}

任何實(shí)現(xiàn)HandleInvalidTimeZoneClient接口的類都將使用此接口指定的getZonedDateTime實(shí)現(xiàn),而不是接口TimeClient指定的實(shí)現(xiàn)。

靜態(tài)方法

除了默認(rèn)方法,你還可以在接口中定義靜態(tài)方法(靜態(tài)方法是一種與定義它的類相關(guān)聯(lián)的方法,而不是與任何對(duì)象相關(guān)聯(lián)的方法,該類的每個(gè)實(shí)例都共享其靜態(tài)方法)。這使你可以更輕松地在庫(kù)中組織輔助方法,你可以在同一個(gè)接口中保留特定于接口的靜態(tài)方法,而不是在多帶帶的類中。以下示例定義一個(gè)靜態(tài)方法,該方法檢索與時(shí)區(qū)標(biāo)識(shí)符對(duì)應(yīng)的ZoneId對(duì)象,如果沒有與給定標(biāo)識(shí)符對(duì)應(yīng)的ZoneId對(duì)象,它將使用系統(tǒng)默認(rèn)時(shí)區(qū)(因此,你可以簡(jiǎn)化方法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)有庫(kù)中

默認(rèn)方法使你能夠向現(xiàn)有接口添加新功能,并確保與為這些接口的舊版本編寫的代碼的二進(jìn)制兼容性,特別是,默認(rèn)方法使你能夠?qū)⒔邮躭ambda表達(dá)式的方法添加為現(xiàn)有接口的參數(shù),本節(jié)演示如何使用默認(rèn)和靜態(tài)方法增強(qiáng)Comparator接口。

考慮CardDeck類,此示例將Card和Deck類重寫為接口,Card接口包含兩個(gè)枚舉類型(SuitRank)和兩個(gè)抽象方法(getSuitgetRank):

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 {
    
    List getCards();
    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類實(shí)現(xiàn)了接口Card,而StandardDeck類實(shí)現(xiàn)了接口Deck。

StandardDeck類實(shí)現(xiàn)了抽象方法Deck.sort,如下所示:

public class StandardDeck implements Deck {
    
    private List entireDeck;
    
    // ...
    
    public void sort() {
        Collections.sort(entireDeck);
    }
    
    // ...
}

方法Collections.sort對(duì)List的實(shí)例進(jìn)行排序,其元素類型實(shí)現(xiàn)了Comparable接口,成員entireDeck是List的一個(gè)實(shí)例,其元素的類型為Card,它擴(kuò)展了Comparable,PlayingCard類實(shí)現(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()首先按花色對(duì)一副牌進(jìn)行排序,然后按等級(jí)排序。

如果你想先按等級(jí)排序,然后按花色排序怎么辦?你需要實(shí)現(xiàn)Comparator接口以指定新的排序條件,并使用方法sort(List list, Comparator c)(包含Comparator參數(shù)的sort方法的版本),你可以在StandardDeck類中定義以下方法:

public void sort(Comparator c) {
    Collections.sort(entireDeck, c);
}

使用此方法,你可以指定方法Collections.sort如何對(duì)Card類的實(shí)例進(jìn)行排序,一種方法是實(shí)現(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í)對(duì)撲克牌組進(jìn)行排序,然后按照花色進(jìn)行排序:

StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort(new SortByRankThenSuit());

但是,這種方法過(guò)于冗長(zhǎng),如果你可以指定你想要排序的東西,而不是你想要排序的方式會(huì)更好,假設(shè)你是編寫Comparator接口的開發(fā)人員,你可以向Comparator接口添加哪些默認(rèn)或靜態(tài)方法,以使其他開發(fā)人員能夠更輕松地指定排序條件?

首先,假設(shè)你想要按等級(jí)對(duì)撲克牌進(jìn)行排序,而不考慮花色,你可以按如下方式調(diào)用StandardDeck.sort方法:

StandardDeck myDeck = new StandardDeck();
myDeck.shuffle();
myDeck.sort(
    (firstCard, secondCard) ->
        firstCard.getRank().value() - secondCard.getRank().value()
); 

因?yàn)榻涌?b>Comparator是一個(gè)功能性接口,所以可以使用lambda表達(dá)式作為sort方法的參數(shù),在此示例中,lambda表達(dá)式比較兩個(gè)整數(shù)值。

如果他們可以通過(guò)僅調(diào)用Card.getRank方法創(chuàng)建Comparator實(shí)例,那么對(duì)于你的開發(fā)人員來(lái)說(shuō)會(huì)更簡(jiǎn)單,特別是,如果你的開發(fā)人員可以創(chuàng)建一個(gè)Comparator實(shí)例來(lái)比較任何可以從getValuehashCode等方法返回?cái)?shù)值的對(duì)象,那將會(huì)很有幫助。使用此靜態(tài)方法comparing增強(qiáng)了Comparator接口:

myDeck.sort(Comparator.comparing((card) -> card.getRank()));

在此示例中,你可以使用方法引用:

myDeck.sort(Comparator.comparing(Card::getRank));

此調(diào)用更好地演示了要排序的內(nèi)容而不是如何進(jìn)行排序。

Comparator接口已經(jīng)通過(guò)靜態(tài)方法comparing的其他版本得到了增強(qiáng),例如comparingDouble和comparingLong,它們使你能夠創(chuàng)建比較其他數(shù)據(jù)類型的Comparator實(shí)例。

假設(shè)你的開發(fā)人員想要?jiǎng)?chuàng)建一個(gè)可以用多個(gè)標(biāo)準(zhǔn)比較對(duì)象的Comparator實(shí)例,例如,你如何先按等級(jí)排序撲克牌,然后按花色排序?和以前一樣,你可以使用lambda表達(dá)式來(lái)指定這些排序條件:

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實(shí)例構(gòu)建Comparator實(shí)例,那么對(duì)于你的開發(fā)人員來(lái)說(shuō)會(huì)更簡(jiǎn)單,Comparator接口已通過(guò)默認(rèn)方法thenComparing增強(qiáng)了此功能:

myDeck.sort(
    Comparator
        .comparing(Card::getRank)
        .thenComparing(Comparator.comparing(Card::getSuit)));

Comparator接口已使用其他版本的默認(rèn)方法thenComparing進(jìn)行了增強(qiáng)(例如thenComparingDouble和thenComparingLong),使你可以構(gòu)建比較其他數(shù)據(jù)類型的Comparator實(shí)例。

假設(shè)你的開發(fā)人員想要?jiǎng)?chuàng)建一個(gè)Comparator實(shí)例,使其能夠以相反的順序?qū)?duì)象集合進(jìn)行排序,例如,你如何按照等級(jí)的降序排序撲克牌組,從Ace到2(而不是從2到Ace)?和以前一樣,你可以指定另一個(gè)lambda表達(dá)式,但是,如果你的開發(fā)人員可以通過(guò)調(diào)用方法來(lái)反轉(zhuǎn)現(xiàn)有的Comparator,那么它會(huì)更簡(jiǎn)單,使用此功能增強(qiáng)了Comparator接口,默認(rèn)方法reversed:

myDeck.sort(
    Comparator.comparing(Card::getRank)
        .reversed()
        .thenComparing(Comparator.comparing(Card::getSuit)));

這個(gè)例子演示了Comparator接口是如何通過(guò)默認(rèn)方法、靜態(tài)方法、lambda表達(dá)式和方法引用來(lái)增強(qiáng)的,從而創(chuàng)建更具表現(xiàn)力的庫(kù)方法,程序員可以通過(guò)查看調(diào)用這些方法的方式來(lái)快速推斷這些方法的功能,使用這些構(gòu)造來(lái)增強(qiáng)庫(kù)中的接口。

上一篇:不斷發(fā)展的接口 下一篇:繼承

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/72878.html

相關(guān)文章

  • Java基礎(chǔ)學(xué)習(xí)教程,eclipse簡(jiǎn)單使用教程Java集成開發(fā)工具)

    摘要:占市場(chǎng)份額,剩下是其他的開發(fā)工具??傊砷_發(fā)工具就是為了提高開發(fā)速度。編寫第一個(gè)程序在上點(diǎn)擊右鍵填寫上類名在下面有一個(gè)選中創(chuàng)建方法。 使用集成開發(fā)工具eclipse 1、java的集成開發(fā)工具很多,包括:eclipse、Intellij IDEA、netbeans..... eclips...

    AlanKeene 評(píng)論0 收藏0
  • Java? 教程(不斷發(fā)展的接口)

    不斷發(fā)展的接口 考慮一下你開發(fā)的名為DoIt的接口: public interface DoIt { void doSomething(int i, double x); int doSomethingElse(String s); } 假設(shè)稍后你要向DoIt添加第三個(gè)方法,這樣現(xiàn)在接口變?yōu)椋?public interface DoIt { void doSomething(i...

    libin19890520 評(píng)論0 收藏0
  • Java? 教程(接口)

    接口 軟件工程中存在許多情況,當(dāng)不同的程序員團(tuán)隊(duì)同意一份合約來(lái)闡明他們的軟件如何交互時(shí)很重要,每個(gè)組都應(yīng)該能夠在不知道如何編寫其他組代碼的情況下編寫代碼,一般來(lái)說(shuō),接口就是這樣的合約。 例如,想象一個(gè)未來(lái)主義社會(huì),計(jì)算機(jī)控制的機(jī)器人汽車在沒有人工操作員的情況下將乘客運(yùn)送到城市街道,汽車制造商編寫操作汽車的軟件(當(dāng)然是Java) - 停止,啟動(dòng),加速,向左轉(zhuǎn),等等,另一個(gè)工業(yè)集團(tuán),電子制導(dǎo)儀器制造商...

    amuqiao 評(píng)論0 收藏0
  • Spring Boot 2.x基礎(chǔ)教程:工程結(jié)構(gòu)推薦

    摘要:典型示例以下結(jié)構(gòu)是比較推薦的組織方式,所有的類和其他都在之下。應(yīng)用主類,該類直接位于下。默認(rèn)情況下,的應(yīng)用主類會(huì)自動(dòng)掃描以及所有子包下的所有類來(lái)進(jìn)行初始化。 Spring Boot框架本身并沒有對(duì)工程結(jié)構(gòu)有特別的要求,但是按照最佳實(shí)踐的工程結(jié)構(gòu)可以幫助我們減少可能會(huì)遇見的坑,尤其是Spring包掃描機(jī)制的存在,如果您使用最佳實(shí)踐的工程結(jié)構(gòu),可以免去不少特殊的配置工作。 典型示例 以下結(jié)...

    CollinPeng 評(píng)論0 收藏0
  • Java? 教程(目錄)

    Java? 教程 Java教程是為JDK 8編寫的,本頁(yè)面中描述的示例和實(shí)踐沒有利用在后續(xù)版本中引入的改進(jìn)。 Java教程是希望使用Java編程語(yǔ)言創(chuàng)建應(yīng)用程序的程序員的實(shí)用指南,其中包括數(shù)百個(gè)完整的工作示例和數(shù)十個(gè)課程,相關(guān)課程組被組織成教程。 覆蓋基礎(chǔ)知識(shí)的路徑 這些教程以書籍的形式提供,如Java教程,第六版,前往Amazon.com購(gòu)買。 入門 介紹Java技術(shù)和安裝Java開發(fā)軟件并使用...

    lifesimple 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<