1. Introduction
1.绪论
After the introduction of default methods in Java interfaces, it seemed that there was no longer any difference between an interface and an abstract class. But, that’s not the case — there are some fundamental differences between them.
在Java接口中引入default方法后,接口和抽象类之间似乎不再有任何区别。但是,事实并非如此–它们之间存在一些根本性的区别。
In this tutorial, we’ll take a closer look at both the interface and abstract class to see how they differ.
在本教程中,我们将仔细研究接口和抽象类,看看它们有何不同。
2. Why Use a Default Method?
2.为什么使用默认方法?
The purpose of the default method is to provide external functionality without breaking the existing implementations. The original motivation behind introducing the default method was to provide backward compatibility to the Collection Framework with the new lambda functions.
default方法的目的是提供外部功能而不破坏现有实现。引入default方法的最初动机是为集合框架提供向后兼容的新lambda函数。
3. Interface With default Method vs Abstract Class
3.带有默认方法的接口与抽象类对比
Let’s take a look at the main fundamental differences.
让我们来看看主要的基本差异。
3.1. State
3.1.国家
The abstract class can have a state, and its methods can access the implementation’s state. Although default methods are allowed in an interface, they can’t access the implementation’s state.
抽象类可以有一个状态,其方法可以访问实现的状态。虽然default方法在接口中是允许的,但它们不能访问实现的状态。
Any logic we write in the default method should be with respect to other methods of the interface — those methods will be independent of the object’s state.
我们在default方法中编写的任何逻辑应该是关于接口的其他方法的–这些方法将独立于对象的状态。
Let’s say that we’ve created an abstract class, CircleClass, which contains a String, color, to represent the state of the CircleClass object:
假设我们创建了一个抽象类,CircleClass,它包含一个String,color,用来表示CircleClass对象的状态。
public abstract class CircleClass {
private String color;
private List<String> allowedColors = Arrays.asList("RED", "GREEN", "BLUE");
public boolean isValid() {
if (allowedColors.contains(getColor())) {
return true;
} else {
return false;
}
}
//standard getters and setters
}
In the above abstract class, we have a non-abstract method called isValid() to validate a CircleClass object based on its state. The isValid() method can access the state of a CircleClass object and validate the instance of CircleClass based on the allowed colors. Due to this behavior, we can write any logic in the abstract class method based on the object’s state.
在上面的抽象类中,我们有一个名为isValid()的非抽象方法,用来根据CircleClass对象的状态进行验证。isValid()方法可以访问CircleClass对象的状态并根据允许的颜色验证CircleClass的实例。由于这种行为,我们可以根据对象的状态在抽象类方法中编写任何逻辑。
Let’s create a simple implementation class of CircleClass:
让我们创建一个简单的CircleClass的实现类:。
public class ChildCircleClass extends CircleClass {
}
Now, let’s create an instance and validate the color:
现在,让我们创建一个实例并验证颜色。
CircleClass redCircle = new ChildCircleClass();
redCircle.setColor("RED");
assertTrue(redCircle.isValid());
Here, we can see that when we put a valid color in the CircleClass object and call the isValid() method, internally, the isValid() method can access the state of the CircleClass object and check if the instance contains a valid color or not.
在这里,我们可以看到,当我们在CircleClass对象中放入一个有效的颜色并调用isValid()方法时,在内部,isValid()方法可以访问CircleClass对象的状态并检查该实例是否包含有效颜色。
Let’s try to do something similar using an interface with a default method:
让我们试着用一个带有default方法的接口来做类似的事情。
public interface CircleInterface {
List<String> allowedColors = Arrays.asList("RED", "GREEN", "BLUE");
String getColor();
public default boolean isValid() {
if (allowedColors.contains(getColor())) {
return true;
} else {
return false;
}
}
}
As we know, an interface can’t have a state, and therefore, the default method can’t access the state.
我们知道,一个接口不能有状态,因此,default方法也不能访问状态。
Here, we’ve defined the getColor() method to provide the state information. The child class will override the getColor() method to provide the state of the instance at runtime:
这里,我们定义了getColor()方法来提供状态信息。子类将覆盖getColor()方法以在运行时提供实例的状态。
public class ChidlCircleInterfaceImpl implements CircleInterface {
private String color;
@Override
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Let’s create an instance and validate the color:
让我们创建一个实例并验证其颜色。
ChidlCircleInterfaceImpl redCircleWithoutState = new ChidlCircleInterfaceImpl();
redCircleWithoutState.setColor("RED");
assertTrue(redCircleWithoutState.isValid());
As we can see here, we’re overriding the getColor() method in the child class so that the default method validates the state at runtime.
正如我们在这里看到的,我们在子类中覆盖了getColor()方法,以便default方法在运行时验证该状态。
3.2. Constructors
3.2.构建器
Abstract classes can have constructors, allowing us to initialize the state upon creation. Interfaces, of course, do not have constructors.
抽象类可以有构造函数,允许我们在创建时初始化状态。当然,接口是没有构造函数的。
3.3. Syntactical Differences
3.3.句法上的差异
Additionally, there are few differences regarding syntax. An abstract class can override Object class methods, but an interface can’t.
此外,在语法方面也有一些区别。一个抽象类可以覆盖Object类的方法,但一个接口不能。
An abstract class can declare instance variables, with all possible access modifiers, and they can be accessed in child classes. An interface can only have public, static, and final variables and can’t have any instance variables.
一个抽象类可以声明实例变量,并带有所有可能的访问修饰符,而且它们可以在子类中被访问。一个接口只能有public、static和final变量,不能有任何实例变量。
Additionally, an abstract class can declare instances and static blocks, whereas an interface can’t have either of these.
此外,抽象类可以声明实例和静态块,而接口则不能有这两者。
Finally, an abstract class can’t refer to a lambda expression, while the interface can have a single abstract method that can refer to a lambda expression.
最后,抽象类不能引用lambda表达式,而接口可以有一个可以引用lambda表达式的单一抽象方法。
4. Conclusion
4.总结
This article shows the difference between an abstract class and an interface with a default method. We’ve also seen which one is best suited based on our scenario.
这篇文章展示了抽象类和带有default方法的接口之间的区别。我们也看到了根据我们的方案,哪一个是最适合的。
Whenever possible, we should always choose an interface with the default method because it allows us to extend a class and also implement an interface.
只要有可能,我们应该总是选择带有默认方法的接口,因为它允许我们扩展一个类并同时实现一个接口。
As usual, all the code samples shown in this article are available over on GitHub.
像往常一样,本文中显示的所有代码样本都可以在GitHub上找到。