您好,登錄后才能下訂單哦!
這篇文章給大家介紹在Java8 default methods中默認(rèn)方法的概念與代碼是怎樣的,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
一、基本概念
Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces.
默認(rèn)方法使您能夠添加新的功能到你現(xiàn)有庫的接口中,并確保與采用老版本接口編寫的代碼的二進(jìn)制兼容性。
什么是默認(rèn)方法(default methods)
即接口可以有實(shí)現(xiàn)方法,而且不需要實(shí)現(xiàn)類去實(shí)現(xiàn)其方法。只需在方法名前面加個(gè)default關(guān)鍵字即可,這些方法默認(rèn)是
為什么要有默認(rèn)方法
為什么要有這個(gè)特性?首先,之前的接口是個(gè)雙刃劍,好處是面向抽象而不是面向具體編程,缺陷是,當(dāng)需要修改接口時(shí)候,需要修改全部實(shí)現(xiàn)該接口的類,目前的java 8之前的集合框架沒有foreach方法,通常能想到的解決辦法是在JDK里給相關(guān)的接口添加新的方法及實(shí)現(xiàn)。然而,對(duì)于已經(jīng)發(fā)布的版本,是沒法在給接口添加新方法的同時(shí)不影響已有的實(shí)現(xiàn)。所以引進(jìn)的默認(rèn)方法。他們的目的是為了解決接口的修改與現(xiàn)有的實(shí)現(xiàn)不兼容的問題
二、 java 8抽象類與接口的區(qū)別
相同點(diǎn):
1.都是抽象類型;
2.都可以有實(shí)現(xiàn)方法(java8才可以)
3.都可以不需要實(shí)現(xiàn)類或者繼承者去實(shí)現(xiàn)所有方法
不同點(diǎn)
1.抽象類不可以多重繼承,接口可以(無論是多重類型繼承還是多重行為繼承);
2.抽象類和接口所反映出的設(shè)計(jì)理念不同。其實(shí)抽象類表示的是"is-a"關(guān)系,接口表示的是"like-a"關(guān)系;
3.接口中定義的變量默認(rèn)是public static final 型,且必須給其初值,所以實(shí)現(xiàn)類中不能重新定義,也不能改變其值;抽象類中的變量默認(rèn)是 friendly 型,其值可以在子類中重新定義,也可以重新賦值。
三、多重繼承的沖突說明
由于同一個(gè)方法可以從不同接口引入,自然而然的會(huì)有沖突的現(xiàn)象,默認(rèn)方法判斷沖突的規(guī)則如下:
1.一個(gè)聲明在類里面的方法優(yōu)先于任何默認(rèn)方法(classes always win)
2.否則,則會(huì)優(yōu)先選取***體的實(shí)現(xiàn),比如下面的例子 B重寫了A的hello方法。
四、如何擴(kuò)展或?qū)崿F(xiàn)帶有默認(rèn)方法的接口?
當(dāng)前擴(kuò)展一個(gè)默認(rèn)方法的接口時(shí),你可以采用以下三種方式:
1:讓擴(kuò)展類繼承默認(rèn)方法,根據(jù)不管是否存在默認(rèn)方法
2:重新聲明默認(rèn)方法,使其變?yōu)橐粋€(gè)抽象方法(注意,擴(kuò)展類的實(shí)現(xiàn)類必須實(shí)現(xiàn)此方法)
3:重新定義默認(rèn)方法,覆蓋(override)父類的默認(rèn)方法
五、默認(rèn)方法樣例代碼
import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; 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)); } }
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; 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 year, int month, int day) { LocalDate dateToSet = LocalDate.of(year, month, day); LocalTime currentTime = LocalTime.from(dateAndTime); dateAndTime = LocalDateTime.of(dateToSet, currentTime); } public void setDateAndTime(int year, int month, int day, int hour, int minute, int second) { LocalDate dateToSet = LocalDate.of(year, month, day); 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 client = new SimpleTimeClient(); // 顯示當(dāng)前日期時(shí)間 System.out.println(client.toString()); // 設(shè)置日期 client.setTime(11, 12, 22); System.out.println(client); // 設(shè)置時(shí)間 client.setDate(2012, 11, 12); System.out.println(client); System.out.println("Time in Asia/Shanghai: " + client.getZonedDateTime("Asia/Shanghai").toString()); } }
六、整合默認(rèn)方法、靜態(tài)方法到已經(jīng)存在的接口
默認(rèn)方法使您能夠添加新的功能到已經(jīng)存在的接口,確保與采用老版本這些接口編寫的代碼的二進(jìn)制兼容性。特別是,默認(rèn)的方法使您能夠在已經(jīng)存在的接口中添加使用lambda表達(dá)式作為參數(shù)的方法。下面的樣例代碼說明通過默認(rèn)方法和靜態(tài)方法,Comparator 接口是如何提供豐富的功能的。
在java8中,Compartor接口提供了豐富的功能,提供了差不多近20個(gè)默認(rèn)或靜態(tài)方法,在以前的版本中僅僅提供了compare(T o1, T o2)一個(gè)比較接口方法
下面的代碼是有關(guān)撲克牌游戲中的洗牌,針對(duì)牌排序,打散,發(fā)牌的部分源代碼
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(); }
package defaultmethods; import java.util.Comparator; import java.util.List; import java.util.Map; //牌桌接口類 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; }
package defaultmethods; import java.util.Comparator; //先根據(jù)rank,再根據(jù)suit進(jìn)行比較 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; else return firstCard.getSuit().value() - secondCard.getSuit().value(); } }
package defaultmethods; //撲克牌實(shí)現(xiàn)類 public class PlayingCard implements Card { private Card.Rank rank; private Card.Suit suit; public PlayingCard(Card.Rank rank, Card.Suit suit) { this.rank = rank; this.suit = suit; } public Card.Suit getSuit() { return suit; } public Card.Rank getRank() { return rank; } public boolean equals(Object obj) { if (obj instanceof Card) { if (((Card) obj).getRank() == this.rank && ((Card) obj).getSuit() == this.suit) { return true; } else { return false; } } else { return false; } } public int hashCode() { return ((suit.value() - 1) * 13) + rank.value(); } //實(shí)現(xiàn)比較接口 public int compareTo(Card o) { return this.hashCode() - o.hashCode(); } //重載toString public String toString() { return this.rank.text() + " of " + this.suit.text(); } public static void main(String... args) { new PlayingCard(Rank.ACE, Suit.DIAMONDS); new PlayingCard(Rank.KING, Suit.SPADES); } }
package defaultmethods; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; //牌桌實(shí)現(xiàn)類 public class StandardDeck implements Deck { //撲克牌列表 private List<Card> entireDeck; public StandardDeck(List<Card> existingList) { this.entireDeck = existingList; } public StandardDeck() { this.entireDeck = new ArrayList<>(); for (Card.Suit s : Card.Suit.values()) { for (Card.Rank r : Card.Rank.values()) { this.entireDeck.add(new PlayingCard(r, s)); } } } public Deck deckFactory() { return new StandardDeck(new ArrayList<Card>()); } public int size() { return entireDeck.size(); } public List<Card> getCards() { return entireDeck; } public void addCard(Card card) { entireDeck.add(card); } public void addCards(List<Card> cards) { entireDeck.addAll(cards); } public void addDeck(Deck deck) { List<Card> listToAdd = deck.getCards(); entireDeck.addAll(listToAdd); } public void sort() { Collections.sort(entireDeck); } public void sort(Comparator<Card> c) { Collections.sort(entireDeck, c); } public void shuffle() { Collections.shuffle(entireDeck); } //為每位玩家分牌 public Map<Integer, Deck> deal(int players, int numberOfCards) throws IllegalArgumentException { int cardsDealt = players * numberOfCards; int sizeOfDeck = entireDeck.size(); if (cardsDealt > sizeOfDeck) { throw new IllegalArgumentException("Number of players (" + players + ") times number of cards to be dealt (" + numberOfCards + ") is greater than the number of cards in the deck (" + sizeOfDeck + ")."); } //把牌分成幾份 int slices=players+1; if(cardsDealt == sizeOfDeck) slices=players; //根據(jù)玩家的個(gè)數(shù),每個(gè)玩家分到的撲克牌數(shù)進(jìn)行分牌 Map<Integer, List<Card>> dealtDeck = entireDeck.stream().collect( Collectors.groupingBy(card -> { int cardIndex = entireDeck.indexOf(card); if (cardIndex >= cardsDealt) return (players + 1); else return (cardIndex % players) + 1; })); System.out.println(dealtDeck); // Convert Map<Integer, List<Card>> to Map<Integer, Deck> Map<Integer, Deck> mapToReturn = new HashMap<>(); for (int i = 1; i < (slices + 1); i++) { Deck currentDeck = deckFactory(); currentDeck.addCards(dealtDeck.get(i)); mapToReturn.put(i, currentDeck); } return mapToReturn; } public String deckToString() { return this.entireDeck.stream().map(Card::toString) .collect(Collectors.joining("\n")); } public String toString(){ return deckToString(); } public static void main(String... args) { System.out.println("Creating deck:"); StandardDeck myDeck = new StandardDeck(); myDeck.sort(); System.out.println("Sorted deck"); System.out.println(myDeck.deckToString()); myDeck.shuffle(); myDeck.sort(new SortByRankThenSuit()); System.out.println("Sorted by rank, then by suit"); System.out.println(myDeck.deckToString()); myDeck.shuffle(); myDeck.sort(Comparator.comparing(Card::getRank).thenComparing( Comparator.comparing(Card::getSuit))); System.out.println("Sorted by rank, then by suit " + "with static and default methods"); System.out.println(myDeck.deckToString()); myDeck.sort(Comparator.comparing(Card::getRank).reversed() .thenComparing(Comparator.comparing(Card::getSuit).reversed())); System.out.println("Sorted by rank reversed, then by suit " + "with static and default methods"); System.out.println(myDeck.deckToString()); myDeck.shuffle(); myDeck.sort( (firstCard, secondCard) -> firstCard.getRank().value() - secondCard.getRank().value() ); System.out.println(myDeck.deckToString()); myDeck.shuffle(); myDeck.sort(Comparator.comparing(Card::getRank)); System.out.println(myDeck.deckToString()); Map<Integer, Deck> map=myDeck.deal(4, 11); for(Map.Entry<Integer, Deck> item:map.entrySet()){ System.out.println(item.getKey()); System.out.println(item.getValue()); System.out.println("-------------------------------"); } } }
關(guān)于在Java8 default methods中默認(rèn)方法的概念與代碼是怎樣的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。