Java 8 interface default方法

我们都知道在Java8以前,接口中只能定义方法名,而不能包含方法的具体实现代码。接口中定义的方法必须在接口的非抽象子类中实现。下面就是关于接口的一个例子:

interface InterfaceA{
    void doFirstWork();
}

class InterfaceImpl implements InterfaceA{
    @Override
    public void doFirstWork() {
        System.out.println("doFirstWork");
    }
}

public class Test {
    public static void main(String[] args) {
        InterfaceImpl obj = new InterfaceImpl();
        obj.doFirstWork();
    }
}
输出:
doFirstWork
如果我们接口已经在给外部程序使用了,这个时候我想要在接口中新增加一个方法,会怎么样哪?

interface InterfaceA{
    void doFirstWork();
    void doSecondWork();
}

class InterfaceImpl implements InterfaceA{
    @Override
    public void doFirstWork() {
        System.out.println("doFirstWork");
    }
}

public class Test {
    public static void main(String[] args) {
        InterfaceImpl obj = new InterfaceImpl();
        obj.doFirstWork();
    }
}
编译失败,输出内容是:
Error:(8, 1) java: InterfaceImpl不是抽象的, 并且未覆盖InterfaceA中的抽象方法doSecondWork()
因为接口有这个语法限制,所以要直接改变/扩展接口内的方法变得非常困难。特别是在尝试强化Java 8 Collections API,让其支持lambda表达式的时候,就面临了这样的挑战。为了克服这个困难,Java 8中引入了一个新的概念,叫做default方法,也可以称为Defender方法,或者虚拟扩展方法(Virtual extension methods)。Default方法是指,在接口内部包含了一些默认的方法实现(也就是接口中可以包含方法体,这打破了Java之前版本对接口的语法限制),从而使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码。接下来,让我们看一个例子:

interface InterfaceA{
    void doFirstWork();
    default void doSecondWork(){
        System.out.println("doSecondWork");
    }
}

class InterfaceImpl implements InterfaceA{
    @Override
    public void doFirstWork() {
        System.out.println("doFirstWork");
    }
}

public class Test {
    public static void main(String[] args) {
        InterfaceImpl obj = new InterfaceImpl();
        obj.doFirstWork();
        obj.doSecondWork();
    }
}
输出:
doFirstWork
doSecondWork
因此,default方法使我们不会破坏与接口相关的实现类代码,在接口中也可以写方法实现了。实现的方法会作为默认的方法实现。
一个问题是:如果一个类实现了两个接口(可以看做是“多继承”),这两个接口又同时都包含了一个名字相同的default方法,那么会发生什么情况? 在这样的情况下,编译器会报错。让我用例子来解释一下:

interface InterfaceA{
    default void doFirstWork(){
        System.out.println("InterfaceA doFirstWork");
    }
}

interface InterfaceB{
    default void doFirstWork(){
        System.out.println("InterfaceB doFirstWork");
    }
}

class InterfaceImpl implements InterfaceA,InterfaceB{
}

public class Test {
    public static void main(String[] args) {
        InterfaceImpl obj = new InterfaceImpl();
        obj.doFirstWork();
    }
}
编译错误输出:
Error:(15, 1) java: 类 InterfaceImpl从类型 InterfaceA 和 InterfaceB 中继承了doFirstWork() 的不相关默认值

因为编译器不知道应该在两个同名的default方法中选择哪一个,因此产生了二义性。我们通过在InterfaceImpl重写doFirstWork方法可以解决编译问题,而且还可以指定调用哪一个接口的方法,代码如下:

nterface InterfaceA{
    default void doFirstWork(){
        System.out.println("InterfaceA doFirstWork");
    }
}

interface InterfaceB{
    default void doFirstWork(){
        System.out.println("InterfaceB doFirstWork");
    }
}

class InterfaceImpl implements InterfaceA,InterfaceB{
    @Override
    public void doFirstWork() {
        InterfaceB.super.doFirstWork();
    }
}

public class Test {
    public static void main(String[] args) {
        InterfaceImpl obj = new InterfaceImpl();
        obj.doFirstWork();
    }
}
输出如下:
InterfaceB doFirstWork





  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
lambdas Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Why Did They Need to Change Java Again? 1 What Is Functional Programming? 2 Example Domain 3 2. Lambda Expressions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Your First Lambda Expression 5 How to Spot a Lambda in a Haystack 6 Using Values 8 Functional Interfaces 9 Type Inference 11 Key Points 13 Exercises 14 3. Streams. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 From External Iteration to Internal Iteration 17 What’s Actually Going On 20 Common Stream Operations 21 collect(toList()) 22 map 22 filter 24 flatMap 25 max and min 26 A Common Pattern Appears 27 reduce 28 Putting Operations Together 30 Refactoring Legacy Code 31 iii Multiple Stream Calls 34 Higher-Order Functions 36 Good Use of Lambda Expressions 36 Key Points 37 Exercises 37 Advanced Exercises 39 4. Libraries. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Using Lambda Expressions in Code 41 Primitives 42 Overload Resolution 45 @FunctionalInterface 47 Binary Interface Compatibility 47 Default Methods 48 Default Methods and Subclassing 49 Multiple Inheritance 52 The Three Rules 53 Tradeoffs 54 Static Methods on Interfaces 54 Optional 55 Key Points 56 Exercises 57 Open Exercises 58 5. Advanced Collections and Collectors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Method References 59 Element Ordering 60 Enter the Collector 62 Into Other Collections 62 To Values 63 Partitioning the Data 64 Grouping the Data 65 Strings 66 Composing Collectors 67 Refactoring and Custom Collectors 69 Reduction as a Collector 76 Collection Niceties 77 Key Points 78 Exercises 78 6. Data Parallelism. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Parallelism Versus Concurrency 81 iv | Table of Contents Why Is Parallelism Important? 83 Parallel Stream Operations 83 Simulations 85 Caveats 88 Performance 89 Parallel Array Operations 92 Key Points 94 Exercises 94 7. Testing, Debugging, and Refactoring. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Lambda Refactoring Candidates 97 In, Out, In, Out, Shake It All About 98 The Lonely Override 98 Behavioral Write Everything Twice 99 Unit Testing Lambda Expressions 102 Using Lambda Expressions in Test Doubles 105 Lazy Evaluation Versus Debugging 106 Logging and Printing 106 The Solution: peek 107 Midstream Breakpoints 107 Key Points 108 8. Design and Architectural Principles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Lambda-Enabled Design Patterns 110 Command Pattern 110 Strategy Pattern 114 Observer Pattern 117 Template Method Pattern 119 Lambda-Enabled Domain-Specific Languages 123 A DSL in Java 124 How We Got There 125 Evaluation 127 Lambda-Enabled SOLID Principles 127 The Single Responsibility Principle 128 The Open/Closed Principle 130 The Dependency Inversion Principle 134 Further Reading 137 Key Points 137 9. Lambda-Enabled Concurrency. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 Why Use Nonblocking I/O? 139 Callbacks 140 Table of Contents | v Message Passing Architectures 144 The Pyramid of Doom 145 Futures 147 Completable Futures 149 Reactive Programming 152 When and Where 155 Key Points 155 Exercises 156 10. Moving Forward 159

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值