原文: https://beginnersbook.com/2017/10/java-8-interface-changes-default-method-and-static-method/

在 java 8 之前,java 中的接口只能有抽象方法。接口的所有方法都是公共的和默认是抽象的。 Java 8 允许接口具有默认和静态方法。我们在接口中使用默认方法的原因是允许开发人员向接口添加新方法,而不会影响实现这些接口的类。

为什么默认方法?

例如,如果ABCD等几个类实现了接口XYZInterface,那么如果我们向XYZInterface添加新方法,我们必须更改所有代码实现此接口的类(ABCD)。在这个例子中,我们只有四个实现我们想要改变的接口的类,但想象如果有数百个类实现一个接口,那么几乎不可能改变所有这些类中的代码。这就是为什么在 java 8 中,我们有一个新概念“默认方法”。这些方法可以添加到任何现有接口,我们不需要在实现类中强制实现这些方法,因此我们可以将这些默认方法添加到现有接口而不会破坏代码。

我们可以说在 java 8 中引入了默认方法的概念,以这种方式在现有接口中添加新方法,使它们向后兼容。向后兼容性是在不破坏旧代码的情况下添加新功能。

接口中的静态方法类似于默认方法,除了我们不能在实现这些接口的类中覆盖这些方法。

Java 8 示例:接口中的默认方法

MyInterface中的方法newMethod()是一个默认方法,这意味着我们不需要在实现类Example中实现这个方法。这样我们就可以将默认方法添加到现有接口,而无需担心实现这些接口的类。

  1. interface MyInterface{
  2. /* This is a default method so we need not
  3. * to implement this method in the implementation
  4. * classes
  5. */
  6. default void newMethod(){
  7. System.out.println("Newly added default method");
  8. }
  9. /* Already existing public and abstract method
  10. * We must need to implement this method in
  11. * implementation classes.
  12. */
  13. void existingMethod(String str);
  14. }
  15. public class Example implements MyInterface{
  16. // implementing abstract method
  17. public void existingMethod(String str){
  18. System.out.println("String is: "+str);
  19. }
  20. public static void main(String[] args) {
  21. Example obj = new Example();
  22. //calling the default method of interface
  23. obj.newMethod();
  24. //calling the abstract method of interface
  25. obj.existingMethod("Java 8 is easy to learn");
  26. }
  27. }

输出:

  1. Newly added default method
  2. String is: Java 8 is easy to learn

Java 8 示例:接口中的静态方法

如上所述,接口中的静态方法与默认方法类似,因此我们不需要在实现类中实现它们。我们可以安全地将它们添加到现有接口,而无需更改实现类中的代码。由于这些方法是静态的,我们不能在实现类中覆盖它们。

  1. interface MyInterface{
  2. /* This is a default method so we need not
  3. * to implement this method in the implementation
  4. * classes
  5. */
  6. default void newMethod(){
  7. System.out.println("Newly added default method");
  8. }
  9. /* This is a static method. Static method in interface is
  10. * similar to default method except that we cannot override
  11. * them in the implementation classes.
  12. * Similar to default methods, we need to implement these methods
  13. * in implementation classes so we can safely add them to the
  14. * existing interfaces.
  15. */
  16. static void anotherNewMethod(){
  17. System.out.println("Newly added static method");
  18. }
  19. /* Already existing public and abstract method
  20. * We must need to implement this method in
  21. * implementation classes.
  22. */
  23. void existingMethod(String str);
  24. }
  25. public class Example implements MyInterface{
  26. // implementing abstract method
  27. public void existingMethod(String str){
  28. System.out.println("String is: "+str);
  29. }
  30. public static void main(String[] args) {
  31. Example obj = new Example();
  32. //calling the default method of interface
  33. obj.newMethod();
  34. //calling the static method of interface
  35. MyInterface.anotherNewMethod();
  36. //calling the abstract method of interface
  37. obj.existingMethod("Java 8 is easy to learn");
  38. }
  39. }

输出:

  1. Newly added default method
  2. Newly added static method
  3. String is: Java 8 is easy to learn

Java 8 - 抽象类与接口

通过在接口中引入默认方法,似乎抽象类与 java 8 中的接口相同。然而,这并非完全正确,即使我们现在可以使用具体方法(带有 body 的方法)接口就像抽象类一样,这并不意味着它们是相同的。它们之间仍然存在很少的差异,其中之一是抽象类可以有构造函数,而在接口中我们不能有构造函数。

接口的目的是提供完全抽象,而抽象类的目的是提供部分抽象。这仍然适用。接口就像是您类的蓝图,通过引入默认方法,您可以简单地说我们可以在接口中添加其他功能而不会影响最终用户类。

默认方法和多重继承

当我们有两个具有相同签名的默认方法的接口时,可能会发生多重继承问题。让我们举个例子。

  1. interface MyInterface{
  2. default void newMethod(){
  3. System.out.println("Newly added default method");
  4. }
  5. void existingMethod(String str);
  6. }
  7. interface MyInterface2{
  8. default void newMethod(){
  9. System.out.println("Newly added default method");
  10. }
  11. void disp(String str);
  12. }
  13. public class Example implements MyInterface, MyInterface2{
  14. // implementing abstract methods
  15. public void existingMethod(String str){
  16. System.out.println("String is: "+str);
  17. }
  18. public void disp(String str){
  19. System.out.println("String is: "+str);
  20. }
  21. public static void main(String[] args) {
  22. Example obj = new Example();
  23. //calling the default method of interface
  24. obj.newMethod();
  25. }
  26. }

输出:

  1. Error: Duplicate default methods named newMethod with the parameters () and () are inherited from the types MyInterface2 and MyInterface

这是因为我们在接口和编译器中都有相同的方法,不知道要调用哪个方法。

如何解决这个问题?为了解决这个问题,我们可以在实现类中实现这个方法,如下所示:

  1. interface MyInterface{
  2. default void newMethod(){
  3. System.out.println("Newly added default method");
  4. }
  5. void existingMethod(String str);
  6. }
  7. interface MyInterface2{
  8. default void newMethod(){
  9. System.out.println("Newly added default method");
  10. }
  11. void disp(String str);
  12. }
  13. public class Example implements MyInterface, MyInterface2{
  14. // implementing abstract methods
  15. public void existingMethod(String str){
  16. System.out.println("String is: "+str);
  17. }
  18. public void disp(String str){
  19. System.out.println("String is: "+str);
  20. }
  21. //Implementation of duplicate default method
  22. public void newMethod(){
  23. System.out.println("Implementation of default method");
  24. }
  25. public static void main(String[] args) {
  26. Example obj = new Example();
  27. //calling the default method of interface
  28. obj.newMethod();
  29. }
  30. }

输出:

  1. Implementation of default method