java8 default methods 默认方法的概念与代码解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

一、基本概念  

      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.
      默认方法使您能够添加新的功能到你现有库的接口中,并确保与采用老版本接口编写的代码的二进制兼容性。

    什么是默认方法(default methods)
    即接口可以有实现方法,而且不需要实现类去实现其方法。只需在方法名前面加个default关键字即可,这些方法默认是

    为什么要有默认方法
    为什么要有这个特性?首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题

二、 java 8抽象类与接口的区别
    相同点:
    1.都是抽象类型;
    2.都可以有实现方法(java8才可以)
    3.都可以不需要实现类或者继承者去实现所有方法

    不同点
    1.抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承);
    2.抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系;
    3.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。

三、多重继承的冲突说明
    由于同一个方法可以从不同接口引入,自然而然的会有冲突的现象,默认方法判断冲突的规则如下:
    1.一个声明在类里面的方法优先于任何默认方法(classes always win)
    2.否则,则会优先选取最具体的实现,比如下面的例子 B重写了A的hello方法。

四、如何扩展或实现带有默认方法的接口?

     当前扩展一个默认方法的接口时,你可以采用以下三种方式:

     1:让扩展类继承默认方法,根据不管是否存在默认方法

     2:重新声明默认方法,使其变为一个抽象方法(注意,扩展类的实现类必须实现此方法)

     3:重新定义默认方法,覆盖(override)父类的默认方法

五、默认方法样例代码

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();
		// 显示当前日期时间
		System.out.println(client.toString());
		// 设置日期
		client.setTime(11, 12, 22);
		System.out.println(client);
		// 设置时间
		client.setDate(2012, 11, 12);
		System.out.println(client);

		System.out.println("Time in Asia/Shanghai: "
				+ client.getZonedDateTime("Asia/Shanghai").toString());
	}
}

六、整合默认方法、静态方法到已经存在的接口

    默认方法使您能够添加新的功能到已经存在的接口,确保与采用老版本这些接口编写的代码的二进制兼容性。特别是,默认的方法使您能够在已经存在的接口中添加使用lambda表达式作为参数的方法。下面的样例代码说明通过默认方法和静态方法,Comparator 接口是如何提供丰富的功能的。

  在java8中,Compartor接口提供了丰富的功能,提供了差不多近20个默认或静态方法,在以前的版本中仅仅提供了compare(T o1, T o2)一个比较接口方法

    下面的代码是有关扑克牌游戏中的洗牌,针对牌排序,打散,发牌的部分源代码

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;

//先根据rank,再根据suit进行比较
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;

//扑克牌实现类
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();
	}

	//实现比较接口
	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;

//牌桌实现类
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;

		//根据玩家的个数,每个玩家分到的扑克牌数进行分牌
		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("-------------------------------");
		}
	}
}
目录
相关文章
|
7天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
20 5
|
9天前
|
Java API 开发者
探索Java中的Lambda表达式:简洁与强大的代码实践
本文深入探讨Java中Lambda表达式的定义、用法及优势,通过实例展示其如何简化代码、提升可读性,并强调在使用中需注意的兼容性和效率问题。Lambda作为Java 8的亮点功能,不仅优化了集合操作,还促进了函数式编程范式的应用,为开发者提供了更灵活的编码方式。
|
5天前
|
Java 开发者
探索Java中的Lambda表达式:简化你的代码之旅##
【8月更文挑战第62天】 Java 8的发布为开发者带来了诸多新特性,其中最引人注目的无疑是Lambda表达式。这一特性不仅让代码变得更加简洁,还极大地提升了开发的效率。本文将通过实际示例,展示如何利用Lambda表达式来优化我们的代码结构,同时探讨其背后的工作原理和性能考量。 ##
|
8天前
|
Java API 开发者
探索Java中的Lambda表达式:简化代码,提升效率
【9月更文挑战第27天】在Java 8中引入的Lambda表达式为编程带来了革命性的变化。通过简洁的语法和强大的功能,它不仅简化了代码编写过程,还显著提升了程序的执行效率。本文将深入探讨Lambda表达式的本质、用法和优势,并结合实例演示其在实际开发中的应用。无论你是Java新手还是资深开发者,都能从中获得启发,优化你的代码设计。
|
12天前
|
网络协议 安全 Linux
网卡接口跃点数:概念与重要性解析
在计算机网络中,跃点数(Hop Count)是指数据包从源设备传输到目标设备时经过的路由器或网关数量,是衡量路径长度的关键指标。本文详细介绍了跃点数的概念、计算方法及其在网络管理中的重要性,包括性能评估、故障排除、网络优化及路由选择等方面的应用。通过使用traceroute或tracert命令,网络管理员可以轻松获取跃点数信息,并据此优化网络结构,提高数据传输效率和安全性。尽管跃点数是重要指标,但仍需与其他因素结合分析以全面评估网络性能。
|
9天前
|
Java Linux Python
Linux环境下 代码java调用python出错
Linux环境下 代码java调用python出错
24 3
|
6天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
19 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
8天前
|
存储 Java 索引
使用java代码实现左右括号查找
使用java代码实现左右括号查找
|
9天前
|
监控 算法 Java
深入解析Java中的垃圾回收机制
本文旨在全面解析Java的垃圾回收机制,探讨其工作原理、常见算法以及在实际开发中的应用。通过对这一重要主题的深入分析,希望帮助读者更好地理解Java虚拟机(JVM)如何管理内存,从而编写出更高效、稳定的Java应用程序。
|
9天前
|
Java 开发者
Java中的异常处理机制深度解析
在Java编程中,异常处理是保证程序稳定性和健壮性的重要手段。本文将深入探讨Java的异常处理机制,包括异常的分类、捕获与处理、自定义异常以及一些最佳实践。通过详细讲解和代码示例,帮助读者更好地理解和应用这一机制,提升代码质量。
12 1

推荐镜像

更多
下一篇
无影云桌面