Interfaces and Abstract classes confusion in Java

2019-02-01 21:39发布

I'm having trouble understanding when to use an interface as opposed to an abstract class and vice versa. Also, I am confused when to extend an interface with another interface. Sorry about the long post, but this is very confusing.

Creating shapes seems like a popular starting point. Let's say we want a way to model 2D shapes. We know that each shape will have an area. What would be the difference between the following two implementations:

with interfaces:

public interface Shape {
    public double area();
}

public class Square implements Shape{
    private int length = 5;
    public Square(){...}

    public double area()
         return length * length;
    }
}

with abstract class:

abstract class Shape {
    abstract public double area();
}

public class Square extends Shape {
    private length = 5;
    public Square(){...}

    public double area(){
        return length * length;
    }

I understand that abstract classes allows you to define instance variables and allows you to give method implementations whereas an interface cannot do these things. But in this case, it seems like these two implementations are identical. So using any one is fine?

But now say we want to describe different types of triangles. We can have an isosceles, acute, and right angle triangles. To me, it makes sense to use class inheritance in this case. Using the 'IS-A' definition: a Right Triangle "IS-A" Triangle. A Triangle "IS-A" Shape. Also, an abstract class should define behaviors and attributes that are common within all subclasses, so this is perfect:

with abstract class

abstract Triangle extends Shape {
    private final int sides = 3;
}
class RightTriangle extends Triangle {
    private int base = 4;
    private int height = 5;

    public RightTriangle(){...}

    public double area() {
        return .5 * base * height
    }
}

We can do this with interfaces as well, with Triangle and Shape being interfaces. However, unlike class inheritance (using 'IS-A' relationship to define what should be a subclass), I'm not sure how to use an interface. I see two ways:

First way:

  public interface Triangle {
      public final int sides = 3;
  }
  public class RightTriangle implements Triangle, Shape {
      private int base = 4;
      private int height = 5;

      public RightTriangle(){}
      public double area(){
          return .5 * height * base;
      }
  }

Second way:

public interface Triangle extends Shape {
     public final int sides = 3;
} 
public class RightTriangle implements Triangle {
    ....

    public double area(){
         return .5 * height * base;
    }
}

It seems to me like both of these ways work. But when would you use one way over the other? And are there any advantages to using interfaces over abstract classes to represent different triangles? Even though we complicated the description of a shape, using interface vs abstract class still seem equivalent.

A critical component to interfaces is that it can define behaviors that can be shared across unrelated classes. So an interface Flyable would be present in classes Airplane as well as in Bird. So in this case, it is clear that an interface approach is preferred.

Also, to build off of the confusing interface extending another interface: When should the 'IS-A' relationship be ignored when deciding on what should be an interface? Take this example: LINK.

Why should 'VeryBadVampire' be a class and 'Vampire' be an interface? A 'VeryBadVampire' IS-A 'Vampire', so my understanding is that a 'Vampire' should be a superclass (maybe abstract class). A 'Vampire' class can implement 'Lethal' to keep its lethal behavior. Furthermore, a 'Vampire' IS-A 'Monster', so 'Monster' should be a class as well. A 'Vampire' class can also implement an interface called 'Dangerous' to keep its dangerous behavior. If we wish to create a new monster called 'BigRat' which is dangerous but not lethal, then we can create a 'BigRat' class which extends 'Monster' and implements 'Dangerous'.

Wouldn't the above achieve the same output as using 'Vampire' as an interface (described in the link)? The only difference I see is that using class inheritance and preserving the 'IS-A' relationship clears up a lot of confusion. Yet this is not followed. What is the advantage of doing this?

Even if you wanted a monster to share vampiric behavior, one can always redefine how the objects are represented. If we wanted a new type of vampire monster called 'VeryMildVampire' and we wanted to create a vampire-like monster called 'Chupacabra', we can do this:

'Vampire' class extends 'Monster' implements 'Dangerous', 'Lethal', 'BloodSuckable'
'VeryMildVampire' class extends 'Vampire' class
'Chupacabra' class extends 'Monster' implements 'BloodSuckable'

But we can also do this:

'VeryMildVampire' extends 'Monster' implements Dangerous, Lethal, Vampiric
'Chupacabra' extends 'Monster' implements Dangerous, Vampiric

The second way here creates a 'Vampiric' interface so that we can more easily define a related monster rather than create a bunch of interfaces which define vampiric behaviors (like in the first example). But this breaks the IS-A relationship. So I'm confused...

7条回答
甜甜的少女心
2楼-- · 2019-02-01 22:07

This is a question that comes up very often, yet there is no single "right" answer that will please everyone.

Classes represent is-a relationships and interfaces represent can-do behaviour. I usually go by a few empirical rules:

  • Stick with a class (abstract/concrete) unless you are certain that you need an interface.
  • If you do use interfaces, slice them into very specific functionality. If an interface contains more than a few methods, you're doing it wrong.

Further, most examples of shapes and persons (or vampires for that matter!) are usually poor examples of real-world models. The "right" answer depends on what your application requires. For instance, you mentioned:

class Vampire extends Monster implements Dangerous, Lethal, BloodSuckable

Does your application really need all these interfaces? How many different types of Monsters are there? Do you actually have classes other than Vampire that implement BloodSuckable?

Try not to generalize too much and extract interfaces when you have no need for them. This goes back to the rule of thumb: stick with a simple class unless your use case demands an interface.

查看更多
家丑人穷心不美
3楼-- · 2019-02-01 22:10

This is a good question. There are many good and bad answers for this question. Typical question is, what is the difference between an abstract class an interface? Lets see where you use abstract classes and where you use interface.

Where to use abstract classes: In terms of OOP, If there is an inheritance hierarchy then you should use an abstract class to model your design.
enter image description here

Where to use interfaces: When you have to connect different contracts(non related classes) using one common contract then you should use an interface. Lets take Collection framework as an example. enter image description here

Queue,List,Set have different structures from their implementation.But still they share some common behaviors like add(),remove(). So we can create an interface called Collection and the we have declared common behaviors in the interface. As you see, ArrayList implements all the behaviors from both List and RandomAccess interfaces.Doing so we can easily add new contracts without changing the existing logic. This is called as "coding to an interface".

查看更多
smile是对你的礼貌
4楼-- · 2019-02-01 22:13

This is question that will come to when designing class hierarchies that are bit complicated that normal. But generally there are few things you need to know when using abstract classes and interfaces

Abstract Class

  • Allows you to leverage the power of using constructors and constructor overriding
  • Restrict the class having multiple inheritance(This is particularly useful if you are designing a complicated API)
  • Instance variables and method implementations
  • Leverage the power of method super calling(Use super to call the parent abstract class's implementation)

Interface

  • Enables multiple inheritance - you can implement n number of interfaces
  • Allows to represent only conceptual methods (No method bodies)

Generally use Interfaces for '-able' clause(as in functionality). Eg:-

  1. Runnable
  2. Observable

Use abstract classes for something like is-a(evolution format). Eg:-

  1. Number
  2. Graphics

But hard and fast rules are not easy to create. Hope this helps

查看更多
【Aperson】
5楼-- · 2019-02-01 22:14

Remember the basic concept when using abstract classes or interfaces.

Abstract classes are used when class to extended is more closely coupled to the class implementing it, i.e when both have a parent-child relation.

In example:

       abstract class Dog {}

       class Breed1 extends Dog {}

       class Breed2 extends Dog {}

Breed1 and Breed2 are both types of a dog and has some common behavior as a dog.

Whereas, an interface is used when implementing class has a feature it can take from the class to implemented.

     interface Animal {
         void eat();
         void noise();
     }

     class Tiger implements Animal {}

     class Dog  implements Animal {}

Tiger and Dog are two different category but both eat and make noises ,which are different. So they can use eat and noise from Animal.

查看更多
Rolldiameter
6楼-- · 2019-02-01 22:17

Use an abstract class when you want to make one or more methods not abstract.

If you want to keep all abstract, use an interface.

查看更多
可以哭但决不认输i
7楼-- · 2019-02-01 22:19

You have quite a few questions here. But I think basically you are asking about interface vs. abstract class.

With interfaces, you can have classes that implement multiple interfaces. However, interface is not durable if you want to use it as the API. Once the interface is published, it's hard to modify the interface because it will break other people's codes.

With abstract class, you can only extends one class. However, abstract class is durable for API because you can still modify in later versions without breaking other people's code. Also with abstract class, you can have predefined implementation. For example, in your Triangle example, for abstract class, you may have a method countEdges() which returns 3 by default.

查看更多
登录 后发表回答