What is the difference between an interface and abstract class?

前端 未结 30 1811
情歌与酒
情歌与酒 2020-11-21 11:51

What exactly is the difference between an interface and abstract class?

相关标签:
30条回答
  • 2020-11-21 12:04

    Many junior developers make the mistake of thinking of interfaces, abstract and concrete classes as slight variations of the same thing, and choose one of them purely on technical grounds: Do I need multiple inheritance? Do I need some place to put common methods? Do I need to bother with something other than just a concrete class? This is wrong, and hidden in these questions is the main problem: "I". When you write code for yourself, by yourself, you rarely think of other present or future developers working on or with your code.

    Interfaces and abstract classes, although apparently similar from a technical point of view, have completely different meanings and purposes.

    Summary

    1. An interface defines a contract that some implementation will fulfill for you.

    2. An abstract class provides a default behavior that your implementation can reuse.

    Alternative summary

    1. An interface is for defining public APIs
    2. An abstract class is for internal use, and for defining SPIs

    On the importance of hiding implementation details

    A concrete class does the actual work, in a very specific way. For example, an ArrayList uses a contiguous area of memory to store a list of objects in a compact manner which offers fast random access, iteration, and in-place changes, but is terrible at insertions, deletions, and occasionally even additions; meanwhile, a LinkedList uses double-linked nodes to store a list of objects, which instead offers fast iteration, in-place changes, and insertion/deletion/addition, but is terrible at random access. These two types of lists are optimized for different use cases, and it matters a lot how you're going to use them. When you're trying to squeeze performance out of a list that you're heavily interacting with, and when picking the type of list is up to you, you should carefully pick which one you're instantiating.

    On the other hand, high level users of a list don't really care how it is actually implemented, and they should be insulated from these details. Let's imagine that Java didn't expose the List interface, but only had a concrete List class that's actually what LinkedList is right now. All Java developers would have tailored their code to fit the implementation details: avoid random access, add a cache to speed up access, or just reimplement ArrayList on their own, although it would be incompatible with all the other code that actually works with List only. That would be terrible... But now imagine that the Java masters actually realize that a linked list is terrible for most actual use cases, and decided to switch over to an array list for their only List class available. This would affect the performance of every Java program in the world, and people wouldn't be happy about it. And the main culprit is that implementation details were available, and the developers assumed that those details are a permanent contract that they can rely on. This is why it's important to hide implementation details, and only define an abstract contract. This is the purpose of an interface: define what kind of input a method accepts, and what kind of output is expected, without exposing all the guts that would tempt programmers to tweak their code to fit the internal details that might change with any future update.

    An abstract class is in the middle between interfaces and concrete classes. It is supposed to help implementations share common or boring code. For example, AbstractCollection provides basic implementations for isEmpty based on size is 0, contains as iterate and compare, addAll as repeated add, and so on. This lets implementations focus on the crucial parts that differentiate between them: how to actually store and retrieve data.

    APIs versus SPIs

    Interfaces are low-cohesion gateways between different parts of code. They allow libraries to exist and evolve without breaking every library user when something changes internally. It's called Application Programming Interface, not Application Programming Classes. On a smaller scale, they also allow multiple developers to collaborate successfully on large scale projects, by separating different modules through well documented interfaces.

    Abstract classes are high-cohesion helpers to be used when implementing an interface, assuming some level of implementation details. Alternatively, abstract classes are used for defining SPIs, Service Provider Interfaces.

    The difference between an API and an SPI is subtle, but important: for an API, the focus is on who uses it, and for an SPI the focus is on who implements it.

    Adding methods to an API is easy, all existing users of the API will still compile. Adding methods to an SPI is hard, since every service provider (concrete implementation) will have to implement the new methods. If interfaces are used to define an SPI, a provider will have to release a new version whenever the SPI contract changes. If abstract classes are used instead, new methods could either be defined in terms of existing abstract methods, or as empty throw not implemented exception stubs, which will at least allow an older version of a service implementation to still compile and run.

    A note on Java 8 and default methods

    Although Java 8 introduced default methods for interfaces, which makes the line between interfaces and abstract classes even blurrier, this wasn't so that implementations can reuse code, but to make it easier to change interfaces that serve both as an API and as an SPI (or are wrongly used for defining SPIs instead of abstract classes).

    Which one to use?

    1. Is the thing supposed to be publicly used by other parts of the code, or by other external code? Add an interface to it to hide the implementation details from the public abstract contract, which is the general behavior of the thing.
    2. Is the thing something that's supposed to have multiple implementations with a lot of code in common? Make both an interface and an abstract, incomplete implementation.
    3. Is there ever going to be only one implementation, and nobody else will use it? Just make it a concrete class.
      1. "ever" is long time, you could play it safe and still add an interface on top of it.

    A corollary: the other way around is often wrongly done: when using a thing, always try to use the most generic class/interface that you actually need. In other words, don't declare your variables as ArrayList theList = new ArrayList(), unless you actually have a very strong dependency on it being an array list, and no other type of list would cut it for you. Use List theList = new ArrayList instead, or even Collection theCollection = new ArrayList if the fact that it's a list, and not any other type of collection doesn't actually matter.

    0 讨论(0)
  • 2020-11-21 12:06

    The key technical differences between an abstract class and an interface are:

    • Abstract classes can have constants, members, method stubs (methods without a body) and defined methods, whereas interfaces can only have constants and methods stubs.

    • Methods and members of an abstract class can be defined with any visibility, whereas all methods of an interface must be defined as public (they are defined public by default).

    • When inheriting an abstract class, a concrete child class must define the abstract methods, whereas an abstract class can extend another abstract class and abstract methods from the parent class don't have to be defined.

    • Similarly, an interface extending another interface is not responsible for implementing methods from the parent interface. This is because interfaces cannot define any implementation.

    • A child class can only extend a single class (abstract or concrete), whereas an interface can extend or a class can implement multiple other interfaces.

    • A child class can define abstract methods with the same or less restrictive visibility, whereas a class implementing an interface must define the methods with the exact same visibility (public).

    0 讨论(0)
  • 2020-11-21 12:10

    If you have some common methods that can be used by multiple classes go for abstract classes. Else if you want the classes to follow some definite blueprint go for interfaces.

    Following examples demonstrate this.

    Abstract class in Java:

    abstract class animals
    {
        // They all love to eat. So let's implement them for everybody
        void eat()
        {
            System.out.println("Eating...");
        }
        // The make different sounds. They will provide their own implementation.
        abstract void sound();
    }
    
    class dog extends animals
    {
        void sound()
        {
            System.out.println("Woof Woof");
        }
    }
    
    class cat extends animals
    {
        void sound()
        {
            System.out.println("Meoww");
        }
    }
    

    Following is an implementation of interface in Java:

    interface Shape
    {
        void display();
        double area();
    }
    
    class Rectangle implements Shape 
    {
        int length, width;
        Rectangle(int length, int width)
        {
            this.length = length;
            this.width = width;
        }
        @Override
        public void display() 
        {
            System.out.println("****\n* *\n* *\n****"); 
        }
        @Override
        public double area() 
        {
            return (double)(length*width);
        }
    } 
    
    class Circle implements Shape 
    {
        double pi = 3.14;
        int radius;
        Circle(int radius)
        {
            this.radius = radius;
        }
        @Override
        public void display() 
        {
            System.out.println("O"); // :P
        }
        @Override
        public double area() 
        { 
            return (double)((pi*radius*radius)/2);
        }
    }
    

    Some Important Key points in a nutshell:

    1. The variables declared in Java interface are by default final. Abstract classes can have non-final variables.

    2. The variables declared in Java interface are by default static. Abstract classes can have non-static variables.

    3. Members of a Java interface are public by default. A Java abstract class can have the usual flavors of class members like private, protected, etc..

    0 讨论(0)
  • 2020-11-21 12:11

    When you want to provide polymorphic behaviour in an inheritance hierarchy, use abstract classes.

    When you want polymorphic behaviour for classes which are completely unrelated, use an interface.

    0 讨论(0)
  • 2020-11-21 12:12

    The main point is that:

    • Abstract is object oriented. It offers the basic data an 'object' should have and/or functions it should be able to do. It is concerned with the object's basic characteristics: what it has and what it can do. Hence objects which inherit from the same abstract class share the basic characteristics (generalization).
    • Interface is functionality oriented. It defines functionalities an object should have. Regardless what object it is, as long as it can do these functionalities, which are defined in the interface, it's fine. It ignores everything else. An object/class can contain several (groups of) functionalities; hence it is possible for a class to implement multiple interfaces.
    0 讨论(0)
  • 2020-11-21 12:12

    It's pretty simple actually.

    You can think of an interface as a class which is only allowed to have abstract methods and nothing else.

    So an interface can only "declare" and not define the behavior you want the class to have.

    An abstract class allows you to do both declare (using abstract methods) as well as define (using full method implementations) the behavior you want the class to have.

    And a regular class only allows you to define, not declare, the behavior/actions you want the class to have.

    One last thing,

    In Java, you can implement multiple interfaces, but you can only extend one (Abstract Class or Class)...

    This means inheritance of defined behavior is restricted to only allow one per class... ie if you wanted a class that encapsulated behavior from Classes A,B&C you would need to do the following: Class A extends B, Class C extends A .. its a bit of a round about way to have multiple inheritance...

    Interfaces on the other hand, you could simply do: interface C implements A, B

    So in effect Java supports multiple inheritance only in "declared behavior" ie interfaces, and only single inheritance with defined behavior.. unless you do the round about way I described...

    Hopefully that makes sense.

    0 讨论(0)
提交回复
热议问题