What is the difference between interface and abstract class in Java?

foreword

Java is a very typical object-oriented language. There was a time when programmers talked about object-oriented and design patterns all day long. Although everyone is no longer so enthusiastic about this aspect, it is undeniable that mastering object-oriented design principles and techniques is one of the foundations for ensuring high-quality code.

The focus of this blog post is, what is the difference between an interface and an abstract class?  

overview

Interfaces and abstract classes are two fundamental mechanisms of Java's object-oriented design.

Interface is the abstraction of behavior, which is a collection of abstract methods, and the purpose of separating API definition and implementation can be achieved by using interface. An interface cannot be instantiated; it cannot contain any non-constant members, and any field has an implied public static finalmeaning; at the same time, there is no non-static method implementation, that is to say, it is either an abstract method or a static method. In the Java standard class library, many interfaces are defined, such as java.util.List.

An abstract class is a class that cannot be instantiated. The purpose of modifying a class with the abstract keyword is mainly for code reuse. Except that it cannot be instantiated, it is not much different from ordinary Java classes in form. It can have one or more abstract methods, or there can be no abstract methods. Abstract classes are mostly used to extract common method implementations or common member variables of related Java classes, and then achieve the purpose of code reuse through inheritance. In the Java standard library, such as the collection framework, many common parts are extracted into abstract classes, such as java.util.AbstractList.

The Java class implements the interface using the implements keyword, and inheriting the abstract class uses the extends keyword. We can refer to the ArrayList in the Java standard library.

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    //...
}
复制代码

text

Compared with other object-oriented languages, such as C++, Java has some basic differences in design. For example, Java does not support multiple inheritance . This limitation, while standardizing the code implementation, also produces some limitations, which affect the program design structure. A Java class can implement multiple interfaces, which is declarative since an interface is a collection of abstract methods, but logic cannot be reused by extending multiple abstract classes.

In some cases, there are specific scenarios that need to abstract general logic that has nothing to do with specific implementation and instantiation, or logic of pure call relationship, but using traditional abstract classes will fall into the dilemma of single inheritance. A common practice in the past is to implement utility classes (Utils) composed of static methods, such as java.util.Collections.

Imagine that any abstract method is added to the interface, and correspondingly all classes that implement the interface must also implement the new method, otherwise a compilation error will occur. For abstract classes, if we add non-abstract methods, its subclasses will only enjoy capability expansion without worrying about compilation problems.

The responsibilities of the interface are not limited to the collection of abstract methods, in fact, there are various practices. There is a class of interfaces without any methods, usually called Marker Interface, as the name suggests, its purpose is to declare something, such as the well-known Cloneable, Serializable, etc. This usage also exists in other Java product codes in the industry.

On the surface, this seems to be the same as Annotation, and it is true. Its advantage is that it is simple and direct. For Annotation, because parameters and values ​​can be specified, it is more expressive, so more people choose to use Annotation.

Java 8 has added support for functional programming, so another class of definition has been added, the so-called functional interface. Simply put, it is an interface with only one abstract method. It is usually recommended to use @FunctionalInterface Annotation to mark it. Lambda expression itself can be regarded as a type of functional interface, which is different from object-oriented to some extent. The well-known Runnable and Callable are all functional interfaces.

Another point that may surprise people is that strictly speaking, after Java 8, interfaces can also have methods!

Starting from Java 8, interface has added support for default method. After Java 9, it is even possible to define a private default method. The Default method provides a binary-compatible way of extending an existing interface. For example, the well-known java.util.Collection, which is the root interface of the collection system, has added a series of default methods in Java 8, mainly adding functions related to Lambda and Stream. In the tool classes like Collections that I mentioned earlier in the column, many methods are suitable to be implemented as default methods in the basic interface.

You can refer to the following code snippet:

public interface Collection<E> extends Iterable<E> {
     /**
     * Returns a sequential Stream with this collection as its source 
     * ...
     **/
     default Stream<E> stream() {
         return StreamSupport.stream(spliterator(), false);
     }
  }
复制代码

object-oriented design

We must be clear about the basic elements of object-oriented: encapsulation, inheritance, and polymorphism.

The purpose of encapsulation is to hide the implementation details inside the transaction in order to improve security and simplify programming. Encapsulation provides a reasonable boundary to prevent external callers from touching internal details. In our daily development, there are too many difficult bugs caused by inadvertently exposing details, such as exposing internal states in a multi-threaded environment, resulting in concurrent modification problems. From another perspective, encapsulating this kind of hiding also provides a simplified interface, avoiding too many meaningless details to waste the energy of the caller.

Inheritance is the basic mechanism of code reuse, similar to our summary of horses, white horses, and dark horses. But it should be noted that inheritance can be regarded as a very tightly coupled relationship. When the code of the parent class is modified, the behavior of the subclass will also change. In practice, excessive abuse of inheritance can be counterproductive.

Polymorphism , you may immediately think of overriding (override), overloading (overload), and upward transformation. Simply put, rewriting is a method with the same name and parameters in the parent and child classes, but different implementations; overloading is a method with the same name, but different parameters, and the signatures of these methods are essentially different. For better explanation, please Refer to the sample code below:

public int doSomething() {
    return 0;
}
// 输入参数不同,意味着方法签名不同,重载的体现
public int doSomething(List<String> strs) {
    return 0;
}
// return类型不一样,编译不能通过
public short doSomething() {
    return 0;
}
复制代码

Here you can think about a small question. The method name and parameters are the same, but the return value is different. Is this a valid overload in Java code? The answer is no, there will be errors in compilation.

To carry out object-oriented programming, it is necessary to master the basic design principles. Here we introduce the most common part, which is the so-called SOLID principle.

  • Single Responsibility (Single Responsibility), it is best for a class or object to have only a single responsibility. If a class is found to bear multiple responsibilities in program design, splitting can be considered.
  • The switch principle (Open-Close, Open for extension, close for modification), the design should be open for extension and closed for modification. In other words, program design should ensure smooth scalability, and try to avoid modifying existing implementations for adding similar functions, so as to reduce regression problems.
  • Liskov Substitution (Liskov Substitution), which is one of the basic elements of object-oriented, when abstracting the inheritance relationship, wherever the parent class or base class can be used, it can be replaced by a subclass.
  • Interface separation (Interface Segregation), when we design classes and interfaces, if too many methods are defined in an interface, its subclasses may face a dilemma, that is, only some methods are meaningful to it, which destroys program cohesion. In this case, the behavior can be decoupled by splitting it into multiple interfaces with a single function. In future maintenance, if an interface design changes, it will not affect subclasses using other interfaces.
  • Dependency Inversion (Dependency Inversion), the entity should depend on the abstraction rather than the implementation. That is to say, high-level modules should not depend on low-level modules, but should be based on abstraction. Practicing this principle is the magic weapon to ensure proper coupling between production code.  

Trade-offs in the practice of OOP principles

It is worth noting that the development of modern languages ​​often does not fully comply with the previous principles. For example, Java 10 introduces local method type inference and var types. According to the Liskov substitution principle, we usually define variables like this:

List<String> list = new ArrayList<>();
复制代码

If you use the var type, it can be simplified to

var list = new ArrayList<String>();
复制代码

However, list is actually inferred asArrayList<String>

ArrayList<String> list = new ArrayList<String>();
复制代码

In theory, this grammatical convenience actually enhances the program's dependence on implementation, but the tiny type leaks bring convenience in writing and improved code readability. Therefore, in practice, we still have to follow the pros and cons Make choices, not stick to principles.  

postscript

The above is  [JAVA] What is the difference between an interface and an abstract class?  all the contents of the ;

It sorts out Java object-oriented technology, compares abstract classes and interfaces, analyzes the evolution of Java language at the interface level and the corresponding programming implementation, and finally reviews and practices the basic principles of object-oriented design. I hope it will be helpful to you.

Guess you like

Origin blog.csdn.net/ww2651071028/article/details/130525040