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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java default 方法

發布時間:2024/1/18 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java default 方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Default 方法

前言:當我在用Spring boot框架開發項目中配置Webconfig類時,該類實現了WebMvcConfigurerAdapter抽象類。但是IDE提示WebMvcConfigurerAdapter類已被棄用,查看該類的定義發現已被@Deprecated注解標記,Spring-webmvc的版本為5.0.6。接著查看它實現的WebMvcConfigurer接口,發現該接口下的所有方法都變成了以default開頭的方法,由于之前不了解default關鍵字,因此查閱官方文檔,便有了下面的翻譯。

原文鏈接:https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

部分Interface描述了一個示例,該示例涉及計算機控制的汽車制造商,他們發布行業標準接口,描述可以調用哪些方法來操作他們的汽車。如果那些電腦控制的汽車制造商向他們的汽車添加新的功能,比如飛行,會怎么樣呢?這些制造商需要指定新的方法,以使其他公司(如電子導航儀器制造商)能夠使他們的軟件適應飛行汽車。這些汽車制造商將在哪里聲明這些新的飛行相關的方法?如果將它們添加到原始接口中,那么已經實現了這些接口的程序員將不得不重寫他們的實現。如果將它們以靜態方法的方式添加,那么程序員將視它們為實用方法,而不是本質的核心的方法。

default方法能夠使你向庫中添加新的功能,并確保它們和這些接口舊版本現有的代碼二進制兼容。

考慮下面的interface,TimeClient,如在Answers to Questions and Exercises: Interfaces中的描述:

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類實現了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());} }

假如你想向TimeClient 接口添加新的功能,例如通過ZonedDateTime對象指定時區的能力(這就像一個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接口,你將不得不修改SimpleTimeClient 類,并且實現getZonedDateTime方法。然而你不必保持getZonedDateTime方法為抽象方法(像之前的例子一樣),取而代之可以定義一個默認的實現。(記住,抽象方法是在沒有實現的情況下聲明的方法)。

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

你通過在方法簽名前以default關鍵字開始的方式,在一個接口中指定了一個方法的定義。在interface中,所有的方法聲明,包括default方法的可見范圍都隱式的聲明為public,因此你可以省略這個public修飾符。

對于這個interface,你不需要改變SimpleTimeClient類,這個類(任何實現了接口TimeClient的類)將有已經定義了的getZonedDateTime方法。下面這個例子,TestSimpleTimeClient類從SimpleTimeClient類的一個實例中調用了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());} }

繼承包含default方法的接口

當你繼承一個包含default方法的接口時,你可以執行以下操作:

  • 根本不用提及default方法,這讓你繼承的接口繼承default方法。
  • 重新聲明default方法,使它成為抽象方法。
  • 重新定義default方法,重寫default方法。

假如你像下面這樣繼承TimeClient接口:

public interface AnotherTimeClient extends TimeClient { }

實現了AnotherTimeClient 接口的任何類,都將擁有default方法TimeClient.getZonedDateTime的實現。

假如你像下面這樣繼承TimeClient接口:

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

任何實現了AbstractZoneTimeClient 接口的類,都將不得不實現getZonedDateTime方法;這個方法是一個抽象方法,像一個接口中所有其他非default(和非靜態)方法一樣。

假如你像下面這樣繼承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());}} }

所有實現了HandleInvalidTimeZoneClient 接口的類,都將使用HandleInvalidTimeZoneClient 接口中實現的getZonedDateTime 方法,而不是第一個接口TimeClient中的getZonedDateTime 方法。

靜態方法

除了default方法,你可以在接口中定義靜態方法。(靜態方法是與定義它的類相關聯的方法,而不是與任何對象相關聯的方法。類的每個實例都共享其靜態方法。)這個使你更容易在函數庫中組織輔助方法;你可以保持靜態方法與同一個接口中,而不是分開的類中。下面的例子定義了一個靜態方法,該方法依據地區標識符檢索返回一個ZoneId對象;如果依據得到的標識符沒有檢索出ZoneId對象,那么將返回系統默認的地區時間。(因此,你可以簡化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));} }

像類中的靜態方法,在一個接口中,你需要使用static關鍵字在方法簽名前來制定它為靜態方法。在一個接口中所有的方法聲明,包括靜態方法,隱式地聲明為public,因此你能省略public標識符。

集成default方法到現有的庫中

default方法能夠使你向已經存在的接口中添加新的功能,并確保它們和這些接口舊版本現有的代碼二進制兼容。特別的,default方法使您能夠添加將lambda表達式作為參數的方法添加到現有接口中。本節演示如何使用默認和靜態方法增強Comparator接口。

考慮在Classes的問題和練習中描述的Card和Deck類。這個例子重寫Card和Deck類為接口。Card接口包含了兩個枚舉類型(Suit和Rank)和兩個抽象方法(getSuit和getRank):

package defaultmethods;public interface Card extends Comparable<Card> {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接口包含了各種各樣操作Card的方法:

package defaultmethods; import java.util.*; import java.util.stream.*; import java.lang.*;public interface Deck {List<Card> getCards();Deck deckFactory();int size();void addCard(Card card);void addCards(List<Card> cards);void addDeck(Deck deck);void shuffle();void sort();void sort(Comparator<Card> c);String deckToString();Map<Integer, Deck> deal(int players, int numberOfCards)throws IllegalArgumentException;}

PlayingCard 類實現了Card接口,StandardDeck 類實現了Deck接口。

StandardDeck 類實現了抽象方法Deck.sort,如下:

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

Collections.sort方法是一個List實例的排序,它的元素類型實現了Comparable接口。entireDeck成員是一個List實例,它的元素類型是Card,其繼承了Comparable接口。PlayingCard類實現了Comparable.compartTo方法,如下:

public int hashCode() {return ((suit.value()-1)*13)+rank.value(); }public int compareTo(Card o) {return this.hashCode() - o.hashCode(); }

compareTo方法使得StandardDeck.sort()中cards元素先按照suit排序,再按照rank排序。

如果你想要deck的排序先按照rank排序,再按照suit排序怎么辦?你需要實現Comparator接口來指定新的排序規則,并且使用sort(List list, Comparator

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

使用這種方法,你可以指定Collections.sort方法中Card類實例的排序。一種方式是實現Comparator接口來指定你想要的cards排序。下面的例子SortByRankThenSuit 就是這樣做的。

package defaultmethods;import java.util.*; import java.util.stream.*; import java.lang.*;public class SortByRankThenSuit implements Comparator<Card> {public int compare(Card firstCard, Card secondCard) {int compVal =firstCard.getRank().value() - secondCard.getRank().value();if (compVal != 0)return compVal;elsereturn firstCard.getSuit().value() - secondCard.getSuit().value(); } }

下面先按照rank排序,再按照suit排序的方式調用deck的sort方法:

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

然而,這種方式太繁瑣了。如果你能指定想要的排序,而不是排序的方式,那就更好了。假設你是編寫Comparator接口的開發人員,向Comparator接口添加怎樣的default方法或靜態方法,才能使其他開發人員更容易地指定排序規則呢?

首先,假設你對于deck的排序想以rank比較來排序,與suit無關。你可以像下面的這種方式來調用StandardDeck.sort方法:

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

因為Comparator 接口是一個函數式接口,因此你可以使用lambda表達式來作為sort函數的參數。在這個例子中,lambda表達式比較了兩個整數值。

如果開發著能夠僅僅通過Card.getRank方法來創建一個Comparator實例,那對于他們來說將會是簡單的。特別的,如果開發者能夠通過一個方法得到一個數值,例如getValue 或者hashCode方法,從而能夠創建一個Comparator實例來比較任何對象,那將是有用的。Comparator接口已經通過使用靜態方法比較增強了這個能力:

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

在這個例子中,你可以使用方法引用來代替:

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

這個方法更好的演示了要什么排序,而不是怎樣排序。

Comparator接口也增加了其他版本的比較方法,例如: comparingDouble 和comparingLong,這樣能夠通過比較其他數據類型來創建Comparator實例。

假設開發者想要超過一種規則比較對象來創建Comparator實例。例如deck的排序先比較rank,然后再比較suit,怎么辦?像前面那樣,你可以通過Lambda表達式來指定排序規則:

StandardDeck myDeck = new StandardDeck(); myDeck.shuffle(); myDeck.sort((firstCard, secondCard) -> {int compare =firstCard.getRank().value() - secondCard.getRank().value();if (compare != 0)return compare;elsereturn firstCard.getSuit().value() - secondCard.getSuit().value();} );

如果能夠通過一系列的Comparator實例構建一個Comparator實例,那將會對開發者來說更簡單。Comparator接口已經通過default方法thenComparing增強了這個能力:

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

Comparator接口已經增加了其他版本的thenComparing(例如 thenComparingDouble 和 thenComparingLong) default方法,使你能夠通過比較其他數據類型來創建Comparator實例。

假設開發者希望創建一個Comparator實例,使它們能夠以相反的順序對對象集合進行排序。例如,你想要對deck中的cards按rank的降序排序,從Ace 到 Two(而不是從Two to Ace)?像之前一樣,你可以指定另一個Lambda表達式。然而,如果開發者能夠通過調用一個方法從而反轉已經存在的Comparator,那將會更簡單。Comparator接口已經通過default方法reversed實現了該功能:

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

這個例子展示了Comparator接口如何通過default方法、靜態方法、Lambda表達式和方法引用來創建一個更具表現力的庫函數,開發者們能夠很快的通過調用方式來推斷出它們的功能。使用這些設計來增強庫中的接口。

總結

以上是生活随笔為你收集整理的Java default 方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。